diff --git a/mobile/android/geckoview/api.txt b/mobile/android/geckoview/api.txt index 5b1e5c47b802..752d389292ff 100644 --- a/mobile/android/geckoview/api.txt +++ b/mobile/android/geckoview/api.txt @@ -544,6 +544,7 @@ package org.mozilla.geckoview { method @AnyThread public void loadUri(@NonNull Uri, @Nullable Uri, int); method @AnyThread public void loadUri(@NonNull Uri, @Nullable Uri, int, @Nullable Map); method @UiThread public void open(@NonNull GeckoRuntime); + method @AnyThread public void purgeHistory(); method @AnyThread public void readFromParcel(@NonNull Parcel); method @UiThread public void releaseDisplay(@NonNull GeckoDisplay); method @AnyThread public void reload(); diff --git a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt index 9b6fbf45c15e..c142cdcbd72e 100644 --- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt +++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/NavigationDelegateTest.kt @@ -1335,4 +1335,56 @@ class NavigationDelegateTest : BaseSessionTest() { } }) } + + @Test fun purgeHistory() { + sessionRule.session.loadUri("$TEST_ENDPOINT$HELLO_HTML_PATH") + sessionRule.waitUntilCalled(object : Callbacks.NavigationDelegate { + @AssertCalled(count = 1) + override fun onCanGoBack(session: GeckoSession, canGoBack: Boolean) { + assertThat("Session should not be null", session, notNullValue()) + assertThat("Cannot go back", canGoBack, equalTo(false)) + } + + @AssertCalled(count = 1) + override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) { + assertThat("Session should not be null", session, notNullValue()) + assertThat("Cannot go forward", canGoForward, equalTo(false)) + } + }) + sessionRule.session.loadUri("$TEST_ENDPOINT$HELLO2_HTML_PATH") + sessionRule.waitUntilCalled(object : Callbacks.All { + @AssertCalled(count = 1) + override fun onCanGoBack(session: GeckoSession, canGoBack: Boolean) { + assertThat("Session should not be null", session, notNullValue()) + assertThat("Cannot go back", canGoBack, equalTo(true)) + } + @AssertCalled(count = 1) + override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) { + assertThat("Session should not be null", session, notNullValue()) + assertThat("Cannot go forward", canGoForward, equalTo(false)) + } + @AssertCalled(count = 1) + override fun onHistoryStateChange(session: GeckoSession, state: GeckoSession.HistoryDelegate.HistoryList) { + assertThat("History should have two entries", state.size, equalTo(2)) + } + }) + sessionRule.session.purgeHistory() + sessionRule.waitUntilCalled(object : Callbacks.All { + @AssertCalled(count = 1) + override fun onHistoryStateChange(session: GeckoSession, state: GeckoSession.HistoryDelegate.HistoryList) { + assertThat("History should have one entry", state.size, equalTo(1)) + } + @AssertCalled(count = 1) + override fun onCanGoBack(session: GeckoSession, canGoBack: Boolean) { + assertThat("Session should not be null", session, notNullValue()) + assertThat("Cannot go back", canGoBack, equalTo(false)) + } + + @AssertCalled(count = 1) + override fun onCanGoForward(session: GeckoSession, canGoForward: Boolean) { + assertThat("Session should not be null", session, notNullValue()) + assertThat("Cannot go forward", canGoForward, equalTo(false)) + } + }) + } } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java index aaab32a0a73f..b725b17d3a00 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java @@ -732,11 +732,20 @@ public class GeckoSession implements Parcelable { final HistoryDelegate historyDelegate = getHistoryDelegate(); final GeckoBundle update = message.getBundle("data"); if (update != null) { + final int previousHistorySize = mStateCache.size(); mStateCache.updateSessionState(update); final SessionState state = new SessionState(mStateCache); delegate.onSessionStateChange(GeckoSession.this, state); - if (historyDelegate != null && update.getBundle("historychange") != null) { - historyDelegate.onHistoryStateChange(GeckoSession.this, state); + if (update.getBundle("historychange") != null) { + if (historyDelegate != null) { + historyDelegate.onHistoryStateChange(GeckoSession.this, state); + } + // If the previous history was larger than one entry and the new size is one, it means the + // History has been purged and the navigation delegate needs to be update. + if ((previousHistorySize > 1) && (state.size() == 1) && mNavigationHandler.getDelegate() != null) { + mNavigationHandler.getDelegate().onCanGoForward(GeckoSession.this, false); + mNavigationHandler.getDelegate().onCanGoBack(GeckoSession.this, false); + } } } } @@ -1898,6 +1907,17 @@ public class GeckoSession implements Parcelable { mEventDispatcher.dispatch("GeckoView:GotoHistoryIndex", msg); } + /** + * Purge history for the session. + * The session history is used for back and forward history. + * Purging the session history means {@link NavigationDelegate#onCanGoBack(GeckoSession, boolean)} + * and {@link NavigationDelegate#onCanGoForward(GeckoSession, boolean)} will be false. + */ + @AnyThread + public void purgeHistory() { + mEventDispatcher.dispatch("GeckoView:PurgeHistory", null); + } + @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, value = {FINDER_FIND_BACKWARDS, FINDER_FIND_LINKS_ONLY, diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md index 296abaa51a0b..141e9f5ac888 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md @@ -41,6 +41,8 @@ exclude: true - ⚠️ Added [`GeckoView.onTouchEventForResult`][71.15] and modified [`PanZoomController.onTouchEvent`][71.16] to return how the touch event was handled. This allows apps to know if an event is handled by touch event listeners in web content. The methods in `PanZoomController` now return `int` instead of `boolean`. +- Added [`GeckoSession.purgeHistory`][71.17] allowing apps to clear a session's history. + ([bug 1583265]({{bugzilla}}1583265)) [71.1]: {{javadoc_uri}}/RuntimeTelemetry.Delegate.html#onBooleanScalar-org.mozilla.geckoview.RuntimeTelemetry.Metric- [71.2]: {{javadoc_uri}}/RuntimeTelemetry.Delegate.html#onLongScalar-org.mozilla.geckoview.RuntimeTelemetry.Metric- @@ -57,6 +59,7 @@ exclude: true [71.13]: {{javadoc_uri}}/GeckoSession.ContentDelegate.html#onFirstContentfulPaint-org.mozilla.geckoview.GeckoSession- [71.15]: {{javadoc_uri}}/GeckoView.html#onTouchEventForResult-android.view.MotionEvent- [71.16]: {{javadoc_uri}}/PanZoomController.html#onTouchEvent-android.view.MotionEvent- +[71.17]: {{javadoc_uri}}/GeckoSession.html#purgeHistory-- ## v70 - Added API for session context assignment @@ -379,4 +382,4 @@ exclude: true [65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String- [65.25]: {{javadoc_uri}}/GeckoResult.html -[api-version]: 68710f52723909eea09a02b94b618a527cc9dfc8 +[api-version]: c588ee34768a61847786ba32b4cefdbe60eed774 diff --git a/mobile/android/modules/geckoview/GeckoViewNavigation.jsm b/mobile/android/modules/geckoview/GeckoViewNavigation.jsm index 4a10a0505aec..4018bb8063c7 100644 --- a/mobile/android/modules/geckoview/GeckoViewNavigation.jsm +++ b/mobile/android/modules/geckoview/GeckoViewNavigation.jsm @@ -64,6 +64,7 @@ class GeckoViewNavigation extends GeckoViewModule { "GeckoView:LoadUri", "GeckoView:Reload", "GeckoView:Stop", + "GeckoView:PurgeHistory", ]); this.messageManager.addMessageListener("Browser:LoadURI", this); @@ -243,6 +244,9 @@ class GeckoViewNavigation extends GeckoViewModule { case "GeckoView:Stop": this.browser.stop(); break; + case "GeckoView:PurgeHistory": + this.browser.purgeSessionHistory(); + break; } }