Upstream: Launch WebAPK without showing intent picker when user taps link in WebAPK scope
This CL surpresses the intent picker when:
- User navigates via a link
AND
- The URL falls in the scope of a WebAPK
AND
- The WebAPK is the only specialized handler for the URL
BUG=609122
TEST=ExternalNavigationHandlerTest.*
Review-Url: https://codereview.chromium.org/2035183002
Cr-Commit-Position: refs/heads/master@{#398946}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java
index cbf9cd0..6a4cc99c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegate.java
@@ -35,6 +35,19 @@
boolean isSpecializedHandlerAvailable(List<ResolveInfo> intent);
/**
+ * Returns the number of specialized intent handlers in {@params infos}. Specialized intent
+ * handlers are intent handlers which handle only a few URLs (e.g. google maps or youtube).
+ */
+ int countSpecializedHandlers(List<ResolveInfo> infos);
+
+ /**
+ * Returns the package name of the first valid WebAPK in {@link infos}.
+ * @param infos ResolveInfos to search.
+ * @return The package name of the first valid WebAPK. Null if no valid WebAPK was found.
+ */
+ String findValidWebApkPackageName(List<ResolveInfo> infos);
+
+ /**
* Get the name of the package of the currently running activity so that incoming intents
* can be identified as originating from this activity.
*/
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
index f6946ec..a03a389 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImpl.java
@@ -12,7 +12,6 @@
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
@@ -45,6 +44,7 @@
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.base.WindowAndroid.PermissionCallback;
+import org.chromium.webapk.lib.client.WebApkValidator;
import java.util.List;
@@ -227,31 +227,41 @@
@Override
public boolean isSpecializedHandlerAvailable(List<ResolveInfo> infos) {
- return isPackageSpecializedHandler(infos, null);
+ return countSpecializedHandlers(infos) > 0;
}
- static boolean isPackageSpecializedHandler(List<ResolveInfo> handlers,
- String packageName) {
- if (handlers == null || handlers.size() == 0) return false;
- for (ResolveInfo resolveInfo : handlers) {
- IntentFilter filter = resolveInfo.filter;
+ @Override
+ public int countSpecializedHandlers(List<ResolveInfo> infos) {
+ return countSpecializedHandlersWithFilter(infos, null);
+ }
+
+ static int countSpecializedHandlersWithFilter(
+ List<ResolveInfo> infos, String filterPackageName) {
+ if (infos == null) {
+ return 0;
+ }
+
+ int count = 0;
+ for (ResolveInfo info : infos) {
+ IntentFilter filter = info.filter;
if (filter == null) {
- // No intent filter matches this intent?
- // Error on the side of staying in the browser, ignore
+ // Error on the side of classifying ResolveInfo as generic.
continue;
}
if (filter.countDataAuthorities() == 0 && filter.countDataPaths() == 0) {
- // Generic handler, skip
+ // Don't count generic handlers.
continue;
}
- if (TextUtils.isEmpty(packageName)) return true;
- ActivityInfo activityInfo = resolveInfo.activityInfo;
- if (activityInfo == null) continue;
- if (!activityInfo.packageName.equals(packageName)) continue;
- return true;
- }
- return false;
+ if (!TextUtils.isEmpty(filterPackageName)
+ && (info.activityInfo == null
+ || !info.activityInfo.packageName.equals(filterPackageName))) {
+ continue;
+ }
+
+ ++count;
+ }
+ return count;
}
/**
@@ -268,7 +278,7 @@
try {
List<ResolveInfo> handlers = context.getPackageManager().queryIntentActivities(
intent, PackageManager.GET_RESOLVED_FILTER);
- return isPackageSpecializedHandler(handlers, packageName);
+ return countSpecializedHandlersWithFilter(handlers, packageName) > 0;
} catch (RuntimeException e) {
logTransactionTooLargeOrRethrow(e, intent);
}
@@ -276,6 +286,14 @@
}
@Override
+ public String findValidWebApkPackageName(List<ResolveInfo> infos) {
+ String webApkPackageName = WebApkValidator.findWebApkPackage(infos);
+ return WebApkValidator.isValidWebApk(mApplicationContext, webApkPackageName)
+ ? webApkPackageName
+ : null;
+ }
+
+ @Override
public String getPackageName() {
return mApplicationContext.getPackageName();
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 62e7b26..8706863 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -347,7 +347,7 @@
// startActivityIfNeeded or startActivity.
if (!isExternalProtocol) {
if (!mDelegate.isSpecializedHandlerAvailable(resolvingInfos)) {
- if (params.isWebApk()) {
+ if (params.webApkPackageName() != null) {
intent.setPackage(mDelegate.getPackageName());
mDelegate.startActivity(intent);
return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT;
@@ -412,6 +412,17 @@
IntentWithGesturesHandler.getInstance().onNewIntentWithGesture(intent);
}
+ if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_WEBAPK)) {
+ // If the only specialized intent handler is a WebAPK, set the intent's package
+ // to launch the WebAPK without showing the intent picker.
+ String targetWebApkPackageName =
+ mDelegate.findValidWebApkPackageName(resolvingInfos);
+ if (targetWebApkPackageName != null
+ && mDelegate.countSpecializedHandlers(resolvingInfos) == 1) {
+ intent.setPackage(targetWebApkPackageName);
+ }
+ }
+
if (mDelegate.startActivityIfNeeded(intent)) {
return OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT;
} else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationParams.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationParams.java
index 403bfbce..7d6192b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationParams.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationParams.java
@@ -43,8 +43,11 @@
/** Whether this navigation happens in main frame. */
private final boolean mIsMainFrame;
- /** Whether this navigation happens in a WebAPK. */
- private final boolean mIsWebApk;
+ /**
+ * The package name of the WebAPK that the navigation happens in. Null if the navigation is not
+ * happening in a WebAPK.
+ */
+ private final String mWebApkPackageName;
/** Whether this navigation is launched by user gesture. */
private final boolean mHasUserGesture;
@@ -58,7 +61,7 @@
private ExternalNavigationParams(String url, boolean isIncognito, String referrerUrl,
int pageTransition, boolean isRedirect, boolean appMustBeInForeground,
TabRedirectHandler redirectHandler, Tab tab, boolean openInNewTab,
- boolean isBackgroundTabNavigation, boolean isMainFrame, boolean isWebApk,
+ boolean isBackgroundTabNavigation, boolean isMainFrame, String webApkPackageName,
boolean hasUserGesture,
boolean shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent) {
mUrl = url;
@@ -72,7 +75,7 @@
mOpenInNewTab = openInNewTab;
mIsBackgroundTabNavigation = isBackgroundTabNavigation;
mIsMainFrame = isMainFrame;
- mIsWebApk = isWebApk;
+ mWebApkPackageName = webApkPackageName;
mHasUserGesture = hasUserGesture;
mShouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent =
shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent;
@@ -136,9 +139,12 @@
return mIsMainFrame;
}
- /** @return Whether this navigation happens in a WebAPK. */
- public boolean isWebApk() {
- return mIsWebApk;
+ /**
+ * @return Package name of the WebAPK that the navigation happens in. Null if the navigation is
+ * not happening in a WebAPK.
+ */
+ public String webApkPackageName() {
+ return mWebApkPackageName;
}
/** @return Whether this navigation is launched by user gesture. */
@@ -188,8 +194,11 @@
/** Whether this navigation happens in main frame. */
private boolean mIsMainFrame;
- /** Whether this navigation happens in a WebAPK. */
- private boolean mIsWebApk;
+ /**
+ * The package name of the WebAPK that the navigation happens in. Null if the navigation is
+ * not happening in a WebAPK.
+ */
+ private String mWebApkPackageName;
/** Whether this navigation is launched by user gesture. */
private boolean mHasUserGesture;
@@ -250,9 +259,12 @@
return this;
}
- /** Sets whether this navigation happens in a WebAPK. */
- public Builder setIsWebApk(boolean v) {
- mIsWebApk = v;
+ /**
+ * Sets the package name of the WebAPK that the navigation happens in. Null if the
+ * navigation is not happening in a WebAPK.
+ */
+ public Builder setWebApkPackageName(String v) {
+ mWebApkPackageName = v;
return this;
}
@@ -274,7 +286,7 @@
public ExternalNavigationParams build() {
return new ExternalNavigationParams(mUrl, mIsIncognito, mReferrerUrl, mPageTransition,
mIsRedirect, mApplicationMustBeInForeground, mRedirectHandler, mTab,
- mOpenInNewTab, mIsBackgroundTabNavigation, mIsMainFrame, mIsWebApk,
+ mOpenInNewTab, mIsBackgroundTabNavigation, mIsMainFrame, mWebApkPackageName,
mHasUserGesture, mShouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent);
}
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
index d37fa440..42b8d2e8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -65,7 +65,7 @@
ExternalNavigationParams.Builder builder =
super.buildExternalNavigationParams(
navigationParams, tabRedirectHandler, shouldCloseTab);
- builder.setIsWebApk(true);
+ builder.setWebApkPackageName(getWebApkPackageName());
return builder;
}
};
@@ -83,9 +83,15 @@
public void onStop() {
super.onStop();
- String packageName = getWebappInfo().webApkPackageName();
WebApkServiceConnectionManager.getInstance().disconnect(
- ContextUtils.getApplicationContext(), packageName);
+ ContextUtils.getApplicationContext(), getWebApkPackageName());
+ }
+
+ /**
+ * Returns the WebAPK's package name.
+ */
+ private String getWebApkPackageName() {
+ return getWebappInfo().webApkPackageName();
}
@Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java
index 9dc032e..34e320c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationDelegateImplTest.java
@@ -34,8 +34,8 @@
public void testIsPackageSpecializedHandler_NoResolveInfo() {
String packageName = "";
List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>();
- assertFalse(ExternalNavigationDelegateImpl
- .isPackageSpecializedHandler(resolveInfos, packageName));
+ assertEquals(0, ExternalNavigationDelegateImpl.countSpecializedHandlersWithFilter(
+ resolveInfos, packageName));
}
@SmallTest
@@ -44,8 +44,8 @@
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
- assertFalse(ExternalNavigationDelegateImpl
- .isPackageSpecializedHandler(resolveInfos, packageName));
+ assertEquals(0, ExternalNavigationDelegateImpl.countSpecializedHandlersWithFilter(
+ resolveInfos, packageName));
}
@SmallTest
@@ -55,8 +55,8 @@
info.filter = new IntentFilter();
info.filter.addDataPath("somepath", 2);
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
- assertTrue(ExternalNavigationDelegateImpl
- .isPackageSpecializedHandler(resolveInfos, packageName));
+ assertEquals(1, ExternalNavigationDelegateImpl.countSpecializedHandlersWithFilter(
+ resolveInfos, packageName));
}
@SmallTest
@@ -66,8 +66,8 @@
info.filter = new IntentFilter();
info.filter.addDataAuthority("http://www.google.com", "80");
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
- assertTrue(ExternalNavigationDelegateImpl
- .isPackageSpecializedHandler(resolveInfos, packageName));
+ assertEquals(1, ExternalNavigationDelegateImpl.countSpecializedHandlersWithFilter(
+ resolveInfos, packageName));
}
@SmallTest
@@ -79,8 +79,8 @@
info.activityInfo = new ActivityInfo();
info.activityInfo.packageName = packageName;
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
- assertTrue(ExternalNavigationDelegateImpl
- .isPackageSpecializedHandler(resolveInfos, packageName));
+ assertEquals(1, ExternalNavigationDelegateImpl.countSpecializedHandlersWithFilter(
+ resolveInfos, packageName));
}
@SmallTest
@@ -92,8 +92,8 @@
info.activityInfo = new ActivityInfo();
info.activityInfo.packageName = "com.foo.bar";
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
- assertFalse(ExternalNavigationDelegateImpl
- .isPackageSpecializedHandler(resolveInfos, packageName));
+ assertEquals(0, ExternalNavigationDelegateImpl.countSpecializedHandlersWithFilter(
+ resolveInfos, packageName));
}
@SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index 87a6158..0640deb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -20,12 +20,14 @@
import org.chromium.base.CommandLine;
import org.chromium.base.metrics.RecordHistogram;
+import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler.OverrideUrlLoadingResult;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabRedirectHandler;
import org.chromium.chrome.browser.util.FeatureUtilities;
import org.chromium.ui.base.PageTransition;
+import org.chromium.webapk.lib.common.WebApkConstants;
import java.net.URISyntaxException;
import java.util.ArrayList;
@@ -40,9 +42,10 @@
private static final int IGNORE = 0x0;
private static final int START_INCOGNITO = 0x1;
private static final int START_CHROME = 0x2;
- private static final int START_FILE = 0x4;
- private static final int START_OTHER_ACTIVITY = 0x8;
- private static final int INTENT_SANITIZATION_EXCEPTION = 0x10;
+ private static final int START_WEBAPK = 0x4;
+ private static final int START_FILE = 0x8;
+ private static final int START_OTHER_ACTIVITY = 0x10;
+ private static final int INTENT_SANITIZATION_EXCEPTION = 0x20;
private static final String SEARCH_RESULT_URL_FOR_TOM_HANKS =
"https://www.google.com/search?q=tom+hanks";
@@ -73,6 +76,19 @@
private static final String TEXT_APP_1_PACKAGE_NAME = "text_app_1";
private static final String TEXT_APP_2_PACKAGE_NAME = "text_app_2";
+ private static final String WEBAPK_SCOPE = "https://www.template.com";
+ private static final String WEBAPK_PACKAGE_NAME = "org.chromium.webapk.template";
+
+ private static final String WEBAPK_WITH_NATIVE_APP_SCOPE =
+ "https://www.webapk.with.native.com";
+ private static final String WEBAPK_WITH_NATIVE_APP_PACKAGE_NAME =
+ "org.chromium.webapk.with.native";
+ private static final String NATIVE_APP_PACKAGE_NAME = "com.webapk.with.native.android";
+
+ private static final String COUNTERFEIT_WEBAPK_SCOPE = "http://www.counterfeit.webapk.com";
+ private static final String COUNTERFEIT_WEBAPK_PACKAGE_NAME =
+ "org.chromium.webapk.counterfeit";
+
private final TestExternalNavigationDelegate mDelegate;
private ExternalNavigationHandler mUrlHandler;
@@ -750,16 +766,89 @@
}
/**
- * Test that tapping on a link which is outside of the referrer Web APK's scope brings the
+ * Test that tapping on a link which is outside of the referrer WebAPK's scope brings the
* user back to Chrome.
*/
@SmallTest
public void testLeaveWebApk_LinkOutOfScope() {
checkUrl(SEARCH_RESULT_URL_FOR_TOM_HANKS)
- .withIsWebApk(true)
+ .withWebApkPackageName(WEBAPK_PACKAGE_NAME)
.expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, START_CHROME);
}
+ /**
+ * Test that tapping a link which falls solely into the scope of a WebAPK does not bypass the
+ * intent picker if WebAPKs are disabled in the command line.
+ */
+ @SmallTest
+ public void testLaunchWebApk_WebApkDisabledCommandLine() {
+ checkUrl(WEBAPK_SCOPE)
+ .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT,
+ START_OTHER_ACTIVITY);
+ }
+
+ /**
+ * Test that tapping a link which falls solely in the scope of a WebAPK launches a WebAPK
+ * without showing the intent picker if WebAPKs are enabled in the command line.
+ */
+ @SmallTest
+ public void testLaunchWebApk_BypassIntentPicker() {
+ CommandLine.getInstance().appendSwitch(ChromeSwitches.ENABLE_WEBAPK);
+ checkUrl(WEBAPK_SCOPE)
+ .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, START_WEBAPK);
+ }
+
+ /**
+ * Test that tapping a link which falls in the scope of multiple intent handlers, one of which
+ * is a WebAPK, shows the intent picker.
+ */
+ @SmallTest
+ public void testLaunchWebApk_ShowIntentPickerMultipleIntentHandlers() {
+ CommandLine.getInstance().appendSwitch(ChromeSwitches.ENABLE_WEBAPK);
+ checkUrl(WEBAPK_WITH_NATIVE_APP_SCOPE)
+ .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT,
+ START_OTHER_ACTIVITY);
+ }
+
+ /**
+ * Test that tapping a link which falls solely into the scope of a different WebAPK launches a
+ * WebAPK without showing the intent picker.
+ */
+ @SmallTest
+ public void testLaunchWebApk_BypassIntentPickerFromAnotherWebApk() {
+ CommandLine.getInstance().appendSwitch(ChromeSwitches.ENABLE_WEBAPK);
+ checkUrl(WEBAPK_SCOPE)
+ .withReferrer(WEBAPK_WITH_NATIVE_APP_SCOPE)
+ .withWebApkPackageName(WEBAPK_WITH_NATIVE_APP_PACKAGE_NAME)
+ .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT, START_WEBAPK);
+ }
+
+ /**
+ * Test that a link which falls into the scope of an invalid WebAPK (e.g. it was incorrectly
+ * signed) does not get any special WebAPK handling. The first time that the user taps on the
+ * link, the intent picker should be shown.
+ */
+ @SmallTest
+ public void testLaunchWebApk_ShowIntentPickerInvalidWebApk() {
+ CommandLine.getInstance().appendSwitch(ChromeSwitches.ENABLE_WEBAPK);
+ checkUrl(COUNTERFEIT_WEBAPK_SCOPE)
+ .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT,
+ START_OTHER_ACTIVITY);
+ }
+
+ /**
+ * Test that tapping a link which falls into the scope of the current WebAPK stays within the
+ * WebAPK.
+ */
+ @SmallTest
+ public void testLaunchWebApk_StayInSameWebApk() {
+ CommandLine.getInstance().appendSwitch(ChromeSwitches.ENABLE_WEBAPK);
+ checkUrl(WEBAPK_SCOPE + "/new.html")
+ .withReferrer(WEBAPK_SCOPE)
+ .withWebApkPackageName(WEBAPK_PACKAGE_NAME)
+ .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+ }
+
private static ResolveInfo newResolveInfo(String packageName, String name) {
ActivityInfo ai = new ActivityInfo();
ai.packageName = packageName;
@@ -788,22 +877,31 @@
return list;
}
}
- if (intent.getDataString().startsWith("http://")
+ String dataString = intent.getDataString();
+ if (dataString.startsWith("http://")
|| intent.getDataString().startsWith("https://")) {
list.add(newResolveInfo("chrome", "chrome"));
}
- if (intent.getDataString().startsWith("http://m.youtube.com")
+ if (dataString.startsWith("http://m.youtube.com")
|| intent.getDataString().startsWith("http://youtube.com")) {
list.add(newResolveInfo("youtube", "youtube"));
- } else if (intent.getDataString().startsWith(PLUS_STREAM_URL)) {
+ } else if (dataString.startsWith(PLUS_STREAM_URL)) {
list.add(newResolveInfo("plus", "plus"));
} else if (intent.getDataString().startsWith(CALENDAR_URL)) {
list.add(newResolveInfo("calendar", "calendar"));
- } else if (intent.getDataString().startsWith("sms")) {
+ } else if (dataString.startsWith("sms")) {
list.add(newResolveInfo(
TEXT_APP_1_PACKAGE_NAME, TEXT_APP_1_PACKAGE_NAME + ".cls"));
list.add(newResolveInfo(
TEXT_APP_2_PACKAGE_NAME, TEXT_APP_2_PACKAGE_NAME + ".cls"));
+ } else if (dataString.startsWith(WEBAPK_SCOPE)) {
+ list.add(newResolveInfo(WEBAPK_PACKAGE_NAME, WEBAPK_PACKAGE_NAME));
+ } else if (dataString.startsWith(WEBAPK_WITH_NATIVE_APP_SCOPE)) {
+ list.add(newResolveInfo(WEBAPK_WITH_NATIVE_APP_PACKAGE_NAME,
+ WEBAPK_WITH_NATIVE_APP_PACKAGE_NAME));
+ list.add(newResolveInfo(NATIVE_APP_PACKAGE_NAME, NATIVE_APP_PACKAGE_NAME));
+ } else if (dataString.startsWith(COUNTERFEIT_WEBAPK_SCOPE)) {
+ list.add(newResolveInfo(COUNTERFEIT_WEBAPK_PACKAGE_NAME, COUNTERFEIT_WEBAPK_SCOPE));
} else {
list.add(newResolveInfo("foo", "foo"));
}
@@ -817,13 +915,41 @@
@Override
public boolean isSpecializedHandlerAvailable(List<ResolveInfo> resolveInfos) {
- for (ResolveInfo resolveInfo : resolveInfos) {
- String packageName = resolveInfo.activityInfo.packageName;
- if (packageName.equals("youtube") || packageName.equals("calendar")) {
- return true;
+ return countSpecializedHandlers(resolveInfos) > 0;
+ }
+
+ @Override
+ public int countSpecializedHandlers(List<ResolveInfo> infos) {
+ if (infos == null) {
+ return 0;
+ }
+ int count = 0;
+ for (ResolveInfo info : infos) {
+ String packageName = info.activityInfo.packageName;
+ if (packageName.equals("youtube") || packageName.equals("calendar")
+ || packageName.equals(COUNTERFEIT_WEBAPK_PACKAGE_NAME)
+ || packageName.equals(NATIVE_APP_PACKAGE_NAME)
+ || packageName.equals(WEBAPK_PACKAGE_NAME)
+ || packageName.equals(WEBAPK_WITH_NATIVE_APP_PACKAGE_NAME)) {
+ ++count;
}
}
- return false;
+ return count;
+ }
+
+ @Override
+ public String findValidWebApkPackageName(List<ResolveInfo> infos) {
+ if (infos == null) {
+ return null;
+ }
+ for (ResolveInfo info : infos) {
+ String packageName = info.activityInfo.packageName;
+ if (packageName.equals(WEBAPK_PACKAGE_NAME)
+ || packageName.equals(WEBAPK_WITH_NATIVE_APP_PACKAGE_NAME)) {
+ return packageName;
+ }
+ }
+ return null;
}
@Override
@@ -950,7 +1076,7 @@
private boolean mIsRedirect;
private boolean mChromeAppInForegroundRequired = true;
private boolean mIsBackgroundTabNavigation;
- private boolean mIsWebApk;
+ private String mWebApkPackageName;
private boolean mHasUserGesture;
private TabRedirectHandler mRedirectHandler;
@@ -958,8 +1084,8 @@
mUrl = url;
}
- public ExternalNavigationTestParams withIsWebApk(boolean isWebApk) {
- mIsWebApk = isWebApk;
+ public ExternalNavigationTestParams withWebApkPackageName(String webApkPackageName) {
+ mWebApkPackageName = webApkPackageName;
return this;
}
@@ -1009,8 +1135,9 @@
int otherExpectation) {
boolean expectStartIncognito = (otherExpectation & START_INCOGNITO) != 0;
boolean expectStartActivity =
- (otherExpectation & (START_CHROME | START_OTHER_ACTIVITY)) != 0;
+ (otherExpectation & (START_CHROME | START_WEBAPK | START_OTHER_ACTIVITY)) != 0;
boolean expectStartChrome = (otherExpectation & START_CHROME) != 0;
+ boolean expectStartWebApk = (otherExpectation & START_WEBAPK) != 0;
boolean expectStartOtherActivity = (otherExpectation & START_OTHER_ACTIVITY) != 0;
boolean expectStartFile = (otherExpectation & START_FILE) != 0;
boolean expectSaneIntent = expectStartOtherActivity
@@ -1025,23 +1152,28 @@
.setRedirectHandler(mRedirectHandler)
.setIsBackgroundTabNavigation(mIsBackgroundTabNavigation)
.setIsMainFrame(true)
- .setIsWebApk(mIsWebApk)
+ .setWebApkPackageName(mWebApkPackageName)
.setHasUserGesture(mHasUserGesture)
.build();
OverrideUrlLoadingResult result = mUrlHandler.shouldOverrideUrlLoading(params);
boolean startActivityCalled = false;
boolean startChromeCalled = false;
+ boolean startWebApkCalled = false;
if (mDelegate.startActivityIntent != null) {
startActivityCalled = true;
String packageName = mDelegate.startActivityIntent.getPackage();
- startChromeCalled =
- packageName != null && packageName.equals(mDelegate.getPackageName());
+ if (packageName != null) {
+ startChromeCalled = packageName.equals(mDelegate.getPackageName());
+ startWebApkCalled =
+ packageName.startsWith(WebApkConstants.WEBAPK_PACKAGE_PREFIX);
+ }
}
assertEquals(expectedOverrideResult, result);
assertEquals(expectStartIncognito, mDelegate.startIncognitoIntentCalled);
assertEquals(expectStartActivity, startActivityCalled);
assertEquals(expectStartChrome, startChromeCalled);
+ assertEquals(expectStartWebApk, startWebApkCalled);
assertEquals(expectStartFile, mDelegate.startFileIntentCalled);
if (startActivityCalled && expectSaneIntent) {