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 |