Commit 9be039f1 authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

[WebLayer] Allow client to check if navigation entries are skippable

This adds isNavigationEntryMarkedToBeSkipped() to NavigationController
which allows the client to check if an entry will be taken into account
by goBack().

Will look into whether we need some sort of notification for when
entries are marked/unmarked as skipped.

Bug: 1082208
Change-Id: I3b5652e01c76677623d3edb3b97638a4df496fa1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2209591
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#770634}
parent d22d015f
...@@ -689,6 +689,32 @@ public class NavigationTest { ...@@ -689,6 +689,32 @@ public class NavigationTest {
assertEquals(customUserAgent, actualUserAgent); assertEquals(customUserAgent, actualUserAgent);
} }
@Test
@SmallTest
public void testSkippedNavigationEntry() throws Exception {
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(URL1);
setNavigationCallback(activity);
int curCompletedCount = mCallback.onCompletedCallback.getCallCount();
mActivityTestRule.executeScriptSync(
"history.pushState(null, '', '#foo');", true /* useSeparateIsolate */);
mCallback.onCompletedCallback.assertCalledWith(curCompletedCount, URL1 + "#foo", true);
curCompletedCount = mCallback.onCompletedCallback.getCallCount();
mActivityTestRule.executeScriptSync(
"history.pushState(null, '', '#bar');", true /* useSeparateIsolate */);
mCallback.onCompletedCallback.assertCalledWith(curCompletedCount, URL1 + "#bar", true);
runOnUiThreadBlocking(() -> {
NavigationController navigationController = activity.getTab().getNavigationController();
int currentIndex = navigationController.getNavigationListCurrentIndex();
// Should skip the two previous same document entries, but not the most recent.
assertFalse(navigationController.isNavigationEntrySkippable(currentIndex));
assertTrue(navigationController.isNavigationEntrySkippable(currentIndex - 1));
assertTrue(navigationController.isNavigationEntrySkippable(currentIndex - 2));
});
}
@Test @Test
@SmallTest @SmallTest
public void testIndexOutOfBounds() throws Exception { public void testIndexOutOfBounds() throws Exception {
...@@ -700,6 +726,7 @@ public class NavigationTest { ...@@ -700,6 +726,7 @@ public class NavigationTest {
assertIndexOutOfBoundsException(() -> controller.goToIndex(10)); assertIndexOutOfBoundsException(() -> controller.goToIndex(10));
assertIndexOutOfBoundsException(() -> controller.getNavigationEntryDisplayUri(10)); assertIndexOutOfBoundsException(() -> controller.getNavigationEntryDisplayUri(10));
assertIndexOutOfBoundsException(() -> controller.getNavigationEntryTitle(10)); assertIndexOutOfBoundsException(() -> controller.getNavigationEntryTitle(10));
assertIndexOutOfBoundsException(() -> controller.isNavigationEntrySkippable(10));
}); });
} }
......
...@@ -113,6 +113,13 @@ public final class NavigationControllerImpl extends INavigationController.Stub { ...@@ -113,6 +113,13 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
mNativeNavigationController, index); mNativeNavigationController, index);
} }
@Override
public boolean isNavigationEntrySkippable(int index) {
StrictModeWorkaround.apply();
return NavigationControllerImplJni.get().isNavigationEntrySkippable(
mNativeNavigationController, index);
}
@CalledByNative @CalledByNative
private NavigationImpl createNavigation(long nativeNavigationImpl) { private NavigationImpl createNavigation(long nativeNavigationImpl) {
return new NavigationImpl(mNavigationControllerClient, nativeNavigationImpl); return new NavigationImpl(mNavigationControllerClient, nativeNavigationImpl);
...@@ -178,5 +185,6 @@ public final class NavigationControllerImpl extends INavigationController.Stub { ...@@ -178,5 +185,6 @@ public final class NavigationControllerImpl extends INavigationController.Stub {
int getNavigationListCurrentIndex(long nativeNavigationControllerImpl); int getNavigationListCurrentIndex(long nativeNavigationControllerImpl);
String getNavigationEntryDisplayUri(long nativeNavigationControllerImpl, int index); String getNavigationEntryDisplayUri(long nativeNavigationControllerImpl, int index);
String getNavigationEntryTitle(long nativeNavigationControllerImpl, int index); String getNavigationEntryTitle(long nativeNavigationControllerImpl, int index);
boolean isNavigationEntrySkippable(long nativeNavigationControllerImpl, int index);
} }
} }
...@@ -33,4 +33,7 @@ interface INavigationController { ...@@ -33,4 +33,7 @@ interface INavigationController {
// Added in 82, removed in 83. // Added in 82, removed in 83.
// void replace(in String uri) = 12; // void replace(in String uri) = 12;
// Added in 85.
boolean isNavigationEntrySkippable(int index) = 13;
} }
...@@ -145,6 +145,11 @@ ScopedJavaLocalRef<jstring> NavigationControllerImpl::GetNavigationEntryTitle( ...@@ -145,6 +145,11 @@ ScopedJavaLocalRef<jstring> NavigationControllerImpl::GetNavigationEntryTitle(
return ScopedJavaLocalRef<jstring>(base::android::ConvertUTF8ToJavaString( return ScopedJavaLocalRef<jstring>(base::android::ConvertUTF8ToJavaString(
env, GetNavigationEntryTitle(index))); env, GetNavigationEntryTitle(index)));
} }
bool NavigationControllerImpl::IsNavigationEntrySkippable(JNIEnv* env,
int index) {
return IsNavigationEntrySkippable(index);
}
#endif #endif
void NavigationControllerImpl::WillRedirectRequest( void NavigationControllerImpl::WillRedirectRequest(
...@@ -248,6 +253,10 @@ std::string NavigationControllerImpl::GetNavigationEntryTitle(int index) { ...@@ -248,6 +253,10 @@ std::string NavigationControllerImpl::GetNavigationEntryTitle(int index) {
return base::UTF16ToUTF8(entry->GetTitle()); return base::UTF16ToUTF8(entry->GetTitle());
} }
bool NavigationControllerImpl::IsNavigationEntrySkippable(int index) {
return web_contents()->GetController().IsEntryMarkedToBeSkipped(index);
}
void NavigationControllerImpl::DidStartNavigation( void NavigationControllerImpl::DidStartNavigation(
content::NavigationHandle* navigation_handle) { content::NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame()) if (!navigation_handle->IsInMainFrame())
......
...@@ -64,6 +64,7 @@ class NavigationControllerImpl : public NavigationController, ...@@ -64,6 +64,7 @@ class NavigationControllerImpl : public NavigationController,
base::android::ScopedJavaLocalRef<jstring> GetNavigationEntryTitle( base::android::ScopedJavaLocalRef<jstring> GetNavigationEntryTitle(
JNIEnv* env, JNIEnv* env,
int index); int index);
bool IsNavigationEntrySkippable(JNIEnv* env, int index);
#endif #endif
private: private:
...@@ -90,6 +91,7 @@ class NavigationControllerImpl : public NavigationController, ...@@ -90,6 +91,7 @@ class NavigationControllerImpl : public NavigationController,
int GetNavigationListCurrentIndex() override; int GetNavigationListCurrentIndex() override;
GURL GetNavigationEntryDisplayURL(int index) override; GURL GetNavigationEntryDisplayURL(int index) override;
std::string GetNavigationEntryTitle(int index) override; std::string GetNavigationEntryTitle(int index) override;
bool IsNavigationEntrySkippable(int index) override;
// content::WebContentsObserver implementation: // content::WebContentsObserver implementation:
void DidStartNavigation( void DidStartNavigation(
......
...@@ -69,6 +69,9 @@ public class NavigationController { ...@@ -69,6 +69,9 @@ public class NavigationController {
/** /**
* Navigates to the previous navigation. * Navigates to the previous navigation.
* *
* Note: this may go back more than a single navigation entry, see {@link
* isNavigationEntrySkippable} for more details.
*
* @throws IndexOutOfBoundsException If {@link #canGoBack} returns false. * @throws IndexOutOfBoundsException If {@link #canGoBack} returns false.
*/ */
public void goBack() throws IndexOutOfBoundsException { public void goBack() throws IndexOutOfBoundsException {
...@@ -103,6 +106,9 @@ public class NavigationController { ...@@ -103,6 +106,9 @@ public class NavigationController {
/** /**
* Returns true if there is a navigation before the current one. * Returns true if there is a navigation before the current one.
* *
* Note: this may return false even if the current index is not 0, see {@link
* isNavigationEntrySkippable} for more details.
*
* @return Whether there is a navigation before the current one. * @return Whether there is a navigation before the current one.
*/ */
public boolean canGoBack() { public boolean canGoBack() {
...@@ -220,12 +226,6 @@ public class NavigationController { ...@@ -220,12 +226,6 @@ public class NavigationController {
} }
} }
private void checkNavigationIndex(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= getNavigationListSize()) {
throw new IndexOutOfBoundsException();
}
}
/** /**
* Returns the title of the navigation entry at the supplied index. * Returns the title of the navigation entry at the supplied index.
* *
...@@ -247,6 +247,28 @@ public class NavigationController { ...@@ -247,6 +247,28 @@ public class NavigationController {
} }
} }
/**
* Returns whether this entry will be skipped on a call to {@link goBack} or {@link goForward}.
* This will be true for certain navigations, such as certain client side redirects and
* history.pushState navigations done without user interaction.
*
* @throws IndexOutOfBoundsException If index is not between 0 and {@link
* getNavigationListCurrentIndex}.
* @since 85
*/
public boolean isNavigationEntrySkippable(int index) throws IndexOutOfBoundsException {
ThreadCheck.ensureOnUiThread();
if (WebLayer.getSupportedMajorVersionInternal() < 85) {
throw new UnsupportedOperationException();
}
checkNavigationIndex(index);
try {
return mNavigationController.isNavigationEntrySkippable(index);
} catch (RemoteException e) {
throw new APICallException(e);
}
}
public void registerNavigationCallback(@NonNull NavigationCallback callback) { public void registerNavigationCallback(@NonNull NavigationCallback callback) {
ThreadCheck.ensureOnUiThread(); ThreadCheck.ensureOnUiThread();
mCallbacks.addObserver(callback); mCallbacks.addObserver(callback);
...@@ -257,6 +279,12 @@ public class NavigationController { ...@@ -257,6 +279,12 @@ public class NavigationController {
mCallbacks.removeObserver(callback); mCallbacks.removeObserver(callback);
} }
private void checkNavigationIndex(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= getNavigationListSize()) {
throw new IndexOutOfBoundsException();
}
}
private final class NavigationControllerClientImpl extends INavigationControllerClient.Stub { private final class NavigationControllerClientImpl extends INavigationControllerClient.Stub {
@Override @Override
public IClientNavigation createClientNavigation(INavigation navigationImpl) { public IClientNavigation createClientNavigation(INavigation navigationImpl) {
......
...@@ -60,6 +60,11 @@ class NavigationController { ...@@ -60,6 +60,11 @@ class NavigationController {
// Gets the page title of the given entry in the back/forward list, or an // Gets the page title of the given entry in the back/forward list, or an
// empty string if there is no navigation entry at that index. // empty string if there is no navigation entry at that index.
virtual std::string GetNavigationEntryTitle(int index) = 0; virtual std::string GetNavigationEntryTitle(int index) = 0;
// Returns whether this entry will be skipped on a call to GoBack() or
// GoForward(). This will be true for navigations that were done without a
// user gesture, including both client side redirects and history.pushState.
virtual bool IsNavigationEntrySkippable(int index) = 0;
}; };
} // namespace weblayer } // namespace weblayer
......
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