| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.infobar; | 5 package org.chromium.chrome.browser.infobar; |
| 6 | 6 |
| 7 import android.app.Activity; | 7 import android.app.Activity; |
| 8 import android.content.ContentResolver; | 8 import android.content.ContentResolver; |
| 9 import android.content.Context; | 9 import android.content.Context; |
| 10 import android.content.Intent; | 10 import android.content.Intent; |
| 11 import android.content.pm.PackageManager; | 11 import android.content.pm.PackageManager; |
| 12 import android.os.Looper; | 12 import android.os.Looper; |
| 13 | 13 |
| 14 import org.chromium.base.ApplicationState; |
| 14 import org.chromium.base.ApplicationStatus; | 15 import org.chromium.base.ApplicationStatus; |
| 15 import org.chromium.base.ContextUtils; | 16 import org.chromium.base.ContextUtils; |
| 17 import org.chromium.base.ThreadUtils; |
| 16 import org.chromium.base.VisibleForTesting; | 18 import org.chromium.base.VisibleForTesting; |
| 17 import org.chromium.base.annotations.CalledByNative; | 19 import org.chromium.base.annotations.CalledByNative; |
| 18 import org.chromium.base.annotations.JNINamespace; | 20 import org.chromium.base.annotations.JNINamespace; |
| 21 import org.chromium.chrome.R; |
| 19 import org.chromium.chrome.browser.banners.AppData; | 22 import org.chromium.chrome.browser.banners.AppData; |
| 20 import org.chromium.chrome.browser.banners.InstallerDelegate; | 23 import org.chromium.chrome.browser.banners.InstallerDelegate; |
| 21 import org.chromium.chrome.browser.tab.Tab; | 24 import org.chromium.chrome.browser.tab.Tab; |
| 22 import org.chromium.ui.base.WindowAndroid; | 25 import org.chromium.ui.base.WindowAndroid; |
| 26 import org.chromium.ui.widget.Toast; |
| 23 | 27 |
| 24 /** | 28 /** |
| 25 * Handles the promotion and installation of an app specified by the current web
page. This Java | 29 * Handles the promotion and installation of an app specified by the current web
page. This Java |
| 26 * object is created by and owned by the native AppBannerInfoBarDelegateAndroid. | 30 * object is created by and owned by the native AppBannerInfoBarDelegateAndroid. |
| 27 */ | 31 */ |
| 28 @JNINamespace("banners") | 32 @JNINamespace("banners") |
| 29 public class AppBannerInfoBarDelegateAndroid { | 33 public class AppBannerInfoBarDelegateAndroid { |
| 30 /** PackageManager to use in place of the real one. */ | 34 /** PackageManager to use in place of the real one. */ |
| 31 private static PackageManager sPackageManagerForTests; | 35 private static PackageManager sPackageManagerForTests; |
| 32 | 36 |
| 33 /** Weak pointer to the native AppBannerInfoBarDelegateAndroid. */ | 37 /** Weak pointer to the native AppBannerInfoBarDelegateAndroid. */ |
| 34 private long mNativePointer; | 38 private long mNativePointer; |
| 35 | 39 |
| 36 /** Monitors an installation in progress. */ | 40 /** Monitors an installation in progress. */ |
| 37 private InstallerDelegate mInstallTask; | 41 private InstallerDelegate mInstallTask; |
| 38 | 42 |
| 39 /** Monitors for application state changes. */ | 43 /** Monitors for application state changes. */ |
| 40 private final ApplicationStatus.ApplicationStateListener mListener; | 44 private final ApplicationStatus.ApplicationStateListener mListener; |
| 41 | 45 |
| 46 /** |
| 47 * Indicates whether a request to install a WebPK has started. This flag is
set before |
| 48 * the package name of the WebAPK is available. |
| 49 */ |
| 50 private boolean mIsWebApkInstalling = false; |
| 51 |
| 52 private String mWebApkPackage; |
| 53 |
| 54 /** |
| 55 * Indicates whether to monitor the installation of the downloaded WebAPK. C
urrently WebAPKs |
| 56 * aren't installed by Play, so user could cancel the installation when Andr
oid installation |
| 57 * dialog shows. The only way to know whether user cancels the installation
is to check whether |
| 58 * the WebAPK is installed when Chrome is resumed. This flag is set to true
once the |
| 59 * installation Intent is sent to Android System. |
| 60 */ |
| 61 private boolean mStartMonitoringWebApkInstallation = false; |
| 62 |
| 42 /** Overrides the PackageManager for testing. */ | 63 /** Overrides the PackageManager for testing. */ |
| 43 @VisibleForTesting | 64 @VisibleForTesting |
| 44 public static void setPackageManagerForTesting(PackageManager manager) { | 65 public static void setPackageManagerForTesting(PackageManager manager) { |
| 45 sPackageManagerForTests = manager; | 66 sPackageManagerForTests = manager; |
| 46 } | 67 } |
| 47 | 68 |
| 48 private AppBannerInfoBarDelegateAndroid(long nativePtr) { | 69 private AppBannerInfoBarDelegateAndroid(long nativePtr) { |
| 49 mNativePointer = nativePtr; | 70 mNativePointer = nativePtr; |
| 50 mListener = createApplicationStateListener(); | 71 mListener = createApplicationStateListener(); |
| 51 ApplicationStatus.registerApplicationStateListener(mListener); | 72 ApplicationStatus.registerApplicationStateListener(mListener); |
| 52 } | 73 } |
| 53 | 74 |
| 54 private ApplicationStatus.ApplicationStateListener createApplicationStateLis
tener() { | 75 private ApplicationStatus.ApplicationStateListener createApplicationStateLis
tener() { |
| 55 return new ApplicationStatus.ApplicationStateListener() { | 76 return new ApplicationStatus.ApplicationStateListener() { |
| 56 @Override | 77 @Override |
| 57 public void onApplicationStateChange(int newState) { | 78 public void onApplicationStateChange(int newState) { |
| 58 if (!ApplicationStatus.hasVisibleActivities()) return; | 79 if (!ApplicationStatus.hasVisibleActivities()) return; |
| 80 if (mStartMonitoringWebApkInstallation |
| 81 && newState == ApplicationState.HAS_RUNNING_ACTIVITIES)
{ |
| 82 if (nativeCloseAppBannerInfobarIfNeeded(mNativePointer)) { |
| 83 mStartMonitoringWebApkInstallation = false; |
| 84 return; |
| 85 } |
| 86 } |
| 59 nativeUpdateInstallState(mNativePointer); | 87 nativeUpdateInstallState(mNativePointer); |
| 60 } | 88 } |
| 61 }; | 89 }; |
| 62 } | 90 } |
| 63 | 91 |
| 64 @CalledByNative | 92 @CalledByNative |
| 65 private void destroy() { | 93 private void destroy() { |
| 66 if (mInstallTask != null) { | 94 if (mInstallTask != null) { |
| 67 mInstallTask.cancel(); | 95 mInstallTask.cancel(); |
| 68 mInstallTask = null; | 96 mInstallTask = null; |
| 69 } | 97 } |
| 70 ApplicationStatus.unregisterApplicationStateListener(mListener); | 98 ApplicationStatus.unregisterApplicationStateListener(mListener); |
| 71 mNativePointer = 0; | 99 mNativePointer = 0; |
| 72 } | 100 } |
| 73 | 101 |
| 74 @CalledByNative | 102 @CalledByNative |
| 75 private boolean installOrOpenNativeApp(Tab tab, AppData appData, String refe
rrer) { | 103 private boolean installOrOpenNativeApp(Tab tab, AppData appData, String refe
rrer) { |
| 76 Context context = ContextUtils.getApplicationContext(); | 104 Context context = ContextUtils.getApplicationContext(); |
| 77 String packageName = appData.packageName(); | 105 String packageName = appData.packageName(); |
| 78 PackageManager packageManager = getPackageManager(context); | 106 PackageManager packageManager = getPackageManager(context); |
| 79 | 107 |
| 80 if (InstallerDelegate.isInstalled(packageManager, packageName)) { | 108 if (InstallerDelegate.isInstalled(packageManager, packageName)) { |
| 81 // Open the app. | 109 // Open the app. |
| 82 Intent launchIntent = packageManager.getLaunchIntentForPackage(packa
geName); | 110 return openApp(context, packageName); |
| 83 if (launchIntent == null) return true; | |
| 84 context.startActivity(launchIntent); | |
| 85 return true; | |
| 86 } else { | 111 } else { |
| 87 // Try installing the app. If the installation was kicked off, retu
rn false to prevent | 112 // Try installing the app. If the installation was kicked off, retu
rn false to prevent |
| 88 // the infobar from disappearing. | 113 // the infobar from disappearing. |
| 89 // The supplied referrer is the URL of the page requesting the nativ
e app banner. It | 114 // The supplied referrer is the URL of the page requesting the nativ
e app banner. It |
| 90 // may be empty depending on that page's referrer policy. If it is n
on-empty, attach it | 115 // may be empty depending on that page's referrer policy. If it is n
on-empty, attach it |
| 91 // to the installation intent as Intent.EXTRA_REFERRER. | 116 // to the installation intent as Intent.EXTRA_REFERRER. |
| 92 Intent installIntent = appData.installIntent(); | 117 Intent installIntent = appData.installIntent(); |
| 93 if (referrer.length() > 0) installIntent.putExtra(Intent.EXTRA_REFER
RER, referrer); | 118 if (referrer.length() > 0) installIntent.putExtra(Intent.EXTRA_REFER
RER, referrer); |
| 94 return !tab.getWindowAndroid().showIntent( | 119 return !tab.getWindowAndroid().showIntent( |
| 95 installIntent, createIntentCallback(appData), null); | 120 installIntent, createIntentCallback(appData), null); |
| 96 } | 121 } |
| 97 } | 122 } |
| 98 | 123 |
| 124 private boolean openApp(Context context, String packageName) { |
| 125 Intent launchIntent = getPackageManager(context).getLaunchIntentForPacka
ge(packageName); |
| 126 if (launchIntent != null) { |
| 127 context.startActivity(launchIntent); |
| 128 } |
| 129 return true; |
| 130 } |
| 131 |
| 99 private WindowAndroid.IntentCallback createIntentCallback(final AppData appD
ata) { | 132 private WindowAndroid.IntentCallback createIntentCallback(final AppData appD
ata) { |
| 100 return new WindowAndroid.IntentCallback() { | 133 return new WindowAndroid.IntentCallback() { |
| 101 @Override | 134 @Override |
| 102 public void onIntentCompleted(WindowAndroid window, int resultCode, | 135 public void onIntentCompleted(WindowAndroid window, int resultCode, |
| 103 ContentResolver contentResolver, Intent data) { | 136 ContentResolver contentResolver, Intent data) { |
| 104 boolean isInstalling = resultCode == Activity.RESULT_OK; | 137 boolean isInstalling = resultCode == Activity.RESULT_OK; |
| 105 if (isInstalling) { | 138 if (isInstalling) { |
| 106 // Start monitoring the install. | 139 // Start monitoring the install. |
| 107 PackageManager pm = | 140 PackageManager pm = |
| 108 getPackageManager(ContextUtils.getApplicationContext
()); | 141 getPackageManager(ContextUtils.getApplicationContext
()); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 122 @Override | 155 @Override |
| 123 public void onInstallFinished(InstallerDelegate task, boolean succes
s) { | 156 public void onInstallFinished(InstallerDelegate task, boolean succes
s) { |
| 124 if (mInstallTask != task) return; | 157 if (mInstallTask != task) return; |
| 125 mInstallTask = null; | 158 mInstallTask = null; |
| 126 nativeOnInstallFinished(mNativePointer, success); | 159 nativeOnInstallFinished(mNativePointer, success); |
| 127 } | 160 } |
| 128 }; | 161 }; |
| 129 } | 162 } |
| 130 | 163 |
| 131 @CalledByNative | 164 @CalledByNative |
| 165 private boolean installOrOpenWebApk(String packageName) { |
| 166 mWebApkPackage = packageName; |
| 167 Context context = ContextUtils.getApplicationContext(); |
| 168 PackageManager packageManager = getPackageManager(context); |
| 169 |
| 170 if (InstallerDelegate.isInstalled(packageManager, packageName)) { |
| 171 // Open the WebApk. |
| 172 mWebApkPackage = null; |
| 173 mStartMonitoringWebApkInstallation = false; |
| 174 return openApp(context, packageName); |
| 175 } else { |
| 176 // Try installing the WebAPK. If the installation was kicked off, r
eturn false to |
| 177 // prevent the infobar from disappearing. |
| 178 // Start monitoring the install. |
| 179 mInstallTask = new InstallerDelegate(Looper.getMainLooper(), package
Manager, |
| 180 createInstallerDelegateObserver(), packageName); |
| 181 mInstallTask.start(); |
| 182 mStartMonitoringWebApkInstallation = true; |
| 183 return false; |
| 184 } |
| 185 } |
| 186 |
| 187 @CalledByNative |
| 132 private void showAppDetails(Tab tab, AppData appData) { | 188 private void showAppDetails(Tab tab, AppData appData) { |
| 133 tab.getWindowAndroid().showIntent(appData.detailsIntent(), null, null); | 189 tab.getWindowAndroid().showIntent(appData.detailsIntent(), null, null); |
| 134 } | 190 } |
| 135 | 191 |
| 136 @CalledByNative | 192 @CalledByNative |
| 137 private int determineInstallState(AppData data) { | 193 private int determineInstallState(AppData data) { |
| 194 if (mIsWebApkInstalling) return AppBannerInfoBarAndroid.INSTALL_STATE_IN
STALLING_WEBAPK; |
| 138 if (mInstallTask != null) return AppBannerInfoBarAndroid.INSTALL_STATE_I
NSTALLING; | 195 if (mInstallTask != null) return AppBannerInfoBarAndroid.INSTALL_STATE_I
NSTALLING; |
| 139 | 196 |
| 140 PackageManager pm = getPackageManager(ContextUtils.getApplicationContext
()); | 197 PackageManager pm = getPackageManager(ContextUtils.getApplicationContext
()); |
| 141 boolean isInstalled = InstallerDelegate.isInstalled(pm, data.packageName
()); | 198 String packageName = data != null ? data.packageName() : mWebApkPackage; |
| 142 return isInstalled ? AppBannerInfoBarAndroid.INSTALL_STATE_INSTALLED | 199 |
| 143 : AppBannerInfoBarAndroid.INSTALL_STATE_NOT_INSTALLED; | 200 boolean isInstalled = InstallerDelegate.isInstalled(pm, packageName); |
| 201 if (!isInstalled) return AppBannerInfoBarAndroid.INSTALL_STATE_NOT_INSTA
LLED; |
| 202 return data != null ? AppBannerInfoBarAndroid.INSTALL_STATE_INSTALLED |
| 203 : AppBannerInfoBarAndroid.INSTALL_STATE_INSTALLED_WEBAPK; |
| 204 } |
| 205 |
| 206 @CalledByNative |
| 207 /** Set the flag of whether a installation process is started for the WebAPK
. */ |
| 208 private void setWebApkInstallingState(boolean isInstalling) { |
| 209 mIsWebApkInstalling = isInstalling; |
| 210 } |
| 211 |
| 212 @CalledByNative |
| 213 private static void showWebApkInstallFailureToast() { |
| 214 ThreadUtils.runOnUiThread(new Runnable() { |
| 215 @Override |
| 216 public void run() { |
| 217 Context applicationContext = ContextUtils.getApplicationContext(
); |
| 218 Toast toast = Toast.makeText(applicationContext, R.string.fail_t
o_install_webapk, |
| 219 Toast.LENGTH_SHORT); |
| 220 toast.show(); |
| 221 } |
| 222 }); |
| 144 } | 223 } |
| 145 | 224 |
| 146 private PackageManager getPackageManager(Context context) { | 225 private PackageManager getPackageManager(Context context) { |
| 147 if (sPackageManagerForTests != null) return sPackageManagerForTests; | 226 if (sPackageManagerForTests != null) return sPackageManagerForTests; |
| 148 return context.getPackageManager(); | 227 return context.getPackageManager(); |
| 149 } | 228 } |
| 150 | 229 |
| 151 @CalledByNative | 230 @CalledByNative |
| 152 private static AppBannerInfoBarDelegateAndroid create(long nativePtr) { | 231 private static AppBannerInfoBarDelegateAndroid create(long nativePtr) { |
| 153 return new AppBannerInfoBarDelegateAndroid(nativePtr); | 232 return new AppBannerInfoBarDelegateAndroid(nativePtr); |
| 154 } | 233 } |
| 155 | 234 |
| 235 @CalledByNative |
| 236 private boolean isWebApkInstalled(String packageName) { |
| 237 PackageManager packageManager = getPackageManager(ContextUtils.getApplic
ationContext()); |
| 238 boolean result = InstallerDelegate.isInstalled(packageManager, packageNa
me); |
| 239 return result; |
| 240 } |
| 241 |
| 156 private native void nativeOnInstallIntentReturned( | 242 private native void nativeOnInstallIntentReturned( |
| 157 long nativeAppBannerInfoBarDelegateAndroid, boolean isInstalling); | 243 long nativeAppBannerInfoBarDelegateAndroid, boolean isInstalling); |
| 158 private native void nativeOnInstallFinished( | 244 private native void nativeOnInstallFinished( |
| 159 long nativeAppBannerInfoBarDelegateAndroid, boolean success); | 245 long nativeAppBannerInfoBarDelegateAndroid, boolean success); |
| 160 private native void nativeUpdateInstallState(long nativeAppBannerInfoBarDele
gateAndroid); | 246 private native void nativeUpdateInstallState(long nativeAppBannerInfoBarDele
gateAndroid); |
| 247 private native boolean nativeCloseAppBannerInfobarIfNeeded( |
| 248 long nativeAppBannerInfoBarDelegateAndroid); |
| 161 } | 249 } |
| OLD | NEW |