Commit 1aca949a authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

[Android WebAPK] Split host browser checking logic out of WebApkUtils 2/X

As part of fixing BUG 817263, I am going to add more methods to WebApkUtils.
This CL splits out the host browser selection logic into its own class.

Bug=817263

Change-Id: I60a2246959ecb008d69937fbe62b37b2769b99ce
Reviewed-on: https://chromium-review.googlesource.com/1184980
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarXi Han <hanxi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#587943}
parent 09393b82
......@@ -38,6 +38,7 @@ template("webapk_java") {
"src/org/chromium/webapk/shell_apk/HostBrowserClassLoader.java",
"src/org/chromium/webapk/shell_apk/HostBrowserLauncher.java",
"src/org/chromium/webapk/shell_apk/ChooseHostBrowserDialog.java",
"src/org/chromium/webapk/shell_apk/HostBrowserUtils.java",
"src/org/chromium/webapk/shell_apk/IdentityService.java",
"src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java",
"src/org/chromium/webapk/shell_apk/MainActivity.java",
......@@ -195,6 +196,7 @@ android_library("shell_apk_javatests") {
junit_binary("webapk_shell_apk_junit_tests") {
java_files = [
"junit/src/org/chromium/webapk/shell_apk/HostBrowserClassLoaderTest.java",
"junit/src/org/chromium/webapk/shell_apk/HostBrowserUtilsTest.java",
"junit/src/org/chromium/webapk/shell_apk/MainActivityTest.java",
"junit/src/org/chromium/webapk/shell_apk/ShareActivityTest.java",
"junit/src/org/chromium/webapk/shell_apk/WebApkServiceImplWrapperTest.java",
......
......@@ -143,7 +143,7 @@ public class ChooseHostBrowserDialog {
private static List<BrowserItem> getBrowserInfosForHostBrowserSelection(
PackageManager packageManager, List<ResolveInfo> resolveInfos) {
List<BrowserItem> browsers = new ArrayList<>();
List<String> browsersSupportingWebApk = WebApkUtils.getBrowsersSupportingWebApk();
List<String> browsersSupportingWebApk = HostBrowserUtils.getBrowsersSupportingWebApk();
Set<String> packages = new HashSet<>();
for (ResolveInfo info : resolveInfos) {
......
......@@ -52,7 +52,7 @@ public class HostBrowserClassLoader {
*/
public static ClassLoader getClassLoaderInstance(Context context, String canaryClassName) {
assertRunningOnUiThread();
Context remoteContext = WebApkUtils.getHostBrowserContext(context);
Context remoteContext = HostBrowserUtils.getHostBrowserContext(context);
if (remoteContext == null) {
Log.w(TAG, "Failed to get remote context.");
return null;
......
......@@ -99,8 +99,9 @@ class HostBrowserLauncher {
String packageName = mContext.getPackageName();
Log.v(TAG, "Package name of the WebAPK:" + packageName);
String runtimeHostInPreferences = WebApkUtils.getHostBrowserFromSharedPreference(mContext);
String runtimeHost = WebApkUtils.getHostBrowserPackageName(mContext);
String runtimeHostInPreferences =
HostBrowserUtils.getHostBrowserFromSharedPreference(mContext);
String runtimeHost = HostBrowserUtils.getHostBrowserPackageName(mContext);
if (!TextUtils.isEmpty(runtimeHostInPreferences)
&& !runtimeHostInPreferences.equals(runtimeHost)) {
deleteSharedPref();
......@@ -203,7 +204,7 @@ class HostBrowserLauncher {
/** Returns whether there is any installed browser supporting WebAPKs. */
private static boolean hasBrowserSupportingWebApks(List<ResolveInfo> resolveInfos) {
List<String> browsersSupportingWebApk = WebApkUtils.getBrowsersSupportingWebApk();
List<String> browsersSupportingWebApk = HostBrowserUtils.getBrowsersSupportingWebApk();
for (ResolveInfo info : resolveInfos) {
if (browsersSupportingWebApk.contains(info.activityInfo.packageName)) {
return true;
......@@ -219,7 +220,8 @@ class HostBrowserLauncher {
@Override
public void onHostBrowserSelected(String selectedHostBrowser) {
launchInHostBrowser(selectedHostBrowser, true);
WebApkUtils.writeHostBrowserToSharedPref(mContext, selectedHostBrowser);
HostBrowserUtils.writeHostBrowserToSharedPref(
mContext, selectedHostBrowser);
finishCallback.run();
}
@Override
......@@ -250,7 +252,7 @@ class HostBrowserLauncher {
@Override
public void onConfirmInstall(String packageName) {
installBrowser(packageName);
WebApkUtils.writeHostBrowserToSharedPref(mContext, packageName);
HostBrowserUtils.writeHostBrowserToSharedPref(mContext, packageName);
finishCallback.run();
}
@Override
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.webapk.shell_apk;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.text.TextUtils;
import org.chromium.webapk.lib.common.WebApkConstants;
import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Contains methods for getting information about host browser.
*/
public class HostBrowserUtils {
public static final String SHARED_PREF_RUNTIME_HOST = "runtime_host";
private static final String TAG = "cr_HostBrowserUtils";
/**
* The package names of the channels of Chrome that support WebAPKs. The most preferred one
* comes first.
*/
private static List<String> sBrowsersSupportingWebApk = new ArrayList<String>(
Arrays.asList("com.google.android.apps.chrome", "com.android.chrome", "com.chrome.beta",
"com.chrome.dev", "com.chrome.canary", "org.chromium.chrome"));
/** Caches the package name of the host browser. */
private static String sHostPackage;
/** For testing only. */
public static void resetCachedHostPackageForTesting() {
sHostPackage = null;
}
/**
* Returns a list of browsers that support WebAPKs. TODO(hanxi): Replace this function once we
* figure out a better way to know which browser supports WebAPKs.
*/
public static List<String> getBrowsersSupportingWebApk() {
return sBrowsersSupportingWebApk;
}
/**
* Returns a Context for the host browser that was specified when building the WebAPK.
* @param context A context.
* @return The remote context. Returns null on an error.
*/
public static Context getHostBrowserContext(Context context) {
try {
String hostPackage = getHostBrowserPackageName(context);
return context.getApplicationContext().createPackageContext(hostPackage, 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* Returns the package name of the host browser to launch the WebAPK. Also caches the package
* name in the SharedPreference if it is not null.
* @param context A context.
* @return The package name. Returns null on an error.
*/
public static String getHostBrowserPackageName(Context context) {
if (sHostPackage == null
|| !WebApkUtils.isInstalled(context.getPackageManager(), sHostPackage)) {
sHostPackage = getHostBrowserPackageNameInternal(context);
if (sHostPackage != null) {
writeHostBrowserToSharedPref(context, sHostPackage);
}
}
return sHostPackage;
}
/**
* Returns the package name of the host browser to launch the WebAPK, or null if we did not find
* one.
*/
private static String getHostBrowserPackageNameInternal(Context context) {
Set<String> installedBrowsers = getInstalledBrowsers(context.getPackageManager());
if (installedBrowsers.isEmpty()) {
return null;
}
// Gets the package name of the host browser if it is stored in the SharedPreference.
String cachedHostBrowser = getHostBrowserFromSharedPreference(context);
if (!TextUtils.isEmpty(cachedHostBrowser)
&& installedBrowsers.contains(cachedHostBrowser)) {
return cachedHostBrowser;
}
// Gets the package name of the host browser if it is specified in AndroidManifest.xml.
String hostBrowserFromManifest =
WebApkUtils.readMetaDataFromManifest(context, WebApkMetaDataKeys.RUNTIME_HOST);
if (!TextUtils.isEmpty(hostBrowserFromManifest)) {
if (installedBrowsers.contains(hostBrowserFromManifest)) {
return hostBrowserFromManifest;
}
return null;
}
// Gets the package name of the default browser on the Android device.
// TODO(hanxi): Investigate the best way to know which browser supports WebAPKs.
String defaultBrowser = getDefaultBrowserPackageName(context.getPackageManager());
if (!TextUtils.isEmpty(defaultBrowser) && installedBrowsers.contains(defaultBrowser)
&& sBrowsersSupportingWebApk.contains(defaultBrowser)) {
return defaultBrowser;
}
// If there is only one browser supporting WebAPK, and we can't decide which browser to use
// by looking up cache, metadata and default browser, open with that browser.
int availableBrowserCounter = 0;
String lastSupportedBrowser = null;
for (String packageName : installedBrowsers) {
if (availableBrowserCounter > 1) break;
if (sBrowsersSupportingWebApk.contains(packageName)) {
availableBrowserCounter++;
lastSupportedBrowser = packageName;
}
}
if (availableBrowserCounter == 1) {
return lastSupportedBrowser;
}
return null;
}
/**
* Returns the uid for the host browser that was specified when building the WebAPK.
* @param context A context.
* @return The application uid. Returns -1 on an error.
*/
public static int getHostBrowserUid(Context context) {
String hostPackageName = getHostBrowserPackageName(context);
if (hostPackageName == null) {
return -1;
}
try {
PackageManager packageManager = context.getPackageManager();
ApplicationInfo appInfo = packageManager.getApplicationInfo(
hostPackageName, PackageManager.GET_META_DATA);
return appInfo.uid;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return -1;
}
/** Returns the package name of the host browser cached in the SharedPreferences. */
public static String getHostBrowserFromSharedPreference(Context context) {
SharedPreferences sharedPref =
context.getSharedPreferences(WebApkConstants.PREF_PACKAGE, Context.MODE_PRIVATE);
return sharedPref.getString(SHARED_PREF_RUNTIME_HOST, null);
}
/** Returns a set of package names of all the installed browsers on the device. */
private static Set<String> getInstalledBrowsers(PackageManager packageManager) {
List<ResolveInfo> resolvedInfos =
WebApkUtils.getInstalledBrowserResolveInfos(packageManager);
Set<String> packagesSupportingWebApks = new HashSet<String>();
for (ResolveInfo info : resolvedInfos) {
packagesSupportingWebApks.add(info.activityInfo.packageName);
}
return packagesSupportingWebApks;
}
/** Returns the package name of the default browser on the Android device. */
private static String getDefaultBrowserPackageName(PackageManager packageManager) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://"));
ResolveInfo resolveInfo =
packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (resolveInfo == null || resolveInfo.activityInfo == null) return null;
return resolveInfo.activityInfo.packageName;
}
/**
* Writes the package name of the host browser to the SharedPreferences. If the host browser is
* different than the previous one stored, delete the SharedPreference before storing the new
* host browser.
*/
public static void writeHostBrowserToSharedPref(Context context, String hostPackage) {
if (TextUtils.isEmpty(hostPackage)) return;
SharedPreferences sharedPref =
context.getSharedPreferences(WebApkConstants.PREF_PACKAGE, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(SHARED_PREF_RUNTIME_HOST, hostPackage);
editor.apply();
}
}
......@@ -18,7 +18,7 @@ public class IdentityService extends Service {
public String getRuntimeHostBrowserPackageName() {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
try {
return WebApkUtils.getHostBrowserPackageName(getApplicationContext());
return HostBrowserUtils.getHostBrowserPackageName(getApplicationContext());
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
......
......@@ -50,7 +50,7 @@ public class WebApkServiceFactory extends Service {
webApkClassLoader.loadClass(WEBAPK_SERVICE_IMPL_CLASS_NAME);
Constructor<?> webApkServiceImplConstructor =
webApkServiceImplClass.getConstructor(Context.class, Bundle.class);
int hostBrowserUid = WebApkUtils.getHostBrowserUid(this);
int hostBrowserUid = HostBrowserUtils.getHostBrowserUid(this);
Bundle bundle = new Bundle();
bundle.putInt(KEY_SMALL_ICON_ID, R.drawable.notification_badge);
bundle.putInt(KEY_HOST_BROWSER_UID, hostBrowserUid);
......
......@@ -6,7 +6,6 @@ package org.chromium.webapk.shell_apk;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
......@@ -20,80 +19,18 @@ import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
import org.chromium.webapk.lib.common.WebApkConstants;
import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Contains utility methods for interacting with WebAPKs.
*/
public class WebApkUtils {
public static final String SHARED_PREF_RUNTIME_HOST = "runtime_host";
private static final int MINIMUM_REQUIRED_CHROME_VERSION = 57;
private static final String TAG = "cr_WebApkUtils";
/**
* The package names of the channels of Chrome that support WebAPKs. The most preferred one
* comes first.
*/
private static List<String> sBrowsersSupportingWebApk = new ArrayList<String>(
Arrays.asList("com.google.android.apps.chrome", "com.android.chrome", "com.chrome.beta",
"com.chrome.dev", "com.chrome.canary", "org.chromium.chrome"));
/** Caches the package name of the host browser. */
private static String sHostPackage;
/** For testing only. */
public static void resetCachedHostPackageForTesting() {
sHostPackage = null;
}
/**
* Returns a list of browsers that support WebAPKs. TODO(hanxi): Replace this function once we
* figure out a better way to know which browser supports WebAPKs.
*/
public static List<String> getBrowsersSupportingWebApk() {
return sBrowsersSupportingWebApk;
}
/**
* Returns a Context for the host browser that was specified when building the WebAPK.
* @param context A context.
* @return The remote context. Returns null on an error.
*/
public static Context getHostBrowserContext(Context context) {
try {
String hostPackage = getHostBrowserPackageName(context);
return context.getApplicationContext().createPackageContext(
hostPackage, 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/**
* Returns the package name of the host browser to launch the WebAPK. Also caches the package
* name in the SharedPreference if it is not null.
* @param context A context.
* @return The package name. Returns null on an error.
*/
public static String getHostBrowserPackageName(Context context) {
if (sHostPackage == null || !isInstalled(context.getPackageManager(), sHostPackage)) {
sHostPackage = getHostBrowserPackageNameInternal(context);
if (sHostPackage != null) {
writeHostBrowserToSharedPref(context, sHostPackage);
}
}
return sHostPackage;
}
private static final float CONTRAST_LIGHT_ITEM_THRESHOLD = 3f;
/** Returns whether the application is installed and enabled. */
public static boolean isInstalled(PackageManager packageManager, String packageName) {
......@@ -151,58 +88,6 @@ public class WebApkUtils {
return returnUrlBuilder.toString();
}
/**
* Returns the package name of the host browser to launch the WebAPK, or null if we did not find
* one.
*/
private static String getHostBrowserPackageNameInternal(Context context) {
Set<String> installedBrowsers = getInstalledBrowsers(context.getPackageManager());
if (installedBrowsers.isEmpty()) {
return null;
}
// Gets the package name of the host browser if it is stored in the SharedPreference.
String cachedHostBrowser = getHostBrowserFromSharedPreference(context);
if (!TextUtils.isEmpty(cachedHostBrowser)
&& installedBrowsers.contains(cachedHostBrowser)) {
return cachedHostBrowser;
}
// Gets the package name of the host browser if it is specified in AndroidManifest.xml.
String hostBrowserFromManifest =
readMetaDataFromManifest(context, WebApkMetaDataKeys.RUNTIME_HOST);
if (!TextUtils.isEmpty(hostBrowserFromManifest)) {
if (installedBrowsers.contains(hostBrowserFromManifest)) {
return hostBrowserFromManifest;
}
return null;
}
// Gets the package name of the default browser on the Android device.
// TODO(hanxi): Investigate the best way to know which browser supports WebAPKs.
String defaultBrowser = getDefaultBrowserPackageName(context.getPackageManager());
if (!TextUtils.isEmpty(defaultBrowser) && installedBrowsers.contains(defaultBrowser)
&& sBrowsersSupportingWebApk.contains(defaultBrowser)) {
return defaultBrowser;
}
// If there is only one browser supporting WebAPK, and we can't decide which browser to use
// by looking up cache, metadata and default browser, open with that browser.
int availableBrowserCounter = 0;
String lastSupportedBrowser = null;
for (String packageName : installedBrowsers) {
if (availableBrowserCounter > 1) break;
if (sBrowsersSupportingWebApk.contains(packageName)) {
availableBrowserCounter++;
lastSupportedBrowser = packageName;
}
}
if (availableBrowserCounter == 1) {
return lastSupportedBrowser;
}
return null;
}
/** Returns a list of ResolveInfo for all of the installed browsers. */
public static List<ResolveInfo> getInstalledBrowserResolveInfos(PackageManager packageManager) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://"));
......@@ -211,70 +96,6 @@ public class WebApkUtils {
return packageManager.queryIntentActivities(browserIntent, PackageManager.MATCH_ALL);
}
/**
* Returns the uid for the host browser that was specified when building the WebAPK.
* @param context A context.
* @return The application uid. Returns -1 on an error.
*/
public static int getHostBrowserUid(Context context) {
String hostPackageName = getHostBrowserPackageName(context);
if (hostPackageName == null) {
return -1;
}
try {
PackageManager packageManager = context.getPackageManager();
ApplicationInfo appInfo = packageManager.getApplicationInfo(
hostPackageName, PackageManager.GET_META_DATA);
return appInfo.uid;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return -1;
}
/** Returns the package name of the host browser cached in the SharedPreferences. */
public static String getHostBrowserFromSharedPreference(Context context) {
SharedPreferences sharedPref =
context.getSharedPreferences(WebApkConstants.PREF_PACKAGE, Context.MODE_PRIVATE);
return sharedPref.getString(SHARED_PREF_RUNTIME_HOST, null);
}
/** Returns a set of package names of all the installed browsers on the device. */
private static Set<String> getInstalledBrowsers(PackageManager packageManager) {
List<ResolveInfo> resolvedInfos = getInstalledBrowserResolveInfos(packageManager);
Set<String> packagesSupportingWebApks = new HashSet<String>();
for (ResolveInfo info : resolvedInfos) {
packagesSupportingWebApks.add(info.activityInfo.packageName);
}
return packagesSupportingWebApks;
}
/** Returns the package name of the default browser on the Android device. */
private static String getDefaultBrowserPackageName(PackageManager packageManager) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://"));
ResolveInfo resolveInfo =
packageManager.resolveActivity(browserIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (resolveInfo == null || resolveInfo.activityInfo == null) return null;
return resolveInfo.activityInfo.packageName;
}
/**
* Writes the package name of the host browser to the SharedPreferences. If the host browser is
* different than the previous one stored, delete the SharedPreference before storing the new
* host browser.
*/
public static void writeHostBrowserToSharedPref(Context context, String hostPackage) {
if (TextUtils.isEmpty(hostPackage)) return;
SharedPreferences sharedPref =
context.getSharedPreferences(WebApkConstants.PREF_PACKAGE, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(SHARED_PREF_RUNTIME_HOST, hostPackage);
editor.apply();
}
/**
* Android uses padding_left under API level 17 and uses padding_start after that.
* If we set the padding in resource file, android will create duplicated resource xml
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment