Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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.webapk.shell_apk; | 5 package org.chromium.webapk.shell_apk; |
| 6 | 6 |
| 7 import android.content.Context; | 7 import android.content.Context; |
| 8 import android.content.Intent; | |
| 9 import android.content.SharedPreferences; | |
| 8 import android.content.pm.ApplicationInfo; | 10 import android.content.pm.ApplicationInfo; |
| 9 import android.content.pm.PackageManager; | 11 import android.content.pm.PackageManager; |
| 10 import android.content.pm.PackageManager.NameNotFoundException; | 12 import android.content.pm.PackageManager.NameNotFoundException; |
| 13 import android.content.pm.ResolveInfo; | |
| 14 import android.graphics.drawable.Drawable; | |
| 15 import android.net.Uri; | |
| 11 import android.os.Bundle; | 16 import android.os.Bundle; |
| 17 import android.text.TextUtils; | |
| 12 | 18 |
| 19 import org.chromium.webapk.lib.common.WebApkConstants; | |
| 13 import org.chromium.webapk.lib.common.WebApkMetaDataKeys; | 20 import org.chromium.webapk.lib.common.WebApkMetaDataKeys; |
| 14 | 21 |
| 22 import java.util.ArrayList; | |
| 23 import java.util.Arrays; | |
| 24 import java.util.HashSet; | |
| 25 import java.util.List; | |
| 26 import java.util.Set; | |
| 27 | |
| 15 /** | 28 /** |
| 16 * Contains utility methods for interacting with WebAPKs. | 29 * Contains utility methods for interacting with WebAPKs. |
| 17 */ | 30 */ |
| 18 public class WebApkUtils { | 31 public class WebApkUtils { |
| 32 public static final String SHARED_PREF_RUNTIME_HOST = "runtime_host"; | |
| 33 | |
| 34 // The package names of the channels of Chrome that support WebAPKs. The mos t preferred one | |
| 35 // comes first. | |
|
pkotwicz
2017/05/26 22:38:39
Nit: use block commenting style
Xi Han
2017/05/29 21:18:56
Done.
| |
| 36 private static List<String> sBrowsersSupportingWebApk = new ArrayList<String >( | |
| 37 Arrays.asList("com.google.android.apps.chrome", "com.android.chrome" , "com.chrome.beta", | |
| 38 "com.chrome.dev", "com.chrome.canary")); | |
| 19 | 39 |
| 20 /** | 40 /** |
| 21 * Caches the value read from Application Metadata which specifies the host browser's package | 41 * Stores information about a potential host browser for the WebAPK. |
| 22 * name. | 42 */ |
| 43 public static class BrowserItem { | |
| 44 private String mPackageName; | |
| 45 private CharSequence mApplicationLabel; | |
| 46 private Drawable mIcon; | |
| 47 private boolean mIsEnabled; | |
|
pkotwicz
2017/05/26 22:38:39
WebApkUtils should not know about the UI in which
Xi Han
2017/05/29 21:18:56
Done.
| |
| 48 | |
| 49 public BrowserItem(String packageName, CharSequence applicationLabel, Dr awable icon, | |
| 50 boolean isEnabled) { | |
| 51 mPackageName = packageName; | |
| 52 mApplicationLabel = applicationLabel; | |
| 53 mIcon = icon; | |
| 54 mIsEnabled = isEnabled; | |
| 55 } | |
| 56 | |
| 57 // Returns the package name of a browser. | |
|
pkotwicz
2017/05/26 22:38:39
Nit: Use /** */ for comments in this class. https:
Xi Han
2017/05/29 21:18:56
Thanks!
| |
| 58 public String getPackageName() { | |
| 59 return mPackageName; | |
| 60 } | |
| 61 | |
| 62 // Returns the application name of a browser. | |
| 63 public CharSequence getApplicationName() { | |
| 64 return mApplicationLabel; | |
| 65 } | |
| 66 | |
| 67 // Returns a drawable of the browser icon. | |
| 68 public Drawable getApplicationIcon() { | |
| 69 return mIcon; | |
| 70 } | |
| 71 | |
| 72 // Returns whether this BrowserItem is clickable. An BrowserItem is clic kable only if the | |
| 73 // browser it represents supporting WebAPKs. | |
| 74 public boolean isEnabled() { | |
| 75 return mIsEnabled; | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * Caches the package name of the host browser. {@link sHostPackage} might r efer to a browser | |
| 81 * which has been uninstalled. A notification can keep the WebAPK process al ive after the host | |
| 82 * browser has been uninstalled. | |
| 23 */ | 83 */ |
| 24 private static String sHostPackage; | 84 private static String sHostPackage; |
| 25 | 85 |
| 86 // For testing only. | |
| 87 public static void resetCachedHostPackageForTesting() { | |
| 88 sHostPackage = null; | |
| 89 } | |
| 90 | |
| 91 public static void setBrowsersSupportingWebApkForTesting(List<String> browse rs) { | |
| 92 sBrowsersSupportingWebApk = browsers; | |
| 93 } | |
| 94 | |
| 26 /** | 95 /** |
| 27 * Returns a Context for the host browser that was specified when building t he WebAPK. | 96 * Returns a Context for the host browser that was specified when building t he WebAPK. |
| 28 * @param context A context. | 97 * @param context A context. |
| 29 * @return The remote context. Returns null on an error. | 98 * @return The remote context. Returns null on an error. |
| 30 */ | 99 */ |
| 31 public static Context getHostBrowserContext(Context context) { | 100 public static Context getHostBrowserContext(Context context) { |
| 32 try { | 101 try { |
| 33 String hostPackage = getHostBrowserPackageName(context); | 102 String hostPackage = getHostBrowserPackageName(context); |
| 34 return context.getApplicationContext().createPackageContext( | 103 return context.getApplicationContext().createPackageContext( |
| 35 hostPackage, | 104 hostPackage, |
| 36 Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_IN CLUDE_CODE); | 105 Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_IN CLUDE_CODE); |
| 37 } catch (NameNotFoundException e) { | 106 } catch (NameNotFoundException e) { |
| 38 e.printStackTrace(); | 107 e.printStackTrace(); |
| 39 } | 108 } |
| 40 return null; | 109 return null; |
| 41 } | 110 } |
| 42 | 111 |
| 43 /** | 112 /** |
| 44 * Returns the package name for the host browser that was specified when bui lding the WebAPK. | 113 * Returns the package name of the host browser to launch the WebAPK. Also c aches the package |
| 114 * name in the SharedPreference if it is not null. | |
| 45 * @param context A context. | 115 * @param context A context. |
| 46 * @return The package name. Returns null on an error. | 116 * @return The package name. Returns null on an error. |
| 47 */ | 117 */ |
| 48 public static String getHostBrowserPackageName(Context context) { | 118 public static String getHostBrowserPackageName(Context context) { |
| 49 if (sHostPackage != null) return sHostPackage; | 119 if (sHostPackage == null) { |
| 50 String hostPackage = null; | 120 sHostPackage = getHostBrowserPackageNameInternal(context); |
| 51 try { | 121 if (sHostPackage != null) { |
| 52 ApplicationInfo ai = context.getPackageManager().getApplicationInfo( | 122 writeHostBrowserToSharedPref(context, sHostPackage); |
| 53 context.getPackageName(), PackageManager.GET_META_DATA); | 123 } |
|
pkotwicz
2017/05/26 22:38:39
The Shared Preferences should be cleared if:
1) Th
Xi Han
2017/05/29 21:18:56
I moved the call of deleteSharedPref() in getHostB
| |
| 54 Bundle bundle = ai.metaData; | |
| 55 hostPackage = bundle.getString(WebApkMetaDataKeys.RUNTIME_HOST); | |
| 56 } catch (NameNotFoundException e) { | |
| 57 e.printStackTrace(); | |
| 58 } | 124 } |
| 59 // Set {@link sHostPackage} to a non-null value so that the value is com puted only once. | 125 |
| 60 sHostPackage = hostPackage != null ? hostPackage : ""; | |
| 61 return sHostPackage; | 126 return sHostPackage; |
| 62 } | 127 } |
| 63 | 128 |
| 64 /** | 129 /** |
| 130 * Returns the package name of the host browser to launch the WebAPK, or nul l if we did not find | |
| 131 * one. | |
| 132 */ | |
| 133 private static String getHostBrowserPackageNameInternal(Context context) { | |
| 134 Set<String> installedBrowsers = getInstalledBrowsers(context.getPackageM anager()); | |
| 135 if (installedBrowsers.isEmpty()) { | |
| 136 return null; | |
| 137 } | |
| 138 | |
| 139 // Gets the package name of the host browser if it is stored in the Shar edPreference. | |
| 140 String cachedHostBrowser = getHostBrowserFromSharedPreference(context); | |
| 141 if (!TextUtils.isEmpty(cachedHostBrowser) | |
| 142 && installedBrowsers.contains(cachedHostBrowser)) { | |
| 143 return cachedHostBrowser; | |
| 144 } | |
| 145 | |
| 146 // Gets the package name of the host browser if it is specified in Andro idManifest.xml. | |
| 147 String hostBrowserFromManifest = getHostBrowserFromAndroidManifest( | |
| 148 context.getPackageManager(), context.getPackageName()); | |
| 149 if (!TextUtils.isEmpty(hostBrowserFromManifest)) { | |
| 150 if (installedBrowsers.contains(hostBrowserFromManifest)) { | |
| 151 return hostBrowserFromManifest; | |
| 152 } | |
| 153 return null; | |
| 154 } | |
| 155 | |
| 156 deleteSharedPref(context); | |
| 157 | |
| 158 // Gets the package name of the default browser on the Android device. | |
| 159 // TODO(hanxi): Investigate the best way to know which browser supports WebAPKs. | |
| 160 String defaultBrowser = getDefaultBrowserPackageName(context.getPackageM anager()); | |
| 161 if (!TextUtils.isEmpty(defaultBrowser) && installedBrowsers.contains(def aultBrowser) | |
| 162 && sBrowsersSupportingWebApk.contains(defaultBrowser)) { | |
| 163 return defaultBrowser; | |
| 164 } | |
| 165 | |
| 166 return null; | |
| 167 } | |
| 168 | |
| 169 /** | |
| 170 * Returns a list of browsers to choose host browser from. The list includes all the installed | |
| 171 * browsers, and if none of the installed browser supports WebAPKs, Chrome w ill be added to the | |
| 172 * list as well. | |
| 173 */ | |
| 174 public static List<BrowserItem> getBrowserInfosForHostBrowserSelection( | |
| 175 PackageManager packageManager) { | |
| 176 Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http:// ")); | |
| 177 List<ResolveInfo> resolvedActivityList = packageManager.queryIntentActiv ities( | |
| 178 browserIntent, PackageManager.MATCH_DEFAULT_ONLY); | |
| 179 | |
| 180 boolean hasBrowserSupportingWebApks = false; | |
| 181 List<BrowserItem> browsers = new ArrayList<>(); | |
| 182 for (ResolveInfo info : resolvedActivityList) { | |
| 183 boolean supportsWebApk = false; | |
| 184 if (sBrowsersSupportingWebApk.contains(info.activityInfo.packageName )) { | |
| 185 supportsWebApk = true; | |
| 186 hasBrowserSupportingWebApks = true; | |
| 187 } | |
| 188 browsers.add(new BrowserItem(info.activityInfo.packageName, | |
| 189 info.loadLabel(packageManager), info.loadIcon(packageManager ), supportsWebApk)); | |
| 190 } | |
| 191 | |
| 192 if (hasBrowserSupportingWebApks) return browsers; | |
| 193 | |
| 194 // TODO(hanxi): add Chrome's icon to WebAPKs. | |
| 195 browsers.add(new BrowserItem("com.android.chrome", "Chrome", null, true) ); | |
| 196 return browsers; | |
| 197 } | |
| 198 | |
| 199 /** | |
| 65 * Returns the uid for the host browser that was specified when building the WebAPK. | 200 * Returns the uid for the host browser that was specified when building the WebAPK. |
| 66 * @param context A context. | 201 * @param context A context. |
| 67 * @return The application uid. Returns -1 on an error. | 202 * @return The application uid. Returns -1 on an error. |
| 68 */ | 203 */ |
| 69 public static int getHostBrowserUid(Context context) { | 204 public static int getHostBrowserUid(Context context) { |
| 70 String hostPackageName = getHostBrowserPackageName(context); | 205 String hostPackageName = getHostBrowserPackageName(context); |
| 71 if (hostPackageName == null) { | 206 if (hostPackageName == null) { |
| 72 return -1; | 207 return -1; |
| 73 } | 208 } |
| 74 try { | 209 try { |
| 75 PackageManager packageManager = context.getPackageManager(); | 210 PackageManager packageManager = context.getPackageManager(); |
| 76 ApplicationInfo appInfo = packageManager.getApplicationInfo( | 211 ApplicationInfo appInfo = packageManager.getApplicationInfo( |
| 77 hostPackageName, PackageManager.GET_META_DATA); | 212 hostPackageName, PackageManager.GET_META_DATA); |
| 78 return appInfo.uid; | 213 return appInfo.uid; |
| 79 } catch (NameNotFoundException e) { | 214 } catch (NameNotFoundException e) { |
| 80 e.printStackTrace(); | 215 e.printStackTrace(); |
| 81 } | 216 } |
| 82 return -1; | 217 return -1; |
| 83 } | 218 } |
| 219 | |
| 220 /** Returns the package name of the host browser cached in the SharedPrefere nces. */ | |
| 221 private static String getHostBrowserFromSharedPreference(Context context) { | |
| 222 SharedPreferences sharedPref = | |
| 223 context.getSharedPreferences(WebApkConstants.PREF_PACKAGE, Conte xt.MODE_PRIVATE); | |
| 224 return sharedPref.getString(SHARED_PREF_RUNTIME_HOST, null); | |
| 225 } | |
| 226 | |
| 227 /** Returns a set of package names of all the installed browsers on the devi ce. */ | |
| 228 public static Set<String> getInstalledBrowsers(PackageManager packageManager ) { | |
| 229 Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http:// ")); | |
| 230 List<ResolveInfo> resolvedActivityList = packageManager.queryIntentActiv ities( | |
| 231 browserIntent, PackageManager.MATCH_DEFAULT_ONLY); | |
| 232 | |
| 233 Set<String> packagesSupportingWebApks = new HashSet<String>(); | |
| 234 for (ResolveInfo info : resolvedActivityList) { | |
| 235 packagesSupportingWebApks.add(info.activityInfo.packageName); | |
| 236 } | |
| 237 return packagesSupportingWebApks; | |
| 238 } | |
| 239 | |
| 240 /** Returns the package name of the "runtime host" in the AndroidManifest.xm l. */ | |
| 241 public static String getHostBrowserFromAndroidManifest( | |
| 242 PackageManager packageManager, String webApkPackageName) { | |
| 243 try { | |
| 244 ApplicationInfo ai = packageManager.getApplicationInfo( | |
| 245 webApkPackageName, PackageManager.GET_META_DATA); | |
| 246 Bundle bundle = ai.metaData; | |
| 247 return bundle.getString(WebApkMetaDataKeys.RUNTIME_HOST); | |
| 248 } catch (NameNotFoundException e) { | |
| 249 return null; | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 /** Returns the package name of the default browser on the Android device. * / | |
| 254 private static String getDefaultBrowserPackageName(PackageManager packageMan ager) { | |
| 255 Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http:// ")); | |
| 256 ResolveInfo resolveInfo = | |
| 257 packageManager.resolveActivity(browserIntent, PackageManager.MAT CH_DEFAULT_ONLY); | |
| 258 if (resolveInfo == null || resolveInfo.activityInfo == null) return null ; | |
| 259 | |
| 260 return resolveInfo.activityInfo.packageName; | |
| 261 } | |
| 262 | |
| 263 /** | |
| 264 * Writes the package name of the host browser to the SharedPreferences. If the host browser is | |
| 265 * different than the previous one stored, delete the SharedPreference befor e storing the new | |
| 266 * host browser. | |
| 267 */ | |
| 268 public static void writeHostBrowserToSharedPref(Context context, String host Package) { | |
| 269 if (TextUtils.isEmpty(hostPackage)) return; | |
| 270 | |
| 271 SharedPreferences sharedPref = | |
| 272 context.getSharedPreferences(WebApkConstants.PREF_PACKAGE, Conte xt.MODE_PRIVATE); | |
| 273 SharedPreferences.Editor editor = sharedPref.edit(); | |
| 274 editor.putString(SHARED_PREF_RUNTIME_HOST, hostPackage); | |
| 275 editor.apply(); | |
| 276 } | |
| 277 | |
| 278 /** Deletes the SharedPreferences. */ | |
| 279 private static void deleteSharedPref(Context context) { | |
| 280 SharedPreferences sharedPref = | |
| 281 context.getSharedPreferences(WebApkConstants.PREF_PACKAGE, Conte xt.MODE_PRIVATE); | |
| 282 SharedPreferences.Editor editor = sharedPref.edit(); | |
| 283 editor.clear(); | |
| 284 editor.apply(); | |
| 285 } | |
| 84 } | 286 } |
| OLD | NEW |