Commit f5fb7c8e authored by Colin Blundell's avatar Colin Blundell Committed by Commit Bot

[Android] Componentize and dedupe getSpecializedHandlersWithFilter

This CL dedupes the //chrome and //weblayer implementations of
getSpecializedHandlersWithFilter() into a static function in
ExternalNavigationHandler.java. There is a slight difference between
the two impls: //chrome's does not consider the InstantApp launcher as
a specialized handler because it handles launching of Instant Apps
internally. WebLayer, however, does not handle launching of Instant Apps
itself and instead lets the system do so as appropriate. We handle this
by adding a parameter to the new //components-level version of the
function.

We also move the tests of this function to
ExternalNavigationHandlerTest.java, including testing the behavior in
response to the value of this new parameter.

A followup CL will dedupe and eliminate the ExternalNavigationDelegate
methods that can be implemented within ExternalNavigationHandler
following this change.

Bug: 1071390
Change-Id: I701c4aa8c46260de3357b3d52e536a237d8c7b60
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2184277Reviewed-by: default avatarMichael Thiessen <mthiesse@chromium.org>
Commit-Queue: Colin Blundell <blundell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#766447}
parent 3e116501
......@@ -19,8 +19,6 @@ import android.provider.Browser;
import android.text.TextUtils;
import android.view.WindowManager.BadTokenException;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.ApplicationState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.ContextUtils;
......@@ -123,40 +121,12 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
@Override
public int countSpecializedHandlers(List<ResolveInfo> infos) {
return getSpecializedHandlersWithFilter(infos, null).size();
return ExternalNavigationHandler.getSpecializedHandlersWithFilter(infos, null, true).size();
}
@Override
public ArrayList<String> getSpecializedHandlers(List<ResolveInfo> infos) {
return getSpecializedHandlersWithFilter(infos, null);
}
@VisibleForTesting
public static ArrayList<String> getSpecializedHandlersWithFilter(
List<ResolveInfo> infos, String filterPackageName) {
ArrayList<String> result = new ArrayList<>();
if (infos == null) {
return result;
}
for (ResolveInfo info : infos) {
if (!ExternalNavigationHandler.matchResolveInfoExceptWildCardHost(
info, filterPackageName)) {
continue;
}
if (info.activityInfo != null) {
if (IntentUtils.isInstantAppResolveInfo(info)) {
// Don't consider the Instant Apps resolver a specialized application.
continue;
}
result.add(info.activityInfo.packageName);
} else {
result.add("");
}
}
return result;
return ExternalNavigationHandler.getSpecializedHandlersWithFilter(infos, null, true);
}
/**
......@@ -170,7 +140,9 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
public static boolean isPackageSpecializedHandler(String packageName, Intent intent) {
List<ResolveInfo> handlers = PackageManagerUtils.queryIntentActivities(
intent, PackageManager.GET_RESOLVED_FILTER);
return !getSpecializedHandlersWithFilter(handlers, packageName).isEmpty();
return !ExternalNavigationHandler
.getSpecializedHandlersWithFilter(handlers, packageName, true)
.isEmpty();
}
@Override
......
......@@ -5,11 +5,7 @@
package org.chromium.chrome.browser.externalnav;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.support.test.filters.SmallTest;
import org.junit.Assert;
......@@ -18,7 +14,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.IntentUtils;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.IntentHandler;
......@@ -31,10 +26,6 @@ import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.external_intents.ExternalNavigationHandler;
import org.chromium.components.external_intents.ExternalNavigationParams;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Instrumentation tests for {@link ExternalNavigationHandler}.
*/
......@@ -93,142 +84,6 @@ import java.util.List;
public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
new ChromeActivityTestRule<>(ChromeActivity.class);
private static List<ResolveInfo> makeResolveInfos(ResolveInfo... infos) {
return Arrays.asList(infos);
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_NoResolveInfo() {
String packageName = "";
List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>();
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_NoPathOrAuthority() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithPath() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataPath("somepath", 2);
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithAuthority() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("http://www.google.com", "80");
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithAuthority_Wildcard_Host() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("*", null);
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.size());
ResolveInfo infoWildcardSubDomain = new ResolveInfo();
infoWildcardSubDomain.filter = new IntentFilter();
infoWildcardSubDomain.filter.addDataAuthority("http://*.google.com", "80");
List<ResolveInfo> resolveInfosWildcardSubDomain = makeResolveInfos(infoWildcardSubDomain);
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(
resolveInfosWildcardSubDomain, packageName)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithTargetPackage_Matching() {
String packageName = "com.android.chrome";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("http://www.google.com", "80");
info.activityInfo = new ActivityInfo();
info.activityInfo.packageName = packageName;
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithTargetPackage_NotMatching() {
String packageName = "com.android.chrome";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("http://www.google.com", "80");
info.activityInfo = new ActivityInfo();
info.activityInfo.packageName = "com.foo.bar";
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializeHandler_withEphemeralResolver() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataPath("somepath", 2);
info.activityInfo = new ActivityInfo();
// See IntentUtils.isInstantAppResolveInfo
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
info.isInstantAppAvailable = true;
} else {
info.activityInfo.name = IntentUtils.EPHEMERAL_INSTALLER_CLASS;
}
info.activityInfo.packageName = "com.google.android.gms";
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
// Ephemeral resolver is not counted as a specialized handler.
Assert.assertEquals(0,
ExternalNavigationDelegateImpl
.getSpecializedHandlersWithFilter(resolveInfos, packageName)
.size());
}
@Test
@SmallTest
public void testMaybeSetPendingIncognitoUrl() {
......
......@@ -1389,10 +1389,7 @@ public class ExternalNavigationHandler {
return !canSelfOpen || allowSelfOpen || hasPdfViewer;
}
// TODO(crbug.com/1071390): Make this method private once its consumers have been moved into
// this class.
public static boolean matchResolveInfoExceptWildCardHost(
ResolveInfo info, String filterPackageName) {
static boolean matchResolveInfoExceptWildCardHost(ResolveInfo info, String filterPackageName) {
IntentFilter intentFilter = info.filter;
if (intentFilter == null) {
// Error on the side of classifying ResolveInfo as generic.
......@@ -1422,6 +1419,35 @@ public class ExternalNavigationHandler {
return true;
}
@VisibleForTesting
public static ArrayList<String> getSpecializedHandlersWithFilter(List<ResolveInfo> infos,
String filterPackageName, boolean handlesInstantAppLaunchingInternally) {
ArrayList<String> result = new ArrayList<>();
if (infos == null) {
return result;
}
for (ResolveInfo info : infos) {
if (!matchResolveInfoExceptWildCardHost(info, filterPackageName)) {
continue;
}
if (info.activityInfo != null) {
if (handlesInstantAppLaunchingInternally
&& IntentUtils.isInstantAppResolveInfo(info)) {
// Don't add the Instant Apps launcher as a specialized handler if the embedder
// handles launching of Instant Apps itself.
continue;
}
result.add(info.activityInfo.packageName);
} else {
result.add("");
}
}
return result;
}
/**
* @return Default SMS application's package name at the system level. Null if there isn't any.
*/
......
......@@ -31,6 +31,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.ContextUtils;
import org.chromium.base.IntentUtils;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.test.BaseJUnit4ClassRunner;
import org.chromium.base.test.util.DisableIf;
......@@ -43,6 +44,7 @@ import org.chromium.ui.base.WindowAndroid;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
......@@ -70,6 +72,7 @@ public class ExternalNavigationHandlerTest {
private static final boolean IS_CUSTOM_TAB_INTENT = true;
private static final boolean SEND_TO_EXTERNAL_APPS = true;
private static final boolean IS_CCT_EXTERNAL_LINK_HANDLING_ENABLED = true;
private static final boolean HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY = true;
private static final String SEARCH_RESULT_URL_FOR_TOM_HANKS =
"https://www.google.com/search?q=tom+hanks";
......@@ -1656,6 +1659,156 @@ public class ExternalNavigationHandlerTest {
mUrlHandler.isPdfDownload("http://somesampleurldne.com/copy.txt"));
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_NoResolveInfo() {
String packageName = "";
List<ResolveInfo> resolveInfos = new ArrayList<ResolveInfo>();
Assert.assertEquals(0,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_NoPathOrAuthority() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(0,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithPath() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataPath("somepath", 2);
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithAuthority() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("http://www.google.com", "80");
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithAuthority_Wildcard_Host() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("*", null);
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(0,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
ResolveInfo infoWildcardSubDomain = new ResolveInfo();
infoWildcardSubDomain.filter = new IntentFilter();
infoWildcardSubDomain.filter.addDataAuthority("http://*.google.com", "80");
List<ResolveInfo> resolveInfosWildcardSubDomain = makeResolveInfos(infoWildcardSubDomain);
Assert.assertEquals(1,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(resolveInfosWildcardSubDomain,
packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithTargetPackage_Matching() {
String packageName = "com.android.chrome";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("http://www.google.com", "80");
info.activityInfo = new ActivityInfo();
info.activityInfo.packageName = packageName;
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(1,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializedHandler_WithTargetPackage_NotMatching() {
String packageName = "com.android.chrome";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataAuthority("http://www.google.com", "80");
info.activityInfo = new ActivityInfo();
info.activityInfo.packageName = "com.foo.bar";
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
Assert.assertEquals(0,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
}
@Test
@SmallTest
public void testIsPackageSpecializeHandler_withEphemeralResolver() {
String packageName = "";
ResolveInfo info = new ResolveInfo();
info.filter = new IntentFilter();
info.filter.addDataPath("somepath", 2);
info.activityInfo = new ActivityInfo();
// See IntentUtils.isInstantAppResolveInfo
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
info.isInstantAppAvailable = true;
} else {
info.activityInfo.name = IntentUtils.EPHEMERAL_INSTALLER_CLASS;
}
info.activityInfo.packageName = "com.google.android.gms";
List<ResolveInfo> resolveInfos = makeResolveInfos(info);
// Whether ephemeral resolver is counted as a specialized handler should be dependent on the
// value passed for |handlesInstantAppLaunchingInternally|.
Assert.assertEquals(0,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(
resolveInfos, packageName, HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
Assert.assertEquals(1,
ExternalNavigationHandler
.getSpecializedHandlersWithFilter(resolveInfos, packageName,
!HANDLES_INSTANT_APP_LAUNCHING_INTERNALLY)
.size());
}
private static List<ResolveInfo> makeResolveInfos(ResolveInfo... infos) {
return Arrays.asList(infos);
}
private static ResolveInfo newResolveInfo(String packageName) {
ActivityInfo ai = new ActivityInfo();
ai.packageName = packageName;
......
......@@ -7,15 +7,11 @@ package org.chromium.weblayer_private;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.StrictMode;
import androidx.annotation.VisibleForTesting;
import org.chromium.base.ContextUtils;
import org.chromium.base.IntentUtils;
import org.chromium.base.PackageManagerUtils;
import org.chromium.components.external_intents.ExternalNavigationDelegate;
import org.chromium.components.external_intents.ExternalNavigationHandler;
import org.chromium.components.external_intents.ExternalNavigationHandler.OverrideUrlLoadingResult;
......@@ -63,49 +59,13 @@ public class ExternalNavigationDelegateImpl implements ExternalNavigationDelegat
@Override
public int countSpecializedHandlers(List<ResolveInfo> infos) {
return getSpecializedHandlersWithFilter(infos, null).size();
return ExternalNavigationHandler.getSpecializedHandlersWithFilter(infos, null, false)
.size();
}
@Override
public ArrayList<String> getSpecializedHandlers(List<ResolveInfo> infos) {
return getSpecializedHandlersWithFilter(infos, null);
}
@VisibleForTesting
public static ArrayList<String> getSpecializedHandlersWithFilter(
List<ResolveInfo> infos, String filterPackageName) {
ArrayList<String> result = new ArrayList<>();
if (infos == null) {
return result;
}
for (ResolveInfo info : infos) {
if (!ExternalNavigationHandler.matchResolveInfoExceptWildCardHost(
info, filterPackageName)) {
continue;
}
if (info.activityInfo != null) {
result.add(info.activityInfo.packageName);
} else {
result.add("");
}
}
return result;
}
/**
* Check whether the given package is a specialized handler for the given intent
*
* @param packageName Package name to check against. Can be null or empty.
* @param intent The intent to resolve for.
* @return Whether the given package is a specialized handler for the given intent. If there is
* no package name given checks whether there is any specialized handler.
*/
public static boolean isPackageSpecializedHandler(String packageName, Intent intent) {
List<ResolveInfo> handlers = PackageManagerUtils.queryIntentActivities(
intent, PackageManager.GET_RESOLVED_FILTER);
return !getSpecializedHandlersWithFilter(handlers, packageName).isEmpty();
return ExternalNavigationHandler.getSpecializedHandlersWithFilter(infos, null, false);
}
@Override
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment