Commit dbb8fa6b authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

weblayer: adds ability to disable intent processing

Currently navigations triggered from the embedder use a
navigation type of LINK. LINK navigations (mostly) result in
processing intents. This is not always desirable (for example,
the SRP shouldn't trigger intents).

This patch adds the ability to disable Intent processing.
I went with a function to disable vs an explicit setter as I
don't think we need support for an absolute 'true' case. By
that I mean if I did add a function like
setIntentProcessingEnabled(boolean value), the implication
is 'true' means intent processing always happens. In code that
isn't the case though, for example, a same host navigation may
not trigger intent resolution. As we don't need the ability
to force intent processing, I'm avoiding it for now.

BUG=1119365
TEST=covered by android tests

Change-Id: Ib374c1d61ce0795654a677b1ff29128f39c75bd9
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2369516Reviewed-by: default avatarDarin Fisher <darin@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Commit-Queue: Scott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#801837}
parent 925b9d8e
......@@ -20,6 +20,7 @@ import org.junit.runner.RunWith;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.weblayer.Browser;
import org.chromium.weblayer.NavigateParams;
import org.chromium.weblayer.Tab;
import org.chromium.weblayer.TabListCallback;
import org.chromium.weblayer.shell.InstrumentationActivity;
......@@ -532,4 +533,35 @@ public class ExternalNavigationTest {
Assert.assertEquals(INTENT_TO_CHROME_ACTION, intent.getAction());
Assert.assertEquals(INTENT_TO_CHROME_DATA_STRING, intent.getDataString());
}
/**
* Verifies that disableIntentProcessing() does in fact disable intent processing.
*/
@Test
@SmallTest
@MinWebLayerVersion(87)
public void testDisableIntentProcessing() throws Throwable {
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(ABOUT_BLANK_URL);
IntentInterceptor intentInterceptor = new IntentInterceptor();
activity.setIntentInterceptor(intentInterceptor);
String url = mActivityTestRule.getTestDataURL(PAGE_THAT_INTENTS_TO_CHROME_ON_LOAD_FILE);
Tab tab = mActivityTestRule.getActivity().getTab();
TestThreadUtils.runOnUiThreadBlocking(() -> {
NavigateParams.Builder navigateParamsBuilder = new NavigateParams.Builder();
navigateParamsBuilder.disableIntentProcessing();
tab.getNavigationController().navigate(Uri.parse(url), navigateParamsBuilder.build());
});
NavigationWaiter waiter = new NavigationWaiter(
INTENT_TO_CHROME_URL, tab, /*expectFailure=*/true, /*waitForPaint=*/false);
waiter.waitForNavigation();
Assert.assertNull(intentInterceptor.mLastIntent);
// The current URL should not have changed.
Assert.assertEquals(url, mActivityTestRule.getCurrentDisplayUrl());
}
}
......@@ -36,12 +36,15 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
if (WebLayerFactoryImpl.getClientMajorVersion() < 83) {
assert params == null;
}
if (params == null) {
NavigationControllerImplJni.get().navigate(mNativeNavigationController, uri);
} else {
NavigationControllerImplJni.get().navigateWithParams(
mNativeNavigationController, uri, params.mShouldReplaceCurrentEntry);
}
navigate2(uri, params == null ? false : params.mShouldReplaceCurrentEntry, false);
}
@Override
public void navigate2(String uri, boolean shouldReplaceCurrentEntry,
boolean disableIntentProcessing) throws RemoteException {
StrictModeWorkaround.apply();
NavigationControllerImplJni.get().navigate(mNativeNavigationController, uri,
shouldReplaceCurrentEntry, disableIntentProcessing);
}
@Override
......@@ -177,9 +180,8 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
void setNavigationControllerImpl(
long nativeNavigationControllerImpl, NavigationControllerImpl caller);
long getNavigationController(long tab);
void navigate(long nativeNavigationControllerImpl, String uri);
void navigateWithParams(
long nativeNavigationControllerImpl, String uri, boolean shouldReplaceCurrentEntry);
void navigate(long nativeNavigationControllerImpl, String uri,
boolean shouldReplaceCurrentEntry, boolean disableIntentProcessing);
void goBack(long nativeNavigationControllerImpl);
void goForward(long nativeNavigationControllerImpl);
boolean canGoBack(long nativeNavigationControllerImpl);
......
......@@ -36,4 +36,9 @@ interface INavigationController {
// Added in 85.
boolean isNavigationEntrySkippable(int index) = 13;
// Added in 87.
void navigate2(in String uri,
in boolean shouldReplaceEntry,
in boolean disableIntentProcessing) = 14;
}
......@@ -125,17 +125,19 @@ void NavigationControllerImpl::SetNavigationControllerImpl(
}
void NavigationControllerImpl::Navigate(JNIEnv* env,
const JavaParamRef<jstring>& url) {
Navigate(GURL(base::android::ConvertJavaStringToUTF8(env, url)));
}
void NavigationControllerImpl::NavigateWithParams(
JNIEnv* env,
const JavaParamRef<jstring>& url,
jboolean should_replace_current_entry) {
const JavaParamRef<jstring>& url,
jboolean should_replace_current_entry,
jboolean disable_intent_processing) {
auto params = std::make_unique<content::NavigationController::LoadURLParams>(
GURL(base::android::ConvertJavaStringToUTF8(env, url)));
params->should_replace_current_entry = should_replace_current_entry;
// On android, the transition type largely dictates whether intent processing
// happens. PAGE_TRANSITION_TYPED does not process intents, where as
// PAGE_TRANSITION_LINK will (with the caveat that even links may not trigger
// intent processing under some circumstances).
params->transition_type = disable_intent_processing
? ui::PAGE_TRANSITION_TYPED
: ui::PAGE_TRANSITION_LINK;
DoNavigate(std::move(params));
}
......@@ -465,11 +467,6 @@ void NavigationControllerImpl::DoNavigate(
return;
}
// For WebLayer's production use cases, navigations from the embedder are most
// appropriately viewed as being from links with user gestures. In particular,
// this ensures that intents resulting from these navigations get launched as
// the embedder expects.
params->transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
params->has_user_gesture = true;
web_contents()->GetController().LoadURLWithParams(*params);
// So that if the user had entered the UI in a bar it stops flashing the
......
......@@ -50,10 +50,9 @@ class NavigationControllerImpl : public NavigationController,
JNIEnv* env,
const base::android::JavaParamRef<jobject>& java_controller);
void Navigate(JNIEnv* env,
const base::android::JavaParamRef<jstring>& url);
void NavigateWithParams(JNIEnv* env,
const base::android::JavaParamRef<jstring>& url,
jboolean should_replace_current_entry);
const base::android::JavaParamRef<jstring>& url,
jboolean should_replace_current_entry,
jboolean disableIntentProcessing);
void GoBack(JNIEnv* env) { GoBack(); }
void GoForward(JNIEnv* env) { GoForward(); }
bool CanGoBack(JNIEnv* env) { return CanGoBack(); }
......
......@@ -14,6 +14,7 @@ import androidx.annotation.NonNull;
public class NavigateParams {
private org.chromium.weblayer_private.interfaces.NavigateParams mInterfaceParams =
new org.chromium.weblayer_private.interfaces.NavigateParams();
private boolean mIntentProcessingDisabled;
/**
* A Builder class to help create NavigateParams.
......@@ -45,6 +46,24 @@ public class NavigateParams {
mParams.mInterfaceParams.mShouldReplaceCurrentEntry = replace;
return this;
}
/**
* Disables lookup and launching of an Intent that matches the uri being navigated to. If
* this is not called, WebLayer may look for a matching intent-filter, and if one is found,
* create and launch an Intent. The exact heuristics of when Intent matching is performed
* depends upon a wide range of state (such as the uri being navigated to, navigation
* stack...).
*
* @since 87
*/
@NonNull
public Builder disableIntentProcessing() {
if (WebLayer.getSupportedMajorVersionInternal() < 87) {
throw new UnsupportedOperationException();
}
mParams.mIntentProcessingDisabled = true;
return this;
}
}
org.chromium.weblayer_private.interfaces.NavigateParams toInterfaceParams() {
......@@ -59,4 +78,18 @@ public class NavigateParams {
public boolean getShouldReplaceCurrentEntry() {
return mInterfaceParams.mShouldReplaceCurrentEntry;
}
/**
* Returns true if intent processing is disabled.
*
* @return Whether intent process is disabled.
*
* @since 87
*/
public boolean isIntentProcessingDisabled() {
if (WebLayer.getSupportedMajorVersionInternal() < 87) {
throw new UnsupportedOperationException();
}
return mIntentProcessingDisabled;
}
}
......@@ -59,8 +59,14 @@ public class NavigationController {
throw new UnsupportedOperationException();
}
try {
mNavigationController.navigate(
uri.toString(), params == null ? null : params.toInterfaceParams());
if (params == null || WebLayer.getSupportedMajorVersionInternal() < 87) {
mNavigationController.navigate(
uri.toString(), params == null ? null : params.toInterfaceParams());
} else {
mNavigationController.navigate2(uri.toString(),
params == null ? false : params.getShouldReplaceCurrentEntry(),
params == null ? false : params.isIntentProcessingDisabled());
}
} catch (RemoteException e) {
throw new APICallException(e);
}
......
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