Skip to content

Commit

Permalink
[BrowserFragment] Add multi-tab back navigation
Browse files Browse the repository at this point in the history
- Facilitate back navigation across multiple tabs by providing a back-navigation function per browser fragment instead of per tab, order of tabs is preserved in native browser.
- Add close() function for browserfragment.Tab

Change-Id: Id532ede5d8a964482adeee357da6a3ff508bf8b2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3805337
Reviewed-by: Robert Sesek <rsesek@chromium.org>
Reviewed-by: Clark DuVall <cduvall@chromium.org>
Commit-Queue: Susanne Westphal <swestphal@chromium.org>
Reviewed-by: Rayan Kanso <rayankans@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1035086}
  • Loading branch information
s-westphal authored and Chromium LUCI CQ committed Aug 15, 2022
1 parent c8a34f2 commit f56c90c
Show file tree
Hide file tree
Showing 16 changed files with 181 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ public boolean setActiveTab(ITab controller) {
}

@Override
public List getTabs() {
public List<TabImpl> getTabs() {
StrictModeWorkaround.apply();
return Arrays.asList(BrowserImplJni.get().getTabs(mNativeBrowser));
}
Expand All @@ -474,6 +474,17 @@ public int getActiveTabId() {
return getActiveTab() != null ? getActiveTab().getId() : 0;
}

@Override
public int[] getTabIds() {
StrictModeWorkaround.apply();
List<TabImpl> tabs = getTabs();
int[] ids = new int[tabs.size()];
for(int i = 0; i < tabs.size(); i++) {
ids[i] = tabs.get(i).getId();
}
return ids;
}

@Override
public void setClient(IBrowserClient client) {
// This function is called from the client once everything has been setup (meaning all the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,7 @@ interface IBrowser {

// Added in 105.
void setSurfaceControlViewHost(in IObjectWrapper host) = 19;

// Added in 105
int[] getTabIds() = 20;
}
2 changes: 1 addition & 1 deletion weblayer/public/java/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,11 @@ process_version("client_version") {
android_aidl("browserfragment_aidl") {
import_include = [ "." ]
sources = [
"org/chromium/browserfragment/interfaces/IBooleanCallback.aidl",
"org/chromium/browserfragment/interfaces/IBrowserFragmentDelegate.aidl",
"org/chromium/browserfragment/interfaces/IBrowserFragmentDelegateClient.aidl",
"org/chromium/browserfragment/interfaces/IBrowserSandboxCallback.aidl",
"org/chromium/browserfragment/interfaces/IBrowserSandboxService.aidl",
"org/chromium/browserfragment/interfaces/IRequestNavigationCallback.aidl",
"org/chromium/browserfragment/interfaces/ITabCallback.aidl",
"org/chromium/browserfragment/interfaces/ITabNavigationControllerProxy.aidl",
"org/chromium/browserfragment/interfaces/ITabObserverDelegate.aidl",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ void initialize(Browser browser, IBrowserFragmentDelegate delegate) throws Remot
mBrowser = browser;
mDelegate = delegate;
mDelegate.setClient(mClient);
mDelegate.setTabObserverDelegate(mTabObserverDelegate);
}

@Override
Expand Down
14 changes: 12 additions & 2 deletions weblayer/public/java/org/chromium/browserfragment/Tab.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import org.chromium.browserfragment.interfaces.ITabProxy;

/**
* Tab controls of the tab content.
* Tab controls the tab content and state.
*/
public class Tab {
private ITabProxy mTabProxy;
Expand All @@ -35,7 +35,7 @@ public String getGuid() {
}

/**
* Sets this tab to active.
* Sets this Tab to active.
*/
public void setActive() {
try {
Expand All @@ -44,6 +44,16 @@ public void setActive() {
}
}

/*
* Closes this Tab.
*/
public void close() {
try {
mTabProxy.close();
} catch (RemoteException e) {
}
}

/**
* Returns the navigation controller for this Tab.
*
Expand Down
35 changes: 35 additions & 0 deletions weblayer/public/java/org/chromium/browserfragment/TabManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import com.google.common.util.concurrent.ListenableFuture;

import org.chromium.browserfragment.interfaces.IBooleanCallback;
import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegate;
import org.chromium.browserfragment.interfaces.ITabCallback;
import org.chromium.browserfragment.interfaces.ITabParams;
Expand All @@ -25,6 +26,19 @@
public class TabManager {
private IBrowserFragmentDelegate mDelegate;

private final class RequestNavigationCallback extends IBooleanCallback.Stub {
private CallbackToFutureAdapter.Completer<Boolean> mCompleter;

RequestNavigationCallback(CallbackToFutureAdapter.Completer<Boolean> completer) {
mCompleter = completer;
}

@Override
public void onResult(boolean didNavigate) {
mCompleter.set(didNavigate);
}
}

private final class TabCallback extends ITabCallback.Stub {
private CallbackToFutureAdapter.Completer<Tab> mCompleter;

Expand Down Expand Up @@ -64,4 +78,25 @@ public ListenableFuture<Tab> getActiveTab() {
return "Active Tab Future";
});
}

/**
* Tries to navigate back inside the Browser session and returns a Future with a Boolean
* which is true if the back navigation was successful.
*
* Only recommended to use if no switching of Tabs is used.
*
* Navigates back inside the currently active tab if possible. If that is not possible,
* checks if any Tab was added to the BrowserFragment before the currently active Tab,
* if so, the currently active Tab is closed and this Tab is set to active.
*
* @return ListenableFuture with a Boolean stating if back navigation was successful.
*/
@NonNull
public ListenableFuture<Boolean> tryNavigateBack() {
return CallbackToFutureAdapter.getFuture(completer -> {
mDelegate.tryNavigateBack(new RequestNavigationCallback(completer));
// Debug string.
return "Did navigate back Future";
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import com.google.common.util.concurrent.ListenableFuture;

import org.chromium.browserfragment.interfaces.IRequestNavigationCallback;
import org.chromium.browserfragment.interfaces.IBooleanCallback;
import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy;

/**
Expand All @@ -20,15 +20,15 @@
public class TabNavigationController {
private final ITabNavigationControllerProxy mTabNavigationControllerProxy;

private final class RequestNavigationCallback extends IRequestNavigationCallback.Stub {
private final class RequestNavigationCallback extends IBooleanCallback.Stub {
private CallbackToFutureAdapter.Completer<Boolean> mCompleter;

RequestNavigationCallback(CallbackToFutureAdapter.Completer<Boolean> completer) {
mCompleter = completer;
}

@Override
public void canNavigate(boolean possible) {
public void onResult(boolean possible) {
mCompleter.set(possible);
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

package org.chromium.browserfragment.interfaces;

oneway interface IRequestNavigationCallback {
void canNavigate(in boolean result) = 1;
oneway interface IBooleanCallback {
void onResult(in boolean result) = 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ package org.chromium.browserfragment.interfaces;

import android.os.Bundle;
import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegateClient;
import org.chromium.browserfragment.interfaces.ITabCallback;
import org.chromium.browserfragment.interfaces.IBooleanCallback;
import org.chromium.browserfragment.interfaces.ITabObserverDelegate;
import org.chromium.browserfragment.interfaces.ITabProxy;
import org.chromium.browserfragment.interfaces.ITabCallback;

oneway interface IBrowserFragmentDelegate {
void setClient(in IBrowserFragmentDelegateClient client) = 1;
Expand All @@ -32,4 +33,5 @@ oneway interface IBrowserFragmentDelegate {
// Tab operations.
void getActiveTab(ITabCallback callback) = 14;
void setTabObserverDelegate(ITabObserverDelegate tabObserverDelegate) = 15;
void tryNavigateBack(IBooleanCallback callback) = 17;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@

package org.chromium.browserfragment.interfaces;

import org.chromium.browserfragment.interfaces.IRequestNavigationCallback;
import org.chromium.browserfragment.interfaces.IBooleanCallback;

oneway interface ITabNavigationControllerProxy {
void navigate(in String uri) = 1;
void goBack() = 2;
void goForward() = 3;
void canGoBack(IRequestNavigationCallback callback) = 4;
void canGoForward(IRequestNavigationCallback callback) = 5;
void canGoBack(IBooleanCallback callback) = 4;
void canGoForward(IBooleanCallback callback) = 5;

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy;

oneway interface ITabProxy {
void setActive() = 1;
void close() = 2;
}
56 changes: 56 additions & 0 deletions weblayer/public/java/org/chromium/weblayer/Browser.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,21 @@ public Set<Tab> getTabs() {
return Tab.getTabsInBrowser(this);
}

/**
* Returns a List of Tabs as saved in the native Browser.
*
* @return The Tabs.
*/
@NonNull
private int[] getTabIds() {
ThreadCheck.ensureOnUiThread();
try {
return mImpl.getTabIds();
} catch (RemoteException e) {
throw new APICallException(e);
}
}

/**
* Disposes a Tab. If {@link tab} is the active Tab, no Tab is made active. After this call
* {@link tab} should not be used.
Expand All @@ -268,6 +283,47 @@ public void destroyTab(@NonNull Tab tab) {
}
}

/**
* Navigates to the previous navigation across all tabs according to tabs in native Browser.
*/
void tryNavigateBack(@NonNull Callback<Boolean> callback) {
Tab activeTab = getActiveTab();
if (activeTab == null) {
callback.onResult(false);
return;
}
if (activeTab.dismissTransientUi()) {
callback.onResult(true);
return;
}
NavigationController controller = activeTab.getNavigationController();
if (controller.canGoBack()) {
controller.goBack();
callback.onResult(true);
return;
}
int[] tabIds = getTabIds();
if (tabIds.length > 1) {
Tab previousTab = null;
int activeTabId = activeTab.getId();
int prevId = -1;
for (int id : tabIds) {
if (id == activeTabId) {
previousTab = Tab.getTabById(prevId);
break;
}
prevId = id;
}
if (previousTab != null) {
activeTab.dispatchBeforeUnloadAndClose();
setActiveTab(previousTab);
callback.onResult(true);
return;
}
}
callback.onResult(false);
}

/**
* Adds a TabListCallback.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import android.view.SurfaceControlViewHost;
import android.view.WindowManager;

import org.chromium.browserfragment.interfaces.IBooleanCallback;
import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegate;
import org.chromium.browserfragment.interfaces.IBrowserFragmentDelegateClient;
import org.chromium.browserfragment.interfaces.ITabCallback;
Expand Down Expand Up @@ -154,4 +155,16 @@ public void onCleared() {
public void setTabObserverDelegate(ITabObserverDelegate tabObserverDelegate) {
mTabDelegate.setObserver(tabObserverDelegate);
}

@Override
public void tryNavigateBack(IBooleanCallback callback) {
mHandler.post(() -> {
mFragment.getBrowser().tryNavigateBack(didNavigate -> {
try {
callback.onResult(didNavigate);
} catch (RemoteException e) {
}
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import android.os.Looper;
import android.os.RemoteException;

import org.chromium.browserfragment.interfaces.IRequestNavigationCallback;
import org.chromium.browserfragment.interfaces.IBooleanCallback;
import org.chromium.browserfragment.interfaces.ITabNavigationControllerProxy;

class TabNavigationControllerProxy extends ITabNavigationControllerProxy.Stub {
Expand Down Expand Up @@ -41,20 +41,20 @@ public void goForward() {
}

@Override
public void canGoBack(IRequestNavigationCallback callback) {
public void canGoBack(IBooleanCallback callback) {
mHandler.post(() -> {
try {
callback.canNavigate(mNavigationController.canGoBack());
callback.onResult(mNavigationController.canGoBack());
} catch (RemoteException e) {
}
});
}

@Override
public void canGoForward(IRequestNavigationCallback callback) {
public void canGoForward(IBooleanCallback callback) {
mHandler.post(() -> {
try {
callback.canNavigate(mNavigationController.canGoForward());
callback.onResult(mNavigationController.canGoForward());
} catch (RemoteException e) {
}
});
Expand Down

0 comments on commit f56c90c

Please sign in to comment.