[M95] Merge fixes for silently redirecting to other browsers
This merges the following 6 changes to the M95 branch:
Handle web intents without specialized handlers in Chrome.
https://chromium-review.googlesource.com/c/chromium/src/+/3166110
Use fallback URL instead of target URL for web links in-browser
https://chromium-review.googlesource.com/c/chromium/src/+/3187533
Ensure user sees chooser dialog when navigating to a different browser
https://chromium-review.googlesource.com/c/chromium/src/+/3198743
Fix crash in ActivityPicker when using resource obfuscation
https://chromium-review.googlesource.com/c/chromium/src/+/3213013
Include ic_launcher drawable for resources excluded from name collapsing
https://chromium-review.googlesource.com/c/chromium/src/+/3217257
Fix showing chooser dialog for specialized http/s URLs
https://chromium-review.googlesource.com/c/chromium/src/+/3225421
PS1 is the changes cherry-picked without resolving any conflicts (so
entirely unchanged from initial review).
Bug: 1249962
Change-Id: Ifa8835ce683e2c522b490c8c5a37656394f46dcd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3232895
Reviewed-by: Colin Blundell <blundell@chromium.org>
Reviewed-by: Yaron Friedman <yfriedman@chromium.org>
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Cr-Commit-Position: refs/branch-heads/4638@{#937}
Cr-Branched-From: 159257cab5585bc8421abf347984bb32fdfe9eb9-refs/heads/main@{#920003}
diff --git a/base/android/java/src/org/chromium/base/PackageManagerUtils.java b/base/android/java/src/org/chromium/base/PackageManagerUtils.java
index 0d08cc1..7aa7921e 100644
--- a/base/android/java/src/org/chromium/base/PackageManagerUtils.java
+++ b/base/android/java/src/org/chromium/base/PackageManagerUtils.java
@@ -18,7 +18,14 @@
*/
public class PackageManagerUtils {
private static final String TAG = "PackageManagerUtils";
- private static final String SAMPLE_URL = "http://";
+
+ // This is the intent Android uses internally to detect browser apps.
+ // See
+ // https://cs.android.com/android/_/android/platform/packages/modules/Permission/+/android12-release:PermissionController/src/com/android/permissioncontroller/role/model/BrowserRoleBehavior.java;drc=86fa7d5dfa43f66b170f93ade4f59b9a770be32f;l=50
+ public static final Intent BROWSER_INTENT = new Intent()
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.fromParts("http", "", null));
/**
* Retrieve information about the Activity that will handle the given Intent.
@@ -61,14 +68,6 @@
}
/**
- * @return Intent to query a list of installed web browsers.
- */
- public static Intent getQueryInstalledBrowsersIntent() {
- return new Intent(Intent.ACTION_VIEW, Uri.parse(SAMPLE_URL))
- .addCategory(Intent.CATEGORY_BROWSABLE);
- }
-
- /**
* @return Intent to query a list of installed home launchers.
*/
public static Intent getQueryInstalledHomeLaunchersIntent() {
@@ -79,7 +78,7 @@
* @return Default ResolveInfo to handle a VIEW intent for a url.
*/
public static ResolveInfo resolveDefaultWebBrowserActivity() {
- return resolveActivity(getQueryInstalledBrowsersIntent(), 0);
+ return resolveActivity(BROWSER_INTENT, PackageManager.MATCH_DEFAULT_ONLY);
}
/**
@@ -87,7 +86,13 @@
* may appear twice if it has multiple intent handlers.
*/
public static List<ResolveInfo> queryAllWebBrowsersInfo() {
- return queryIntentActivities(getQueryInstalledBrowsersIntent(), PackageManager.MATCH_ALL);
+ // Copying these flags from Android source for detecting the list of installed browsers.
+ // Apparently MATCH_ALL doesn't include MATCH_DIRECT_BOOT_*.
+ // See
+ // https://cs.android.com/android/_/android/platform/packages/modules/Permission/+/android12-release:PermissionController/src/com/android/permissioncontroller/role/model/BrowserRoleBehavior.java;drc=86fa7d5dfa43f66b170f93ade4f59b9a770be32f;l=114
+ int flags = PackageManager.MATCH_ALL | PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_DEFAULT_ONLY;
+ return queryIntentActivities(BROWSER_INTENT, flags);
}
/**
diff --git a/chrome/android/aapt2.config b/chrome/android/aapt2.config
index a1e0ee9..ea85a3e 100644
--- a/chrome/android/aapt2.config
+++ b/chrome/android/aapt2.config
@@ -1 +1,3 @@
+drawable/ic_launcher#no_collapse
+drawable/ic_launcher_round#no_collapse
drawable/shortcut_incognito#no_collapse
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
index 173a1bd3..9d7bbd0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/DefaultBrowserInfo.java
@@ -170,7 +170,7 @@
List<ResolveInfo> ris = PackageManagerUtils.queryAllWebBrowsersInfo();
if (ris != null) {
for (ResolveInfo ri : ris) {
- String packageName = ri.activityInfo.applicationInfo.packageName;
+ String packageName = ri.activityInfo.packageName;
if (!uniquePackages.add(packageName)) continue;
if (isSystemPackage(ri)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
index dad88fe..96bbbb0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -20,7 +20,6 @@
import androidx.browser.trusted.TrustedWebActivityDisplayMode.ImmersiveMode;
import org.chromium.base.ContextUtils;
-import org.chromium.base.IntentUtils;
import org.chromium.base.PackageManagerUtils;
import org.chromium.base.supplier.Supplier;
import org.chromium.cc.input.BrowserControlsState;
@@ -125,39 +124,25 @@
// instead.
boolean isExternalProtocol = !UrlUtilities.isAcceptedScheme(intent.toUri(0));
boolean hasDefaultHandler = hasDefaultHandler(intent);
- try {
- // For a URL chrome can handle and there is no default set, handle it ourselves.
- if (!hasDefaultHandler) {
- if (!TextUtils.isEmpty(mClientPackageName)
- && isPackageSpecializedHandler(mClientPackageName, intent)) {
- intent.setPackage(mClientPackageName);
- } else if (!isExternalProtocol) {
- return StartActivityIfNeededResult.HANDLED_WITHOUT_ACTIVITY_START;
- }
+ // For a URL chrome can handle and there is no default set, handle it ourselves.
+ if (!hasDefaultHandler) {
+ if (!TextUtils.isEmpty(mClientPackageName)
+ && isPackageSpecializedHandler(mClientPackageName, intent)) {
+ // Package and Selector cannot be set at the same time.
+ intent.setSelector(null);
+ intent.setPackage(mClientPackageName);
+ } else if (!isExternalProtocol) {
+ return StartActivityIfNeededResult.HANDLED_WITHOUT_ACTIVITY_START;
}
+ }
- if (proxy) {
- dispatchAuthenticatedIntent(intent);
- mHasActivityStarted = true;
- return StartActivityIfNeededResult.HANDLED_WITH_ACTIVITY_START;
- } else {
- // If android fails to find a handler, handle it ourselves.
- Context context = getAvailableContext();
- if (context instanceof Activity
- && ((Activity) context).startActivityIfNeeded(intent, -1)) {
- mHasActivityStarted = true;
- return StartActivityIfNeededResult.HANDLED_WITH_ACTIVITY_START;
- }
- }
- return StartActivityIfNeededResult.HANDLED_WITHOUT_ACTIVITY_START;
- } catch (SecurityException e) {
- // https://crbug.com/808494: Handle the URL in Chrome if dispatching to another
- // application fails with a SecurityException. This happens due to malformed
- // manifests in another app.
- return StartActivityIfNeededResult.HANDLED_WITHOUT_ACTIVITY_START;
- } catch (RuntimeException e) {
- IntentUtils.logTransactionTooLargeOrRethrow(e, intent);
- return StartActivityIfNeededResult.HANDLED_WITHOUT_ACTIVITY_START;
+ if (proxy) {
+ dispatchAuthenticatedIntent(intent);
+ mHasActivityStarted = true;
+ return StartActivityIfNeededResult.HANDLED_WITH_ACTIVITY_START;
+ } else {
+ // Defer to ExternalNavigationHandler to call startActivityIfNeeded.
+ return StartActivityIfNeededResult.DID_NOT_HANDLE;
}
}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
index 291f658..5873f4b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -7,9 +7,15 @@
import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
@@ -28,8 +34,10 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.chromium.android.support.PackageManagerWrapper;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils;
+import org.chromium.base.PackageManagerUtils;
import org.chromium.base.test.util.ApplicationTestUtils;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
@@ -46,6 +54,7 @@
import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResultType;
import org.chromium.components.external_intents.InterceptNavigationDelegateImpl;
import org.chromium.content_public.browser.LoadUrlParams;
@@ -57,6 +66,8 @@
import org.chromium.ui.base.PageTransition;
import org.chromium.url.GURL;
+import java.util.Arrays;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -105,6 +116,10 @@
BASE_PATH + "navigation_to_file_scheme_via_intent_uri.html";
private static final String SUBFRAME_REDIRECT_WITH_PLAY_FALLBACK =
BASE_PATH + "subframe_navigation_with_play_fallback.html";
+ private static final String REDIRECT_TO_OTHER_BROWSER =
+ BASE_PATH + "redirect_to_other_browser.html";
+
+ private static final String OTHER_BROWSER_PACKAGE = "com.other.browser";
private static class TestTabObserver extends EmptyTabObserver {
private final CallbackHelper mFinishCallback;
@@ -136,8 +151,51 @@
}
}
+ private static ResolveInfo newResolveInfo(String packageName) {
+ ActivityInfo ai = new ActivityInfo();
+ ai.packageName = packageName;
+ ai.name = "Name: " + packageName;
+ ai.applicationInfo = new ApplicationInfo();
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo = ai;
+ return ri;
+ }
+
+ private static class TestContext extends ContextWrapper {
+ public TestContext(Context baseContext) {
+ super(baseContext);
+ }
+
+ @Override
+ public PackageManager getPackageManager() {
+ return new PackageManagerWrapper(super.getPackageManager()) {
+ @Override
+ public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
+ if ((intent.getPackage() != null
+ && intent.getPackage().equals(OTHER_BROWSER_PACKAGE))
+ || intent.filterEquals(PackageManagerUtils.BROWSER_INTENT)) {
+ return Arrays.asList(newResolveInfo(OTHER_BROWSER_PACKAGE));
+ }
+
+ return TestContext.super.getPackageManager().queryIntentActivities(
+ intent, flags);
+ }
+
+ @Override
+ public ResolveInfo resolveActivity(Intent intent, int flags) {
+ if (intent.getPackage() != null
+ && intent.getPackage().equals(OTHER_BROWSER_PACKAGE)) {
+ return newResolveInfo(OTHER_BROWSER_PACKAGE);
+ }
+ return TestContext.super.getPackageManager().resolveActivity(intent, flags);
+ }
+ };
+ }
+ }
+
private ActivityMonitor mActivityMonitor;
private EmbeddedTestServer mTestServer;
+ private Context mContextToRestore;
@Before
public void setUp() throws Exception {
@@ -146,12 +204,19 @@
filter.addDataScheme("market");
mActivityMonitor = InstrumentationRegistry.getInstrumentation().addMonitor(
filter, new Instrumentation.ActivityResult(Activity.RESULT_OK, null), true);
- mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+ mTestServer = mActivityTestRule.getTestServer();
}
@After
public void tearDown() {
- mTestServer.stopAndDestroyServer();
+ if (mContextToRestore != null) {
+ ContextUtils.initApplicationContextForTests(mContextToRestore);
+ }
+ }
+
+ private void setUpTestContext() {
+ mContextToRestore = ContextUtils.getApplicationContext();
+ ContextUtils.initApplicationContextForTests(new TestContext(mContextToRestore));
}
private void loadUrlAndWaitForIntentUrl(
@@ -371,10 +436,10 @@
String fallbackUrl = mTestServer.getURL(FALLBACK_LANDING_PATH);
String originalUrl = mTestServer.getURL(NAVIGATION_WITH_FALLBACK_URL_PAGE + "?replace_text="
+ Base64.encodeToString(
- ApiCompatibilityUtils.getBytesUtf8("PARAM_FALLBACK_URL"), Base64.URL_SAFE)
+ ApiCompatibilityUtils.getBytesUtf8("PARAM_FALLBACK_URL"), Base64.URL_SAFE)
+ ":"
+ Base64.encodeToString(
- ApiCompatibilityUtils.getBytesUtf8(fallbackUrl), Base64.URL_SAFE));
+ ApiCompatibilityUtils.getBytesUtf8(fallbackUrl), Base64.URL_SAFE));
loadUrlAndWaitForIntentUrl(originalUrl, true, false, false, fallbackUrl, true);
}
@@ -393,13 +458,10 @@
byte[] base64FallbackUrl =
Base64.encode(ApiCompatibilityUtils.getBytesUtf8(fallbackUrl), Base64.URL_SAFE);
- String originalUrl = mTestServer.getURL(
- NAVIGATION_WITH_FALLBACK_URL_PARENT_FRAME_PAGE
- + "?replace_text="
- + Base64.encodeToString(paramBase64Name, Base64.URL_SAFE) + ":"
+ String originalUrl = mTestServer.getURL(NAVIGATION_WITH_FALLBACK_URL_PARENT_FRAME_PAGE
+ + "?replace_text=" + Base64.encodeToString(paramBase64Name, Base64.URL_SAFE) + ":"
+ Base64.encodeToString(base64ParamFallbackUrl, Base64.URL_SAFE)
- + "&replace_text="
- + Base64.encodeToString(paramBase64Value, Base64.URL_SAFE) + ":"
+ + "&replace_text=" + Base64.encodeToString(paramBase64Value, Base64.URL_SAFE) + ":"
+ Base64.encodeToString(base64FallbackUrl, Base64.URL_SAFE));
// Fallback URL from a subframe will not trigger main or sub frame navigation.
@@ -557,4 +619,65 @@
loadUrlAndWaitForIntentUrl(
mTestServer.getURL(SUBFRAME_REDIRECT_WITH_PLAY_FALLBACK), false, false);
}
+
+ private void runRedirectToOtherBrowserTest(Instrumentation.ActivityResult chooserResult) {
+ Context context = ContextUtils.getApplicationContext();
+ Intent intent = new Intent(
+ Intent.ACTION_VIEW, Uri.parse(mTestServer.getURL(REDIRECT_TO_OTHER_BROWSER)));
+ intent.setClassName(context, ChromeLauncherActivity.class.getName());
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PICK_ACTIVITY);
+ Instrumentation.ActivityMonitor monitor =
+ InstrumentationRegistry.getInstrumentation().addMonitor(
+ filter, chooserResult, true);
+
+ ChromeTabbedActivity activity = ApplicationTestUtils.waitForActivityWithClass(
+ ChromeTabbedActivity.class, Stage.CREATED, () -> context.startActivity(intent));
+ mActivityTestRule.setActivity(activity);
+
+ CriteriaHelper.pollUiThread(() -> {
+ Criteria.checkThat(monitor.getHits(), Matchers.is(1));
+ }, 10000L, CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+ InstrumentationRegistry.getInstrumentation().removeMonitor(monitor);
+ }
+
+ @Test
+ @LargeTest
+ public void testRedirectToOtherBrowser_ChooseSelf() throws TimeoutException {
+ setUpTestContext();
+ Intent result = new Intent(Intent.ACTION_CREATE_SHORTCUT);
+
+ runRedirectToOtherBrowserTest(
+ new Instrumentation.ActivityResult(Activity.RESULT_OK, result));
+
+ // Wait for the target (data) URL to load in the tab.
+ CriteriaHelper.pollUiThread(() -> {
+ Criteria.checkThat(
+ mActivityTestRule.getActivity().getActivityTab().getUrl().getScheme(),
+ Matchers.is(UrlConstants.DATA_SCHEME));
+ });
+ }
+
+ @Test
+ @LargeTest
+ public void testRedirectToOtherBrowser_ChooseOther() throws TimeoutException {
+ setUpTestContext();
+ IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
+ filter.addDataScheme(UrlConstants.DATA_SCHEME);
+ filter.addCategory(Intent.CATEGORY_BROWSABLE);
+ Instrumentation.ActivityMonitor monitor =
+ InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, true);
+
+ Intent result = new Intent(Intent.ACTION_VIEW);
+ result.setComponent(new ComponentName(OTHER_BROWSER_PACKAGE, "activity"));
+
+ runRedirectToOtherBrowserTest(
+ new Instrumentation.ActivityResult(Activity.RESULT_OK, result));
+
+ CriteriaHelper.pollUiThread(
+ () -> { Criteria.checkThat(monitor.getHits(), Matchers.is(1)); });
+
+ InstrumentationRegistry.getInstrumentation().removeMonitor(monitor);
+ }
}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java
index cbfccca..8164f35 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ChromeActionModeHandlerUnitTest.java
@@ -149,8 +149,7 @@
}
// Mock intent for querying web browsers.
- packageManager.addResolveInfoForIntent(
- PackageManagerUtils.getQueryInstalledBrowsersIntent(), browsersList);
+ packageManager.addResolveInfoForIntent(PackageManagerUtils.BROWSER_INTENT, browsersList);
// Mock intent for querying home launchers.
packageManager.addResolveInfoForIntent(
diff --git a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java
index cfbb6b27..073db5e 100644
--- a/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java
+++ b/chrome/browser/ui/android/default_browser_promo/java/src/org/chromium/chrome/browser/ui/default_browser_promo/DefaultBrowserPromoUtilsTest.java
@@ -81,14 +81,12 @@
DefaultBrowserPromoDeps deps = DefaultBrowserPromoDeps.getInstance();
infoList.add(createResolveInfo(DefaultBrowserPromoDeps.CHROME_STABLE_PACKAGE_NAME, 1));
- packageManager.addResolveInfoForIntent(
- PackageManagerUtils.getQueryInstalledBrowsersIntent(), infoList);
+ packageManager.addResolveInfoForIntent(PackageManagerUtils.BROWSER_INTENT, infoList);
Assert.assertFalse("Chrome stable should not be counted as a pre-stable channel",
deps.isChromePreStableInstalled());
infoList.add(createResolveInfo("com.android.chrome.123", 1));
- packageManager.addResolveInfoForIntent(
- PackageManagerUtils.getQueryInstalledBrowsersIntent(), infoList);
+ packageManager.addResolveInfoForIntent(PackageManagerUtils.BROWSER_INTENT, infoList);
Assert.assertFalse("A random package should not be counted as a pre-stable channel",
deps.isChromePreStableInstalled());
@@ -96,8 +94,7 @@
if (name.equals(DefaultBrowserPromoDeps.CHROME_STABLE_PACKAGE_NAME)) continue;
List<ResolveInfo> list = new ArrayList<>(infoList);
list.add(createResolveInfo(name, 1));
- packageManager.addResolveInfoForIntent(
- PackageManagerUtils.getQueryInstalledBrowsersIntent(), list);
+ packageManager.addResolveInfoForIntent(PackageManagerUtils.BROWSER_INTENT, list);
Assert.assertTrue(name + " should be considered as a pre-stable channel",
deps.isChromePreStableInstalled());
}
diff --git a/chrome/test/data/android/url_overriding/redirect_to_other_browser.html b/chrome/test/data/android/url_overriding/redirect_to_other_browser.html
new file mode 100644
index 0000000..b99eefd
--- /dev/null
+++ b/chrome/test/data/android/url_overriding/redirect_to_other_browser.html
@@ -0,0 +1,9 @@
+<html>
+ <head>
+ <meta http-equiv="refresh" content="0;URL='intent:text/plain;base64,SGVsbG8sIHdvcmxk#Intent;action=android.intent.action.VIEW;scheme=data;package=com.other.browser;end'" />
+ <script></script>
+ </head>
+ <body>
+ Redirecting...
+ </body>
+</html>
diff --git a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
index f4ae1b7..df6e442 100644
--- a/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
+++ b/components/external_intents/android/java/src/org/chromium/components/external_intents/ExternalNavigationHandler.java
@@ -13,10 +13,14 @@
import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
import android.net.Uri;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -60,14 +64,17 @@
import org.chromium.network.mojom.ReferrerPolicy;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.PermissionCallback;
+import org.chromium.ui.base.WindowAndroid;
import org.chromium.url.GURL;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
/**
* Logic related to the URL overriding/intercepting functionality.
@@ -680,8 +687,8 @@
// wtai://wp/mc;number
// number=string(phone-number)
String phoneNumber = params.getUrl().getSpec().substring(WTAI_MC_URL_PREFIX.length());
- startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(WebView.SCHEME_TEL + phoneNumber)),
- false, mDelegate);
+ startActivity(
+ new Intent(Intent.ACTION_VIEW, Uri.parse(WebView.SCHEME_TEL + phoneNumber)), false);
if (DEBUG) Log.i(TAG, "wtai:// link handled");
RecordUserAction.record("Android.PhoneIntent");
return true;
@@ -873,6 +880,74 @@
}
/**
+ * Returns true if an intent is an ACTION_VIEW intent targeting browsers or browser-like apps
+ * (excluding the embedding app).
+ */
+ private boolean isViewIntentToOtherBrowser(Intent targetIntent, List<ResolveInfo> resolveInfos,
+ boolean isIntentWithSupportedProtocol, boolean hasSpecializedHandler) {
+ // Note that up until at least Android S, an empty action will match any intent filter
+ // with with an action specified. If an intent selector is specified, then don't trust the
+ // action on the intent.
+ if (!TextUtils.isEmpty(targetIntent.getAction())
+ && !targetIntent.getAction().equals(Intent.ACTION_VIEW)
+ && targetIntent.getSelector() == null) {
+ return false;
+ }
+
+ if (targetIntent.getPackage() != null
+ && targetIntent.getPackage().equals(
+ ContextUtils.getApplicationContext().getPackageName())) {
+ return false;
+ }
+
+ String selfPackageName = mDelegate.getContext().getPackageName();
+ boolean matchesOtherPackage = false;
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ ActivityInfo info = resolveInfo.activityInfo;
+ if (info == null || !selfPackageName.equals(info.packageName)) {
+ matchesOtherPackage = true;
+ break;
+ }
+ }
+ if (!matchesOtherPackage) return false;
+
+ // Shortcut the queryIntentActivities if the scheme is a browser-supported scheme.
+ if (isIntentWithSupportedProtocol && !hasSpecializedHandler) return true;
+
+ // Fall back to querying for browser packages if the intent doesn't obviously match or not
+ // match a browser. This will catch custom URL schemes like googlechrome://.
+ Set<String> browserPackages = getInstalledBrowserPackages();
+
+ if (hasSpecializedHandler) {
+ List<String> specializedPackages = getSpecializedHandlers(resolveInfos);
+ for (String packageName : specializedPackages) {
+ // A non-browser package is specialized, so don't consider it to be targeting a
+ // browser.
+ if (!browserPackages.contains(packageName)) return false;
+ }
+ }
+
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ ActivityInfo info = resolveInfo.activityInfo;
+ if (info != null && browserPackages.contains(info.packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static Set<String> getInstalledBrowserPackages() {
+ List<ResolveInfo> browsers = PackageManagerUtils.queryAllWebBrowsersInfo();
+
+ Set<String> packageNames = new HashSet<>();
+ for (ResolveInfo browser : browsers) {
+ if (browser.activityInfo == null) continue;
+ packageNames.add(browser.activityInfo.packageName);
+ }
+ return packageNames;
+ }
+
+ /**
* Current URL has at least one specialized handler available. For navigations
* within the same host, keep the navigation inside the browser unless the set of
* available apps to handle the new navigation is different. http://crbug.com/463138
@@ -1049,7 +1124,7 @@
boolean closeTab = params.shouldCloseContentsOnOverrideUrlLoadingAndLaunchIntent();
if (shouldLaunch) {
try {
- startActivity(intent, proxy, mDelegate);
+ startActivity(intent, proxy);
if (mDelegate.canCloseTabOnIncognitoIntentLaunch() && closeTab) {
mDelegate.closeTab();
}
@@ -1116,22 +1191,6 @@
return false;
}
- private boolean launchExternalIntent(Intent targetIntent, boolean shouldProxyForInstantApps) {
- try {
- if (!startActivityIfNeeded(targetIntent, shouldProxyForInstantApps)) {
- if (DEBUG) Log.i(TAG, "The current Activity was the only targeted Activity.");
- return false;
- }
- } catch (ActivityNotFoundException e) {
- // The targeted app must have been uninstalled/disabled since we queried for Activities
- // to handle this intent.
- if (DEBUG) Log.i(TAG, "Activity not found.");
- return false;
- }
- if (DEBUG) Log.i(TAG, "startActivityIfNeeded");
- return true;
- }
-
// This will handle external navigations only for intent meant for Autofill Assistant.
private boolean handleWithAutofillAssistant(
ExternalNavigationParams params, Intent targetIntent, GURL browserFallbackUrl) {
@@ -1203,7 +1262,12 @@
return OverrideUrlLoadingResult.forNoOverride();
}
+ GURL intentDataUrl = new GURL(targetIntent.getDataString());
boolean isExternalProtocol = !UrlUtilities.isAcceptedScheme(params.getUrl());
+ // intent: URLs are considered an external protocol, but may still contain a Data URI that
+ // this app does support, and may still end up launching this app.
+ boolean isIntentWithSupportedProtocol = UrlUtilities.hasIntentScheme(params.getUrl())
+ && UrlUtilities.isAcceptedScheme(intentDataUrl);
if (isInternalPdfDownload(isExternalProtocol, params)) {
return OverrideUrlLoadingResult.forNoOverride();
@@ -1291,8 +1355,8 @@
return fallBackToHandlingInApp();
}
- // From this point on we should only have intents that this app can't handle, or intents for
- // apps with specialized handlers.
+ // From this point on we should only have URLs from intent URIs, or URLs for
+ // apps with specialized handlers (including custom schemes).
if (shouldStayWithinHost(
params, isLink, isFormSubmit, resolvingInfos.get(), isExternalProtocol)) {
@@ -1313,7 +1377,7 @@
assert intentResolutionMatches(debugIntent, targetIntent);
if (params.isIncognito()) {
- return handleIncognitoIntent(params, targetIntent, resolvingInfos.get(),
+ return handleIncognitoIntent(params, targetIntent, intentDataUrl, resolvingInfos.get(),
browserFallbackUrl, shouldProxyForInstantApps);
}
@@ -1327,24 +1391,29 @@
} else if (launchWebApkIfSoleIntentHandler(resolvingInfos.get(), targetIntent)) {
return OverrideUrlLoadingResult.forExternalIntent();
}
- if (launchExternalIntent(targetIntent, shouldProxyForInstantApps)) {
- return OverrideUrlLoadingResult.forExternalIntent();
+
+ boolean requiresIntentChooser = false;
+ if (isViewIntentToOtherBrowser(targetIntent, resolvingInfos.get(),
+ isIntentWithSupportedProtocol, hasSpecializedHandler)) {
+ RecordHistogram.recordBooleanHistogram("Android.Intent.WebIntentToOtherBrowser", true);
+ requiresIntentChooser = true;
}
- return OverrideUrlLoadingResult.forNoOverride();
+
+ return startActivityIfNeeded(targetIntent, shouldProxyForInstantApps, resolvingInfos.get(),
+ requiresIntentChooser, browserFallbackUrl, intentDataUrl, params.getReferrerUrl());
}
private OverrideUrlLoadingResult handleIncognitoIntent(ExternalNavigationParams params,
- Intent targetIntent, List<ResolveInfo> resolvingInfos, GURL browserFallbackUrl,
- boolean shouldProxyForInstantApps) {
+ Intent targetIntent, GURL intentDataUrl, List<ResolveInfo> resolvingInfos,
+ GURL browserFallbackUrl, boolean shouldProxyForInstantApps) {
boolean intentTargetedToApp = mDelegate.willAppHandleIntent(targetIntent);
GURL fallbackUrl = browserFallbackUrl;
// If we can handle the intent, then fall back to handling the target URL instead of
// the fallbackUrl if the user decides not to leave incognito.
if (resolveInfoContainsSelf(resolvingInfos)) {
- GURL targetUrl = UrlUtilities.hasIntentScheme(params.getUrl())
- ? new GURL(targetIntent.getDataString())
- : params.getUrl();
+ GURL targetUrl =
+ UrlUtilities.hasIntentScheme(params.getUrl()) ? intentDataUrl : params.getUrl();
// Make sure the browser can handle this URL, in case the Intent targeted a
// non-browser component for this app.
if (UrlUtilities.isAcceptedScheme(targetUrl)) fallbackUrl = targetUrl;
@@ -1413,7 +1482,7 @@
return OverrideUrlLoadingResult.forAsyncAction(
OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH);
} else {
- startActivity(intent, false, mDelegate);
+ startActivity(intent, false);
if (DEBUG) Log.i(TAG, "Intent to Play Store.");
return OverrideUrlLoadingResult.forExternalIntent();
}
@@ -1483,7 +1552,7 @@
Intent webApkIntent = new Intent(targetIntent);
webApkIntent.setPackage(packageName);
try {
- startActivity(webApkIntent, false, mDelegate);
+ startActivity(webApkIntent, false);
if (DEBUG) Log.i(TAG, "Launched WebAPK");
return true;
} catch (ActivityNotFoundException e) {
@@ -1616,16 +1685,15 @@
* @param proxy Whether we need to proxy the intent through AuthenticatedProxyActivity (this is
* used by Instant Apps intents).
*/
- public static void startActivity(
- Intent intent, boolean proxy, ExternalNavigationDelegate delegate) {
+ private void startActivity(Intent intent, boolean proxy) {
try {
forcePdfViewerAsIntentHandlerIfNeeded(intent);
if (proxy) {
- delegate.dispatchAuthenticatedIntent(intent);
+ mDelegate.dispatchAuthenticatedIntent(intent);
} else {
// Start the activity via the current activity if possible, and otherwise as a new
// task from the application context.
- Context context = ContextUtils.activityFromContext(delegate.getContext());
+ Context context = ContextUtils.activityFromContext(mDelegate.getContext());
if (context == null) {
context = ContextUtils.getApplicationContext();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -1634,10 +1702,10 @@
}
recordExternalNavigationDispatched(intent);
} catch (RuntimeException e) {
- IntentUtils.logTransactionTooLargeOrRethrow(e, intent);
+ Log.e(TAG, "Could not start Activity for intent " + intent.toString(), e);
}
- delegate.didStartActivity(intent);
+ mDelegate.didStartActivity(intent);
}
/**
@@ -1646,69 +1714,191 @@
* @param intent The intent we want to send.
* @param proxy Whether we need to proxy the intent through AuthenticatedProxyActivity (this is
* used by Instant Apps intents).
- * @returns whether an activity was started for the intent.
+ * @param resolvingInfos The resolvingInfos |intent| matches against.
+ * @param requiresIntentChooser Whether, for security reasons, the Intent Chooser is required to
+ * be shown.
+ * @param browserFallbackUrl The fallback URL if the user chooses not to leave this app.
+ * @param intentDataUrl The URL |intent| is targeting.
+ * @param referrerUrl The referrer for the navigation.
+ * @returns The OverrideUrlLoadingResult for starting (or not starting) the Activity.
*/
- private boolean startActivityIfNeeded(Intent intent, boolean proxy) {
- @ExternalNavigationDelegate.StartActivityIfNeededResult
- int delegateResult = mDelegate.maybeHandleStartActivityIfNeeded(intent, proxy);
+ private OverrideUrlLoadingResult startActivityIfNeeded(Intent intent, boolean proxy,
+ List<ResolveInfo> resolvingInfos, boolean requiresIntentChooser,
+ GURL browserFallbackUrl, GURL intentDataUrl, GURL referrerUrl) {
+ // Only touches disk on Kitkat. See http://crbug.com/617725 for more context.
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+ try {
+ boolean withoutPackage = TextUtils.isEmpty(intent.getPackage());
- switch (delegateResult) {
- case ExternalNavigationDelegate.StartActivityIfNeededResult.HANDLED_WITH_ACTIVITY_START:
- return true;
- case ExternalNavigationDelegate.StartActivityIfNeededResult
- .HANDLED_WITHOUT_ACTIVITY_START:
- return false;
- case ExternalNavigationDelegate.StartActivityIfNeededResult.DID_NOT_HANDLE:
- return startActivityIfNeededInternal(intent, proxy);
+ // TODO(https://crbug.com/1251722): Rename this delegate function and require
+ // the delegate to defer to the code below to actually launch the Activity.
+ @ExternalNavigationDelegate.StartActivityIfNeededResult
+ int delegateResult = mDelegate.maybeHandleStartActivityIfNeeded(intent, proxy);
+
+ if (withoutPackage
+ && (!TextUtils.isEmpty(intent.getPackage()) || intent.getComponent() != null)) {
+ // Embedder chose a package for this Intent, we no longer need to use the chooser.
+ requiresIntentChooser = false;
+ }
+ switch (delegateResult) {
+ case ExternalNavigationDelegate.StartActivityIfNeededResult
+ .HANDLED_WITH_ACTIVITY_START:
+ return OverrideUrlLoadingResult.forExternalIntent();
+ case ExternalNavigationDelegate.StartActivityIfNeededResult
+ .HANDLED_WITHOUT_ACTIVITY_START:
+ return OverrideUrlLoadingResult.forNoOverride();
+ case ExternalNavigationDelegate.StartActivityIfNeededResult.DID_NOT_HANDLE:
+ return startActivityIfNeededInternal(intent, proxy, resolvingInfos,
+ requiresIntentChooser, browserFallbackUrl, intentDataUrl, referrerUrl);
+ default:
+ assert false;
+ }
+ } catch (SecurityException e) {
+ // https://crbug.com/808494: Handle the URL internally if dispatching to another
+ // application fails with a SecurityException. This happens due to malformed
+ // manifests in another app.
+ } catch (ActivityNotFoundException e) {
+ // The targeted app must have been uninstalled/disabled since we queried for Activities
+ // to handle this intent.
+ if (DEBUG) Log.i(TAG, "Activity not found.");
+ } catch (AndroidRuntimeException e) {
+ // https://crbug.com/1226177: Most likely cause of this exception is Android failing
+ // to start the app that we previously detected could handle the Intent.
+ Log.e(TAG, "Could not start Activity for intent " + intent.toString(), e);
+ } catch (RuntimeException e) {
+ IntentUtils.logTransactionTooLargeOrRethrow(e, intent);
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
}
-
- assert false;
- return false;
+ return OverrideUrlLoadingResult.forNoOverride();
}
/**
* Implementation of startActivityIfNeeded() that is used when the delegate does not handle the
* event.
*/
- private boolean startActivityIfNeededInternal(Intent intent, boolean proxy) {
- boolean activityWasLaunched;
- // Only touches disk on Kitkat. See http://crbug.com/617725 for more context.
- StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
- try {
- forcePdfViewerAsIntentHandlerIfNeeded(intent);
- if (proxy) {
- mDelegate.dispatchAuthenticatedIntent(intent);
- activityWasLaunched = true;
- } else {
- Activity activity = ContextUtils.activityFromContext(mDelegate.getContext());
- if (activity != null) {
- activityWasLaunched = activity.startActivityIfNeeded(intent, -1);
- } else {
- activityWasLaunched = false;
- }
+ private OverrideUrlLoadingResult startActivityIfNeededInternal(Intent intent, boolean proxy,
+ List<ResolveInfo> resolvingInfos, boolean requiresIntentChooser,
+ GURL browserFallbackUrl, GURL intentDataUrl, GURL referrerUrl) {
+ forcePdfViewerAsIntentHandlerIfNeeded(intent);
+ if (proxy) {
+ mDelegate.dispatchAuthenticatedIntent(intent);
+ recordExternalNavigationDispatched(intent);
+ return OverrideUrlLoadingResult.forExternalIntent();
+ } else {
+ Activity activity = ContextUtils.activityFromContext(mDelegate.getContext());
+ if (activity == null) return OverrideUrlLoadingResult.forNoOverride();
+
+ if (requiresIntentChooser) {
+ return startActivityWithChooser(intent, resolvingInfos, browserFallbackUrl,
+ intentDataUrl, referrerUrl, activity);
}
- if (activityWasLaunched) {
- recordExternalNavigationDispatched(intent);
- }
- return activityWasLaunched;
- } catch (SecurityException e) {
- // https://crbug.com/808494: Handle the URL internally if dispatching to another
- // application fails with a SecurityException. This happens due to malformed manifests
- // in another app.
- return false;
- } catch (AndroidRuntimeException e) {
- // https://crbug.com/1226177: Most likely cause of this exception is Android failing to
- // start the app that we previously detected could handle the Intent.
- Log.e(TAG, "Could not start Activity for intent " + intent.toString(), e);
- return false;
- } catch (RuntimeException e) {
- IntentUtils.logTransactionTooLargeOrRethrow(e, intent);
- return false;
- } finally {
- StrictMode.setThreadPolicy(oldPolicy);
+ return doStartActivityIfNeeded(intent, activity);
}
}
+ private OverrideUrlLoadingResult doStartActivityIfNeeded(Intent intent, Activity activity) {
+ if (activity.startActivityIfNeeded(intent, -1)) {
+ if (DEBUG) Log.i(TAG, "startActivityIfNeeded");
+ mDelegate.didStartActivity(intent);
+ recordExternalNavigationDispatched(intent);
+ return OverrideUrlLoadingResult.forExternalIntent();
+ } else {
+ if (DEBUG) Log.i(TAG, "The current Activity was the only targeted Activity.");
+ return OverrideUrlLoadingResult.forNoOverride();
+ }
+ }
+
+ @SuppressWarnings("UseCompatLoadingForDrawables")
+ private OverrideUrlLoadingResult startActivityWithChooser(final Intent intent,
+ List<ResolveInfo> resolvingInfos, GURL browserFallbackUrl, GURL intentDataUrl,
+ GURL referrerUrl, Activity activity) {
+ ResolveInfo intentResolveInfo =
+ PackageManagerUtils.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ // If this is null, then the intent was only previously matching
+ // non-default filters, so just drop it.
+ if (intentResolveInfo == null) return OverrideUrlLoadingResult.forNoOverride();
+
+ // If the |resolvingInfos| from queryIntentActivities don't contain the result of
+ // resolveActivity, it means the intent is resolving to the ResolverActivity, so the user
+ // will already get the option to choose the target app (as there will be multiple options)
+ // and we don't need to do anything. Otherwise we have to make a fake option in the chooser
+ // dialog that loads the URL in the embedding app.
+ if (!resolversSubsetOf(Arrays.asList(intentResolveInfo), resolvingInfos)) {
+ return doStartActivityIfNeeded(intent, activity);
+ }
+
+ Intent pickerIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickerIntent.putExtra(Intent.EXTRA_INTENT, intent);
+
+ // Add the fake entry for the embedding app. This behavior is not well documented but works
+ // consistently across Android since L (and at least up to S).
+ PackageManager pm = activity.getPackageManager();
+ ArrayList<ShortcutIconResource> icons = new ArrayList<>();
+ ArrayList<String> labels = new ArrayList<>();
+ String packageName = activity.getPackageName();
+ String label = "";
+ ShortcutIconResource resource = new ShortcutIconResource();
+ try {
+ ApplicationInfo applicationInfo =
+ pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
+ label = (String) pm.getApplicationLabel(applicationInfo);
+ Resources resources = pm.getResourcesForApplication(applicationInfo);
+ resource.packageName = packageName;
+ resource.resourceName = resources.getResourceName(applicationInfo.icon);
+ // This will throw a Resources.NotFoundException if the package uses resource
+ // name collapsing/stripping. The ActivityPicker fails to handle this exception, we have
+ // have to check for it here to avoid crashes.
+ resources.getDrawable(resources.getIdentifier(resource.resourceName, null, null), null);
+ } catch (NameNotFoundException | Resources.NotFoundException e) {
+ Log.w(TAG, "No icon resource found for package: " + packageName);
+ // Most likely the app doesn't have an icon and is just a test
+ // app. Android will just use a blank icon.
+ resource.packageName = "";
+ resource.resourceName = "";
+ }
+ labels.add(label);
+ icons.add(resource);
+ pickerIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, labels);
+ pickerIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icons);
+
+ // Call startActivityForResult on the PICK_ACTIVITY intent, which will set the component of
+ // the data result to the component of the chosen app.
+ mDelegate.getWindowAndroid().showCancelableIntent(
+ pickerIntent, new WindowAndroid.IntentCallback() {
+ @Override
+ public void onIntentCompleted(int resultCode, Intent data) {
+ // If |data| is null, the user backed out of the intent chooser.
+ if (data == null) return;
+
+ // Quirk of how we use the ActivityChooser - if the embedding app is
+ // chosen we get an intent back with ACTION_CREATE_SHORTCUT.
+ if (data.getAction().equals(Intent.ACTION_CREATE_SHORTCUT)) {
+ // It's pretty arbitrary whether to prefer the data URL or the fallback
+ // URL here. We could consider preferring the fallback URL, as the URL
+ // was probably intending to leave Chrome, but loading the URL the site
+ // was trying to load in a browser seems like the better choice and
+ // matches what would have happened had the regular chooser dialog shown
+ // up and the user selected this app.
+ if (UrlUtilities.isAcceptedScheme(intentDataUrl)) {
+ clobberCurrentTab(intentDataUrl, referrerUrl);
+ } else if (!browserFallbackUrl.isEmpty()) {
+ clobberCurrentTab(browserFallbackUrl, referrerUrl);
+ }
+ return;
+ }
+
+ // Set the package for the original intent to the chosen app and start
+ // it. Note that a selector cannot be set at the same time as a package.
+ intent.setSelector(null);
+ intent.setPackage(data.getComponent().getPackageName());
+ startActivity(intent, false);
+ }
+ }, null);
+ return OverrideUrlLoadingResult.forAsyncAction(
+ OverrideUrlLoadingAsyncActionType.UI_GATING_INTENT_LAUNCH);
+ }
+
/**
* 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).
@@ -1787,7 +1977,7 @@
}
protected boolean resolveInfoContainsSelf(List<ResolveInfo> resolveInfos) {
- String packageName = ContextUtils.getApplicationContext().getPackageName();
+ String packageName = mDelegate.getContext().getPackageName();
for (ResolveInfo resolveInfo : resolveInfos) {
ActivityInfo info = resolveInfo.activityInfo;
if (info != null && packageName.equals(info.packageName)) {
diff --git a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
index 5af25a6..79d741b 100644
--- a/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
+++ b/components/external_intents/android/javatests/src/org/chromium/components/external_intents/ExternalNavigationHandlerTest.java
@@ -89,6 +89,7 @@
private static final boolean HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY = true;
private static final boolean INTENT_STARTED_TASK = true;
+ private static final String SELF_PACKAGE_NAME = "test.app.name";
private static final String INTENT_APP_PACKAGE_NAME = "com.imdb.mobile";
private static final String YOUTUBE_URL = "http://youtube.com/";
private static final String YOUTUBE_MOBILE_URL = "http://m.youtube.com";
@@ -123,14 +124,14 @@
"intent:///name/nm0000158#Intent;scheme=imdb;package=com.imdb.mobile;S."
+ ExternalNavigationHandler.EXTRA_MARKET_REFERRER + "=" + ENCODED_MARKET_REFERRER
+ ";end";
- private static final String INTENT_URL_FOR_CHROME_CUSTOM_TABS = "intent://example.com#Intent;"
- + "package=org.chromium.chrome;"
+ private static final String INTENT_URL_FOR_SELF_CUSTOM_TABS = "intent://example.com#Intent;"
+ + "package=" + SELF_PACKAGE_NAME + ";"
+ "action=android.intent.action.VIEW;"
+ "scheme=http;"
+ "S.android.support.customtabs.extra.SESSION=;"
+ "end;";
- private static final String INTENT_URL_FOR_CHROME = "intent://example.com#Intent;"
- + "package=org.chromium.chrome;"
+ private static final String INTENT_URL_FOR_SELF = "intent://example.com#Intent;"
+ + "package=" + SELF_PACKAGE_NAME + ";"
+ "action=android.intent.action.VIEW;"
+ "scheme=http;"
+ "S." + ExternalNavigationHandler.EXTRA_BROWSER_FALLBACK_URL + "="
@@ -196,6 +197,7 @@
mContext = new TestContext(InstrumentationRegistry.getTargetContext(), mDelegate);
ContextUtils.initApplicationContextForTests(mContext);
+ mDelegate.setContext(mContext);
NativeLibraryTestUtils.loadNativeLibraryNoBrowserProcess();
}
@@ -761,7 +763,7 @@
public void testCCTIntentUriDoesNotFireCCTAndLoadInChrome_InIncognito() throws Exception {
mUrlHandler.mResolveInfoContainsSelf = true;
mDelegate.setCanLoadUrlInTab(false);
- checkUrl(INTENT_URL_FOR_CHROME_CUSTOM_TABS)
+ checkUrl(INTENT_URL_FOR_SELF_CUSTOM_TABS)
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
Assert.assertNull(mDelegate.startActivityIntent);
@@ -771,7 +773,7 @@
@Test
@SmallTest
public void testCCTIntentUriFiresCCT_InRegular() throws Exception {
- checkUrl(INTENT_URL_FOR_CHROME_CUSTOM_TABS)
+ checkUrl(INTENT_URL_FOR_SELF_CUSTOM_TABS)
.withIsIncognito(false)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
START_OTHER_ACTIVITY);
@@ -783,14 +785,14 @@
public void testChromeIntentUriDoesNotFireAndLoadsInChrome_InIncognito() throws Exception {
mUrlHandler.mResolveInfoContainsSelf = true;
mDelegate.setCanLoadUrlInTab(false);
- checkUrl(INTENT_URL_FOR_CHROME)
+ checkUrl(INTENT_URL_FOR_SELF)
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
Assert.assertNull(mDelegate.startActivityIntent);
Assert.assertEquals("http://example.com/", mUrlHandler.mNewUrlAfterClobbering);
mUrlHandler.mResolveInfoContainsSelf = false;
- checkUrl(INTENT_URL_FOR_CHROME)
+ checkUrl(INTENT_URL_FOR_SELF)
.withIsIncognito(true)
.expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_CLOBBERING_TAB, IGNORE);
Assert.assertNull(mDelegate.startActivityIntent);
@@ -2276,6 +2278,23 @@
mUrlHandler.canExternalAppHandleUrl(new GURL(indexOutOfBoundsException)));
}
+ @Test
+ @SmallTest
+ public void testIntentToOtherBrowser() {
+ // This will create a non-specialized ResolveInfo for the target package.
+ mDelegate.setCanResolveActivityForExternalSchemes(true);
+
+ String intent = "intent://example.com#Intent;scheme=https;package=com.other.browser;end";
+
+ // This is a limitation of this testing harness, which doesn't get past
+ // startActivityIfNeeded as that requires an Activity context. This functionality is
+ // tested in ExternalNavigationDelegateImplTest.
+ checkUrl(intent)
+ .withPageTransition(PageTransition.LINK)
+ .expecting(OverrideUrlLoadingResultType.OVERRIDE_WITH_EXTERNAL_INTENT,
+ START_OTHER_ACTIVITY);
+ }
+
private static List<ResolveInfo> makeResolveInfos(ResolveInfo... infos) {
return Arrays.asList(infos);
}
@@ -2361,7 +2380,7 @@
@Override
protected AlertDialog showLeavingIncognitoAlert(Context context,
ExternalNavigationParams params, Intent intent, GURL fallbackUrl, boolean proxy) {
- if (context == null) return mAlertDialog;
+ if (context instanceof TestContext) return mAlertDialog;
mShownIncognitoAlertDialog =
super.showLeavingIncognitoAlert(context, params, intent, fallbackUrl, proxy);
return mShownIncognitoAlertDialog;
@@ -2447,6 +2466,11 @@
return list;
}
+ public ResolveInfo resolveActivity(Intent intent) {
+ List<ResolveInfo> list = queryIntentActivities(intent);
+ return list.size() > 0 ? list.get(0) : null;
+ }
+
@Override
public Context getContext() {
return mContext;
@@ -2883,6 +2907,11 @@
public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
return mDelegate.queryIntentActivities(intent);
}
+
+ @Override
+ public ResolveInfo resolveActivity(Intent intent, int flags) {
+ return mDelegate.resolveActivity(intent);
+ }
}
private static class TestContext extends ContextWrapper {
@@ -2905,7 +2934,7 @@
@Override
public String getPackageName() {
- return "test.app.name";
+ return SELF_PACKAGE_NAME;
}
@Override
@@ -2914,8 +2943,7 @@
}
@Override
- public void startActivity(Intent intent) {
- }
+ public void startActivity(Intent intent) {}
@Override
public void startActivity(Intent intent, Bundle options) {
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index c584249..b85d96e 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -1553,6 +1553,16 @@
</summary>
</histogram>
+<histogram name="Android.Intent.WebIntentToOtherBrowser" enum="Boolean"
+ expires_after="M98">
+ <owner>mthiesse@chromium.org</owner>
+ <owner>yfriedman@chromium.org</owner>
+ <summary>
+ When a site attempts to navigate to a supported URL with an intent URL that
+ targets other browser-like apps.
+ </summary>
+</histogram>
+
<histogram name="Android.IsLastSharedAppInfoRetrieved"
enum="BooleanIsLastSharedAppInfoRetrieved" expires_after="M77">
<owner>tedchoc@chromium.org</owner>
diff --git a/weblayer/browser/android/javatests/BUILD.gn b/weblayer/browser/android/javatests/BUILD.gn
index 81a33e7..82f31eea 100644
--- a/weblayer/browser/android/javatests/BUILD.gn
+++ b/weblayer/browser/android/javatests/BUILD.gn
@@ -57,6 +57,7 @@
"//net/android:net_java_test_support",
"//third_party/android_deps:android_support_v4_java",
"//third_party/android_deps:espresso_java",
+ "//third_party/android_sdk:android_support_chromium_java",
"//third_party/android_support_test_runner:rules_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/androidx:androidx_activity_activity_java",
diff --git a/weblayer/browser/android/javatests/skew/expectations.txt b/weblayer/browser/android/javatests/skew/expectations.txt
index ab44db6..ff80cfa 100644
--- a/weblayer/browser/android/javatests/skew/expectations.txt
+++ b/weblayer/browser/android/javatests/skew/expectations.txt
@@ -5,7 +5,7 @@
# with versions less than or equal to $VERSION of the implementation.
#
# These lines are not comments! They define the set of known tags and other information.
-# tags: [ client_lte_91 client_lte_94 ]
+# tags: [ client_lte_91 client_lte_94 impl_lte_94 ]
# 'all' disables the test from any skew test.
# tags: [ all ]
# results: [ Skip ]
@@ -35,6 +35,45 @@
crbug.com/1238481 [ client_lte_94 ] org.chromium.weblayer.test.TabTest#testRotationDoesntChangeVisibility [ Skip ]
crbug.com/1239028 [ client_lte_94 ] org.chromium.weblayer.test.MediaSessionTest#basic [ Skip ]
+# Chrome changes broke some test infrastructure, so tests are only artificially
+# broken - the behavior under test has not changed.
+crbug.com/1249962 [ client_lte_94] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentAfterRedirectInBackgroundTabLaunchedWhenBackgroundLaunchesAllowed [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentAfterRedirectLaunched [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentInNewTabLaunchedOnLinkClick [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentInSameTabLaunchedOnLinkClick [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentNavigationParamSetOnIntentLaunchViaLinkClick [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentNavigationParamSetOnNavigationsToIntents [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentViaOnLoadLaunched [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithFallbackUrlAfterRedirectLaunched [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBackgroundTabLaunchedWhenBackgroundLaunchesAllowed [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoBlockedWhenBackgroundLaunchesAllowedAndUserForbids [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoLaunchedWhenBackgroundLaunchesAllowedAndUserConsents [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoWithEmbedderPresentingWarningDialogBlockedWhenBackgroundLaunchesAllowedAndUserForbids [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoWithEmbedderPresentingWarningDialogLaunchedWhenBackgroundLaunchesAllowedAndUserConsents [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupLaunchedWhenBackgroundLaunchesAllowed [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectLaunched [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testUserClicksLinkToPageWithExternalIntentLaunchedViaOnLoad [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testUserDecidingExternalIntentNavigationParamSetOnNavigationsToIntentsInIncognito [ Skip ]
+crbug.com/1249962 [ client_lte_94 ] org.chromium.weblayer.test.NavigationTest#testIsKnownProtocol [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentAfterRedirectInBackgroundTabLaunchedWhenBackgroundLaunchesAllowed [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentAfterRedirectLaunched [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentInNewTabLaunchedOnLinkClick [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentInSameTabLaunchedOnLinkClick [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentNavigationParamSetOnIntentLaunchViaLinkClick [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentNavigationParamSetOnNavigationsToIntents [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentViaOnLoadLaunched [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithFallbackUrlAfterRedirectLaunched [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBackgroundTabLaunchedWhenBackgroundLaunchesAllowed [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoBlockedWhenBackgroundLaunchesAllowedAndUserForbids [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoLaunchedWhenBackgroundLaunchesAllowedAndUserConsents [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoWithEmbedderPresentingWarningDialogBlockedWhenBackgroundLaunchesAllowedAndUserForbids [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupInIncognitoWithEmbedderPresentingWarningDialogLaunchedWhenBackgroundLaunchesAllowedAndUserConsents [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectInBrowserStartupLaunchedWhenBackgroundLaunchesAllowed [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testExternalIntentWithNoRedirectLaunched [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testUserClicksLinkToPageWithExternalIntentLaunchedViaOnLoad [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.ExternalNavigationTest#testUserDecidingExternalIntentNavigationParamSetOnNavigationsToIntentsInIncognito [ Skip ]
+crbug.com/1249962 [ impl_lte_94 ] org.chromium.weblayer.test.NavigationTest#testIsKnownProtocol [ Skip ]
+
# Bulk disable to get bot green.
crbug.com/1191751 [ all ] org.chromium.weblayer.test.InputTypesTest* [ Skip ]
crbug.com/1191751 [ all ] org.chromium.weblayer.test.TabCallbackTest#testScrollNotificationDirectionChange [ Skip ]
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/ExternalNavigationTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/ExternalNavigationTest.java
index 8d9df69..0900568 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/ExternalNavigationTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/ExternalNavigationTest.java
@@ -12,11 +12,11 @@
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
-import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
@@ -49,17 +49,6 @@
public InstrumentationActivityTestRule mActivityTestRule =
new InstrumentationActivityTestRule();
- /**
- * A dummy activity that claims to handle "weblayer://weblayertest".
- */
- public static class DummyActivityForSpecialScheme extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- finish();
- }
- }
-
private static final boolean EXPECT_NAVIGATION_COMPLETION = true;
private static final boolean EXPECT_NAVIGATION_FAILURE = false;
private static final boolean RESULTS_IN_EXTERNAL_INTENT = true;
@@ -77,20 +66,21 @@
// The package is not specified in the intent that gets created when navigating to the special
// scheme.
private static final String INTENT_TO_DUMMY_ACTIVITY_FOR_SPECIAL_SCHEME_PACKAGE = null;
- private static final String INTENT_TO_CHROME_DATA_CONTENT =
+ private static final String INTENT_TO_SELF_DATA_CONTENT =
"play.google.com/store/apps/details?id=com.facebook.katana/";
- private static final String INTENT_TO_CHROME_SCHEME = "https";
- private static final String INTENT_TO_CHROME_DATA_STRING =
- INTENT_TO_CHROME_SCHEME + "://" + INTENT_TO_CHROME_DATA_CONTENT;
- private static final String INTENT_TO_CHROME_ACTION = "android.intent.action.VIEW";
- private static final String INTENT_TO_CHROME_PACKAGE = "com.android.chrome";
+ private static final String INTENT_TO_SELF_SCHEME = "https";
+ private static final String INTENT_TO_SELF_DATA_STRING =
+ INTENT_TO_SELF_SCHEME + "://" + INTENT_TO_SELF_DATA_CONTENT;
+ private static final String INTENT_TO_SELF_ACTION = "android.intent.action.VIEW";
+ private static final String INTENT_TO_SELF_PACKAGE =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName();
- // An intent that opens Chrome to view a specified URL. Note that the "end" is left off to allow
- // appending extras when constructing URLs.
- private static final String INTENT_TO_CHROME = "intent://" + INTENT_TO_CHROME_DATA_CONTENT
- + "#Intent;scheme=" + INTENT_TO_CHROME_SCHEME + ";action=" + INTENT_TO_CHROME_ACTION
- + ";package=" + INTENT_TO_CHROME_PACKAGE + ";";
- private static final String INTENT_TO_CHROME_URL = INTENT_TO_CHROME + "end";
+ // An intent that opens the test app to view a specified URL. Note that the "end" is left off to
+ // allow appending extras when constructing URLs.
+ private static final String INTENT_TO_SELF = "intent://" + INTENT_TO_SELF_DATA_CONTENT
+ + "#Intent;scheme=" + INTENT_TO_SELF_SCHEME + ";action=" + INTENT_TO_SELF_ACTION
+ + ";package=" + INTENT_TO_SELF_PACKAGE + ";";
+ private static final String INTENT_TO_SELF_URL = INTENT_TO_SELF + "end";
// An intent URL that gets rejected as malformed.
private static final String MALFORMED_INTENT_URL = "intent://garbage;end";
@@ -100,33 +90,33 @@
private static final String NON_RESOLVABLE_INTENT =
"intent://dummy.com/#Intent;scheme=https;action=android.intent.action.VIEW;package=com.missing.app;";
- private static final String LINK_WITH_INTENT_TO_CHROME_IN_SAME_TAB_FILE =
- "link_with_intent_to_chrome_in_same_tab.html";
- private static final String LINK_WITH_INTENT_TO_CHROME_IN_NEW_TAB_FILE =
- "link_with_intent_to_chrome_in_new_tab.html";
+ private static final String LINK_WITH_INTENT_TO_SELF_IN_SAME_TAB_FILE =
+ "link_with_intent_to_package_in_same_tab.html#" + INTENT_TO_SELF_PACKAGE;
+ private static final String LINK_WITH_INTENT_TO_SELF_IN_NEW_TAB_FILE =
+ "link_with_intent_to_package_in_new_tab.html#" + INTENT_TO_SELF_PACKAGE;
private static final String PAGE_THAT_INTENTS_TO_CHROME_ON_LOAD_FILE =
- "page_that_intents_to_chrome_on_load.html";
+ "page_that_intents_to_package_on_load.html#" + INTENT_TO_SELF_PACKAGE;
private static final String LINK_TO_PAGE_THAT_INTENTS_TO_CHROME_ON_LOAD_FILE =
- "link_to_page_that_intents_to_chrome_on_load.html";
+ "link_to_page_that_intents_to_package_on_load.html#" + INTENT_TO_SELF_PACKAGE;
// The test server handles "echo" with a response containing "Echo" :).
private final String mTestServerSiteUrl = mActivityTestRule.getTestServer().getURL("/echo");
private final String mTestServerSiteFallbackUrlExtra =
"S.browser_fallback_url=" + android.net.Uri.encode(mTestServerSiteUrl) + ";";
- private final String mIntentToChromeWithFallbackUrl =
- INTENT_TO_CHROME + mTestServerSiteFallbackUrlExtra + "end";
+ private final String mIntentToSelfWithFallbackUrl =
+ INTENT_TO_SELF + mTestServerSiteFallbackUrlExtra + "end";
private final String mNonResolvableIntentWithFallbackUrl =
NON_RESOLVABLE_INTENT + mTestServerSiteFallbackUrlExtra + "end";
private final String mRedirectToCustomSchemeUrlWithDefaultExternalHandler =
mActivityTestRule.getTestServer().getURL(
"/server-redirect?" + CUSTOM_SCHEME_URL_WITH_DEFAULT_EXTERNAL_HANDLER);
- private final String mRedirectToIntentToChromeURL =
- mActivityTestRule.getTestServer().getURL("/server-redirect?" + INTENT_TO_CHROME_URL);
+ private final String mRedirectToIntentToSelfURL =
+ mActivityTestRule.getTestServer().getURL("/server-redirect?" + INTENT_TO_SELF_URL);
private final String mNonResolvableIntentWithFallbackUrlThatLaunchesIntent =
NON_RESOLVABLE_INTENT + "S.browser_fallback_url="
- + android.net.Uri.encode(mRedirectToIntentToChromeURL) + ";end";
+ + android.net.Uri.encode(mRedirectToIntentToSelfURL) + ";end";
private class IntentInterceptor implements InstrumentationActivity.IntentInterceptor {
public Intent mLastIntent;
@@ -276,10 +266,10 @@
// Navigate directly to an intent in the background and verify that the intent is not
// launched.
- NavigationWaiter waiter = new NavigationWaiter(INTENT_TO_CHROME_URL, backgroundTab,
+ NavigationWaiter waiter = new NavigationWaiter(INTENT_TO_SELF_URL, backgroundTab,
/*expectFailure=*/true, /*waitForPaint=*/false);
TestThreadUtils.runOnUiThreadBlocking(() -> {
- backgroundTab.getNavigationController().navigate(Uri.parse(INTENT_TO_CHROME_URL));
+ backgroundTab.getNavigationController().navigate(Uri.parse(INTENT_TO_SELF_URL));
});
waiter.waitForNavigation();
@@ -321,7 +311,7 @@
NavigateParams.Builder navigateParamsBuilder = new NavigateParams.Builder();
navigateParamsBuilder.allowIntentLaunchesInBackground();
backgroundTab.getNavigationController().navigate(
- Uri.parse(INTENT_TO_CHROME_URL), navigateParamsBuilder.build());
+ Uri.parse(INTENT_TO_SELF_URL), navigateParamsBuilder.build());
});
intentInterceptor.waitForIntent();
@@ -330,9 +320,9 @@
// navigation in the background tab.
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
int numNavigationsInBackgroundTab = TestThreadUtils.runOnUiThreadBlocking(
() -> { return backgroundTab.getNavigationController().getNavigationListSize(); });
@@ -357,11 +347,10 @@
// Perform a navigation that redirects to an intent in the background and verify that the
// intent is not launched.
- NavigationWaiter waiter = new NavigationWaiter(INTENT_TO_CHROME_URL, backgroundTab,
+ NavigationWaiter waiter = new NavigationWaiter(INTENT_TO_SELF_URL, backgroundTab,
/*expectFailure=*/true, /*waitForPaint=*/false);
TestThreadUtils.runOnUiThreadBlocking(() -> {
- backgroundTab.getNavigationController().navigate(
- Uri.parse(mRedirectToIntentToChromeURL));
+ backgroundTab.getNavigationController().navigate(Uri.parse(mRedirectToIntentToSelfURL));
});
waiter.waitForNavigation();
@@ -403,7 +392,7 @@
NavigateParams.Builder navigateParamsBuilder = new NavigateParams.Builder();
navigateParamsBuilder.allowIntentLaunchesInBackground();
backgroundTab.getNavigationController().navigate(
- Uri.parse(mRedirectToIntentToChromeURL), navigateParamsBuilder.build());
+ Uri.parse(mRedirectToIntentToSelfURL), navigateParamsBuilder.build());
});
intentInterceptor.waitForIntent();
@@ -412,9 +401,9 @@
// navigation in the background tab.
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
int numNavigationsInBackgroundTab = TestThreadUtils.runOnUiThreadBlocking(
() -> { return backgroundTab.getNavigationController().getNavigationListSize(); });
@@ -434,7 +423,7 @@
NavigationCallback navigationCallback = new NavigationCallback() {
@Override
public void onNavigationFailed(Navigation navigation) {
- if (navigation.getUri().toString().equals(INTENT_TO_CHROME_URL)) {
+ if (navigation.getUri().toString().equals(INTENT_TO_SELF_URL)) {
onNavigationFailedCallbackHelper.notifyCalled();
}
}
@@ -451,7 +440,7 @@
browser.getActiveTab().getNavigationController().registerNavigationCallback(
navigationCallback);
browser.getActiveTab().getNavigationController().navigate(
- Uri.parse(INTENT_TO_CHROME_URL));
+ Uri.parse(INTENT_TO_SELF_URL));
}
});
@@ -508,7 +497,7 @@
NavigateParams.Builder navigateParamsBuilder = new NavigateParams.Builder();
navigateParamsBuilder.allowIntentLaunchesInBackground();
browser.getActiveTab().getNavigationController().navigate(
- Uri.parse(INTENT_TO_CHROME_URL), navigateParamsBuilder.build());
+ Uri.parse(INTENT_TO_SELF_URL), navigateParamsBuilder.build());
}
});
@@ -518,9 +507,9 @@
intentInterceptor.waitForIntent();
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
// ...the tab created for the initial navigation should be closed...
onTabRemovedCallbackHelper.waitForFirst();
@@ -548,7 +537,7 @@
NavigationCallback navigationCallback = new NavigationCallback() {
@Override
public void onNavigationFailed(Navigation navigation) {
- if (navigation.getUri().toString().equals(INTENT_TO_CHROME_URL)) {
+ if (navigation.getUri().toString().equals(INTENT_TO_SELF_URL)) {
onNavigationFailedCallbackHelper.notifyCalled();
}
}
@@ -564,7 +553,7 @@
browser.getActiveTab().getNavigationController().registerNavigationCallback(
navigationCallback);
browser.getActiveTab().getNavigationController().navigate(
- Uri.parse(INTENT_TO_CHROME_URL));
+ Uri.parse(INTENT_TO_SELF_URL));
}
});
@@ -626,7 +615,7 @@
NavigateParams.Builder navigateParamsBuilder = new NavigateParams.Builder();
navigateParamsBuilder.allowIntentLaunchesInBackground();
browser.getActiveTab().getNavigationController().navigate(
- Uri.parse(INTENT_TO_CHROME_URL), navigateParamsBuilder.build());
+ Uri.parse(INTENT_TO_SELF_URL), navigateParamsBuilder.build());
}
});
@@ -645,9 +634,9 @@
intentInterceptor.waitForIntent();
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
// ...the tab created for the initial navigation should be closed...
onTabRemovedCallbackHelper.waitForFirst();
@@ -680,11 +669,13 @@
@Override
public void onNavigationStarted(Navigation navigation) {
// There should be no additional navigations after the initial one.
- Assert.assertEquals(INTENT_TO_CHROME_URL, navigation.getUri().toString());
+ Assert.assertEquals(INTENT_TO_DUMMY_ACTIVITY_FOR_SPECIAL_SCHEME_DATA_STRING,
+ navigation.getUri().toString());
}
@Override
public void onNavigationFailed(Navigation navigation) {
- if (navigation.getUri().toString().equals(INTENT_TO_CHROME_URL)) {
+ if (navigation.getUri().toString().equals(
+ INTENT_TO_DUMMY_ACTIVITY_FOR_SPECIAL_SCHEME_DATA_STRING)) {
onNavigationToIntentFailedCallbackHelper.notifyCalled();
}
}
@@ -703,7 +694,8 @@
NavigateParams.Builder navigateParamsBuilder = new NavigateParams.Builder();
navigateParamsBuilder.allowIntentLaunchesInBackground();
browser.getActiveTab().getNavigationController().navigate(
- Uri.parse(INTENT_TO_CHROME_URL), navigateParamsBuilder.build());
+ Uri.parse(INTENT_TO_DUMMY_ACTIVITY_FOR_SPECIAL_SCHEME_DATA_STRING),
+ navigateParamsBuilder.build());
}
});
@@ -775,7 +767,7 @@
NavigateParams.Builder navigateParamsBuilder = new NavigateParams.Builder();
navigateParamsBuilder.allowIntentLaunchesInBackground();
browser.getActiveTab().getNavigationController().navigate(
- Uri.parse(INTENT_TO_CHROME_URL), navigateParamsBuilder.build());
+ Uri.parse(INTENT_TO_SELF_URL), navigateParamsBuilder.build());
}
});
@@ -798,9 +790,9 @@
intentInterceptor.waitForIntent();
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
// ...the tab created for the initial navigation should be closed...
onTabRemovedCallbackHelper.waitForFirst();
@@ -833,11 +825,13 @@
@Override
public void onNavigationStarted(Navigation navigation) {
// There should be no additional navigations after the initial one.
- Assert.assertEquals(INTENT_TO_CHROME_URL, navigation.getUri().toString());
+ Assert.assertEquals(INTENT_TO_DUMMY_ACTIVITY_FOR_SPECIAL_SCHEME_DATA_STRING,
+ navigation.getUri().toString());
}
@Override
public void onNavigationFailed(Navigation navigation) {
- if (navigation.getUri().toString().equals(INTENT_TO_CHROME_URL)) {
+ if (navigation.getUri().toString().equals(
+ INTENT_TO_DUMMY_ACTIVITY_FOR_SPECIAL_SCHEME_DATA_STRING)) {
onNavigationToIntentFailedCallbackHelper.notifyCalled();
}
}
@@ -860,7 +854,8 @@
NavigateParams.Builder navigateParamsBuilder = new NavigateParams.Builder();
navigateParamsBuilder.allowIntentLaunchesInBackground();
browser.getActiveTab().getNavigationController().navigate(
- Uri.parse(INTENT_TO_CHROME_URL), navigateParamsBuilder.build());
+ Uri.parse(INTENT_TO_DUMMY_ACTIVITY_FOR_SPECIAL_SCHEME_DATA_STRING),
+ navigateParamsBuilder.build());
}
});
@@ -913,7 +908,7 @@
Tab tab = mActivityTestRule.getActivity().getTab();
TestThreadUtils.runOnUiThreadBlocking(
- () -> { tab.getNavigationController().navigate(Uri.parse(INTENT_TO_CHROME_URL)); });
+ () -> { tab.getNavigationController().navigate(Uri.parse(INTENT_TO_SELF_URL)); });
intentInterceptor.waitForIntent();
@@ -921,9 +916,9 @@
Assert.assertEquals(ABOUT_BLANK_URL, mActivityTestRule.getCurrentDisplayUrl());
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
}
/**
@@ -957,12 +952,12 @@
IntentInterceptor intentInterceptor = new IntentInterceptor();
activity.setIntentInterceptor(intentInterceptor);
- navigateAndCheckExternalIntentParams(INTENT_TO_CHROME_URL, EXPECT_NAVIGATION_FAILURE,
+ navigateAndCheckExternalIntentParams(INTENT_TO_SELF_URL, EXPECT_NAVIGATION_FAILURE,
RESULTS_IN_EXTERNAL_INTENT, DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT);
- navigateAndCheckExternalIntentParams(mIntentToChromeWithFallbackUrl,
+ navigateAndCheckExternalIntentParams(mIntentToSelfWithFallbackUrl,
EXPECT_NAVIGATION_FAILURE, RESULTS_IN_EXTERNAL_INTENT,
DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT);
- navigateAndCheckExternalIntentParams(mRedirectToIntentToChromeURL, INTENT_TO_CHROME_URL,
+ navigateAndCheckExternalIntentParams(mRedirectToIntentToSelfURL, INTENT_TO_SELF_URL,
EXPECT_NAVIGATION_FAILURE, RESULTS_IN_EXTERNAL_INTENT,
DOESNT_RESULT_IN_USER_DECIDING_EXTERNAL_INTENT);
navigateAndCheckExternalIntentParams(mRedirectToCustomSchemeUrlWithDefaultExternalHandler,
@@ -994,7 +989,7 @@
extras.putBoolean(InstrumentationActivity.EXTRA_IS_INCOGNITO, true);
mActivityTestRule.launchShellWithUrl(ABOUT_BLANK_URL, extras);
- navigateAndCheckExternalIntentParams(INTENT_TO_CHROME_URL, EXPECT_NAVIGATION_FAILURE,
+ navigateAndCheckExternalIntentParams(INTENT_TO_SELF_URL, EXPECT_NAVIGATION_FAILURE,
DOESNT_RESULT_IN_EXTERNAL_INTENT, RESULTS_IN_USER_DECIDING_EXTERNAL_INTENT);
}
@@ -1017,7 +1012,7 @@
NavigationCallback navigationCallback = new NavigationCallback() {
@Override
public void onNavigationFailed(Navigation navigation) {
- Assert.assertEquals(INTENT_TO_CHROME_URL, navigation.getUri().toString());
+ Assert.assertEquals(INTENT_TO_SELF_URL, navigation.getUri().toString());
Assert.assertEquals(true, navigation.wasIntentLaunched());
Assert.assertEquals(false, navigation.isUserDecidingIntentLaunch());
@@ -1030,7 +1025,7 @@
// Navigate to a URL that has a link to an intent, click on the link, and verify via the
// callback that the navigation to the intent fails with the expected state set.
- String url = mActivityTestRule.getTestDataURL(LINK_WITH_INTENT_TO_CHROME_IN_SAME_TAB_FILE);
+ String url = mActivityTestRule.getTestDataURL(LINK_WITH_INTENT_TO_SELF_IN_SAME_TAB_FILE);
mActivityTestRule.navigateAndWait(url);
mActivityTestRule.executeScriptSync(
"document.onclick = function() {document.getElementById('link').click()}",
@@ -1059,7 +1054,7 @@
Tab tab = mActivityTestRule.getActivity().getTab();
TestThreadUtils.runOnUiThreadBlocking(() -> {
- tab.getNavigationController().navigate(Uri.parse(mRedirectToIntentToChromeURL));
+ tab.getNavigationController().navigate(Uri.parse(mRedirectToIntentToSelfURL));
});
intentInterceptor.waitForIntent();
@@ -1068,9 +1063,9 @@
Assert.assertEquals(ABOUT_BLANK_URL, mActivityTestRule.getCurrentDisplayUrl());
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
}
/**
@@ -1118,7 +1113,7 @@
IntentInterceptor intentInterceptor = new IntentInterceptor();
activity.setIntentInterceptor(intentInterceptor);
- String url = mActivityTestRule.getTestDataURL(LINK_WITH_INTENT_TO_CHROME_IN_SAME_TAB_FILE);
+ String url = mActivityTestRule.getTestDataURL(LINK_WITH_INTENT_TO_SELF_IN_SAME_TAB_FILE);
mActivityTestRule.navigateAndWait(url);
@@ -1134,9 +1129,9 @@
Assert.assertEquals(url, mActivityTestRule.getCurrentDisplayUrl());
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
}
/**
@@ -1153,7 +1148,7 @@
IntentInterceptor intentInterceptor = new IntentInterceptor();
activity.setIntentInterceptor(intentInterceptor);
- String url = mActivityTestRule.getTestDataURL(LINK_WITH_INTENT_TO_CHROME_IN_NEW_TAB_FILE);
+ String url = mActivityTestRule.getTestDataURL(LINK_WITH_INTENT_TO_SELF_IN_NEW_TAB_FILE);
mActivityTestRule.navigateAndWait(url);
@@ -1191,9 +1186,9 @@
intentInterceptor.waitForIntent();
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
// (3) And finally the new tab should be closed.
onTabRemovedCallbackHelper.waitForFirst();
@@ -1224,7 +1219,7 @@
activity.setIntentInterceptor(intentInterceptor);
String url = mActivityTestRule.getTestServer().getURL(
- "/server-redirect?" + mIntentToChromeWithFallbackUrl);
+ "/server-redirect?" + mIntentToSelfWithFallbackUrl);
Tab tab = mActivityTestRule.getActivity().getTab();
TestThreadUtils.runOnUiThreadBlocking(
@@ -1236,9 +1231,9 @@
Assert.assertEquals(ABOUT_BLANK_URL, mActivityTestRule.getCurrentDisplayUrl());
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
}
/**
@@ -1324,7 +1319,7 @@
() -> { tab.getNavigationController().navigate(Uri.parse(url)); });
NavigationWaiter waiter = new NavigationWaiter(
- INTENT_TO_CHROME_URL, tab, /*expectFailure=*/true, /*waitForPaint=*/false);
+ INTENT_TO_SELF_URL, tab, /*expectFailure=*/true, /*waitForPaint=*/false);
waiter.waitForNavigation();
Assert.assertNull(intentInterceptor.mLastIntent);
@@ -1365,9 +1360,9 @@
Assert.assertEquals(initialUrl, mActivityTestRule.getCurrentDisplayUrl());
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
}
/**
@@ -1416,9 +1411,9 @@
Assert.assertEquals(url, mActivityTestRule.getCurrentDisplayUrl());
Intent intent = intentInterceptor.mLastIntent;
Assert.assertNotNull(intent);
- Assert.assertEquals(INTENT_TO_CHROME_PACKAGE, intent.getPackage());
- Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
- Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
+ Assert.assertEquals(INTENT_TO_SELF_PACKAGE, intent.getPackage());
+ Assert.assertEquals(INTENT_TO_SELF_ACTION, intent.getAction());
+ Assert.assertEquals(INTENT_TO_SELF_DATA_STRING, intent.getDataString());
}
/**
@@ -1442,7 +1437,7 @@
});
NavigationWaiter waiter = new NavigationWaiter(
- INTENT_TO_CHROME_URL, tab, /*expectFailure=*/true, /*waitForPaint=*/false);
+ INTENT_TO_SELF_URL, tab, /*expectFailure=*/true, /*waitForPaint=*/false);
waiter.waitForNavigation();
Assert.assertNull(intentInterceptor.mLastIntent);
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
index 86317ab..8d01e771 100644
--- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
+++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/NavigationTest.java
@@ -84,9 +84,10 @@
// A URL with a custom scheme/host that is handled by WebLayer Shell.
private static final String CUSTOM_SCHEME_URL_WITH_DEFAULT_EXTERNAL_HANDLER =
"weblayer://weblayertest/intent";
- // An intent that opens Chrome to view a specified URL.
- private static final String INTENT_TO_CHROME_URL =
- "intent://play.google.com/store/apps/details?id=com.facebook.katana/#Intent;scheme=https;action=android.intent.action.VIEW;package=com.android.chrome;end";
+ // An intent that sends an url with a custom scheme that is handled by WebLayer Shell.
+ private static final String INTENT_TO_CUSTOM_SCHEME_URL =
+ "intent://weblayertest/intent#Intent;scheme=weblayer;"
+ + "action=android.intent.action.VIEW;end";
// An IntentInterceptor that simply drops intents to ensure that intent launches don't interfere
// with running of tests.
@@ -762,7 +763,7 @@
assertEquals(true, mCallback.onCompletedCallback.isKnownProtocol());
// Test external protocol cases.
- mActivityTestRule.navigateAndWaitForFailure(activity.getTab(), INTENT_TO_CHROME_URL,
+ mActivityTestRule.navigateAndWaitForFailure(activity.getTab(), INTENT_TO_CUSTOM_SCHEME_URL,
/*waitForPaint=*/false);
assertEquals(false, mCallback.onStartedCallback.isKnownProtocol());
assertEquals(false, mCallback.onFailedCallback.isKnownProtocol());
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java
index 6717c9d..967dab2 100644
--- a/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java
+++ b/weblayer/browser/java/org/chromium/weblayer_private/ExternalNavigationDelegateImpl.java
@@ -14,7 +14,6 @@
import org.chromium.base.Callback;
import org.chromium.base.Function;
import org.chromium.base.PackageManagerUtils;
-import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.components.external_intents.ExternalNavigationDelegate;
import org.chromium.components.external_intents.ExternalNavigationDelegate.StartActivityIfNeededResult;
import org.chromium.components.external_intents.ExternalNavigationParams;
@@ -78,17 +77,7 @@
assert !proxy
: "|proxy| should be true only for instant apps, which WebLayer doesn't handle";
- boolean isExternalProtocol = !UrlUtilities.isAcceptedScheme(intent.toUri(0));
- boolean hasDefaultHandler = hasDefaultHandler(intent);
-
- // Match CCT's custom behavior of keeping http(s) URLs with no default handler in the app.
- // TODO(blundell): If/when CCT eliminates its special handling of this case, eliminate it
- // from WebLayer as well.
- if (!isExternalProtocol && !hasDefaultHandler) {
- return StartActivityIfNeededResult.HANDLED_WITHOUT_ACTIVITY_START;
- }
-
- // Otherwise defer to ExternalNavigationHandler's default logic.
+ // Defer to ExternalNavigationHandler's default logic.
return StartActivityIfNeededResult.DID_NOT_HANDLE;
}
diff --git a/weblayer/shell/android/shell_apk/AndroidManifest.xml b/weblayer/shell/android/shell_apk/AndroidManifest.xml
index 5739c36..35457b3 100644
--- a/weblayer/shell/android/shell_apk/AndroidManifest.xml
+++ b/weblayer/shell/android/shell_apk/AndroidManifest.xml
@@ -48,14 +48,26 @@
android:theme="@android:style/Theme.Holo.Light.NoActionBar">
</activity>
<activity android:name="org.chromium.weblayer.test.ExternalNavigationTest$DummyActivityForSpecialScheme"
- android:exported="true" >
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:host="weblayertest" android:scheme="weblayer" />
- </intent-filter>
- </activity>
+ android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:host="weblayertest" android:scheme="weblayer" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="org.chromium.weblayer.test.ExternalNavigationTest$DummyActivity"
+ android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:scheme="about" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ </intent-filter>
+ </activity>
<!-- Enable ADB logging of js logs (console.log). This is disabled by default because some
websites log PII. -->
diff --git a/weblayer/test/data/link_to_page_that_intents_to_chrome_on_load.html b/weblayer/test/data/link_to_page_that_intents_to_chrome_on_load.html
deleted file mode 100644
index d5e024b..0000000
--- a/weblayer/test/data/link_to_page_that_intents_to_chrome_on_load.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <meta name="viewport"
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
-</head>
-<body>
- <a id='link' href='/weblayer/test/data/page_that_intents_to_chrome_on_load.html'>
- Click to go to page that intents to Chrome on load
-</a>
-</body>
-</html>
diff --git a/weblayer/test/data/link_to_page_that_intents_to_package_on_load.html b/weblayer/test/data/link_to_page_that_intents_to_package_on_load.html
new file mode 100644
index 0000000..e31ef486
--- /dev/null
+++ b/weblayer/test/data/link_to_page_that_intents_to_package_on_load.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta name="viewport"
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
+</head>
+<body>
+ <a id='link'>
+ <script type="text/javascript">
+ document.getElementById('link').href = '/weblayer/test/data/page_that_intents_to_package_on_load.html' + window.location.hash;
+ </script>
+ Click to go to page that intents to the package specified in the URL hash on load
+</a>
+</body>
+</html>
diff --git a/weblayer/test/data/link_with_intent_to_chrome_in_new_tab.html b/weblayer/test/data/link_with_intent_to_chrome_in_new_tab.html
deleted file mode 100644
index 44994a17..0000000
--- a/weblayer/test/data/link_with_intent_to_chrome_in_new_tab.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <meta name="viewport"
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
-</head>
-<body>
- <a id='link' target='_blank' href='intent://play.google.com/store/apps/details?id=com.facebook.katana/#Intent;scheme=https;action=android.intent.action.VIEW;package=com.android.chrome;end'>
- Click to intent to production Chrome in a new tab
-</a>
-</body>
-</html>
diff --git a/weblayer/test/data/link_with_intent_to_chrome_in_same_tab.html b/weblayer/test/data/link_with_intent_to_chrome_in_same_tab.html
deleted file mode 100644
index e442dc92..0000000
--- a/weblayer/test/data/link_with_intent_to_chrome_in_same_tab.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <meta name="viewport"
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
-</head>
-<body>
- <a id='link' href='intent://play.google.com/store/apps/details?id=com.facebook.katana/#Intent;scheme=https;action=android.intent.action.VIEW;package=com.android.chrome;end'>
- Click to intent to production Chrome in this tab
-</a>
-</body>
-</html>
diff --git a/weblayer/test/data/link_with_intent_to_package_in_new_tab.html b/weblayer/test/data/link_with_intent_to_package_in_new_tab.html
new file mode 100644
index 0000000..5fc9711
--- /dev/null
+++ b/weblayer/test/data/link_with_intent_to_package_in_new_tab.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta name="viewport"
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
+</head>
+<body>
+ <a id='link' target='_blank'>
+ Click to intent to the package specified in the URL hash in a new tab
+ </a>
+ <script type="text/javascript">
+ document.getElementById('link').href = 'intent://play.google.com/store/apps/details?id=com.facebook.katana/#Intent;scheme=https;action=android.intent.action.VIEW;package=' + window.location.href.split('#')[1] + ';end';
+ </script>
+</body>
+</html>
diff --git a/weblayer/test/data/link_with_intent_to_package_in_same_tab.html b/weblayer/test/data/link_with_intent_to_package_in_same_tab.html
new file mode 100644
index 0000000..0a9a240
--- /dev/null
+++ b/weblayer/test/data/link_with_intent_to_package_in_same_tab.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta name="viewport"
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
+</head>
+<body>
+ <a id='link'>
+ Click to intent to the package specified in the URL hash in this tab
+ </a>
+ <script type="text/javascript">
+ document.getElementById('link').href = 'intent://play.google.com/store/apps/details?id=com.facebook.katana/#Intent;scheme=https;action=android.intent.action.VIEW;package=' + window.location.href.split('#')[1] + ';end';
+ </script>
+</body>
+</html>
diff --git a/weblayer/test/data/page_that_intents_to_chrome_on_load.html b/weblayer/test/data/page_that_intents_to_chrome_on_load.html
deleted file mode 100644
index 253dfbe..0000000
--- a/weblayer/test/data/page_that_intents_to_chrome_on_load.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <meta name="viewport"
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
-</head>
-<body>
- <a id='link' href='intent://play.google.com/store/apps/details?id=com.facebook.katana/#Intent;scheme=https;action=android.intent.action.VIEW;package=com.android.chrome;end'>
- Click to intent to production Chrome in this tab
-</a>
-<script>
- window.addEventListener("load", function() {
- document.getElementById("link").click();
- }, false);
-</script>
-</body>
-</html>
diff --git a/weblayer/test/data/page_that_intents_to_package_on_load.html b/weblayer/test/data/page_that_intents_to_package_on_load.html
new file mode 100644
index 0000000..4875c03
--- /dev/null
+++ b/weblayer/test/data/page_that_intents_to_package_on_load.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta name="viewport"
+ content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
+</head>
+<body>
+ <a id='link'>
+ Click to intent to the package specified in the URL hash in this tab
+ </a>
+<script>
+ document.getElementById('link').href = 'intent://play.google.com/store/apps/details?id=com.facebook.katana/#Intent;scheme=https;action=android.intent.action.VIEW;package=' + window.location.href.split('#')[1] + ';end';
+ window.addEventListener("load", function() {
+ document.getElementById("link").click();
+ }, false);
+</script>
+</body>
+</html>