Files
cromite/build/patches/Enable-extension-in-incognito.patch
2026-05-19 10:48:25 +02:00

1543 lines
75 KiB
Diff

From: uazo <uazo@users.noreply.github.com>
Date: Thu, 20 Nov 2025 12:53:28 +0000
Subject: Enable extensions in incognito
Full activation of incognito mode in experimental extension
License: GPL-3.0-only - https://spdx.org/licenses/GPL-3.0-only.html
---
.../chrome/browser/ChromeTabbedActivity.java | 5 +
.../chrome/browser/app/ChromeActivity.java | 42 +++++-
.../CustomTabIntentDataProvider.java | 3 +
.../browser/tabmodel/TabModelJniBridge.java | 3 +-
.../tabmodel/TabModelSelectorBase.java | 14 ++
.../browser/toolbar/ToolbarManager.java | 8 +-
.../developer_private_functions.cc | 3 +-
.../browser/extensions/extension_tab_util.cc | 2 +-
.../tabmodel/IncognitoTabModelImpl.java | 10 +-
.../tabmodel/IncognitoTabModelObserver.java | 3 +
.../extensions/extension_actions_bridge.cc | 23 ++-
.../extensions/extension_actions_bridge.h | 4 +-
.../ui/extensions/ExtensionActionsBridge.java | 62 +++++++-
.../ui/extensions/ExtensionsMenuBridge.java | 103 ++++++++++---
.../extensions/ExtensionsToolbarBridge.java | 137 ++++++++++++------
.../ExtensionActionListCoordinator.java | 12 +-
.../ExtensionActionListMediator.java | 24 +--
.../extensions/ExtensionsMenuCoordinator.java | 14 +-
.../extensions/ExtensionsMenuMediator.java | 12 +-
.../ExtensionsToolbarCoordinator.java | 10 +-
.../ExtensionsToolbarCoordinatorImpl.java | 21 ++-
.../browser/toolbar/top/ToolbarPhone.java | 16 ++
.../browser_window/ChromeAndroidTaskImpl.java | 18 ++-
.../ChromeAndroidTaskFeature.java | 2 +-
components/tabs/impl/tab_collection.cc | 16 ++
components/tabs/impl/tab_strip_collection.cc | 4 +-
26 files changed, 449 insertions(+), 122 deletions(-)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -125,6 +125,7 @@ import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulator;
import org.chromium.chrome.browser.contextmenu.ChromeContextMenuPopulatorFactory;
import org.chromium.chrome.browser.cookies.CookiesFetcher;
import org.chromium.chrome.browser.crypto.CipherFactory;
+import org.chromium.chrome.browser.customtabs.CustomTabActivity;
import org.chromium.chrome.browser.data_sharing.DataSharingIntentUtils;
import org.chromium.chrome.browser.data_sharing.DataSharingTabGroupUtils;
import org.chromium.chrome.browser.data_sharing.DataSharingTabManager;
@@ -4165,6 +4166,10 @@ public class ChromeTabbedActivity extends ChromeActivity implements PreAttachInt
coordinator.showExtensionsMenu();
RecordUserAction.record("MobileMenuExtensionsMenu");
} else if (id == R.id.manage_extensions_menu_id) {
+ if (getCurrentTabModel().isIncognito()) {
+ CustomTabActivity.showInfoPage(this, UrlConstants.CHROME_EXTENSIONS_URL);
+ return true;
+ }
LoadUrlParams params =
new LoadUrlParams(
UrlConstants.CHROME_EXTENSIONS_URL, PageTransition.AUTO_TOPLEVEL);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/ChromeActivity.java
@@ -190,6 +190,7 @@ import org.chromium.chrome.browser.tab.TabSelectionType;
import org.chromium.chrome.browser.tab.TabState;
import org.chromium.chrome.browser.tab.TabUtils;
import org.chromium.chrome.browser.tab_ui.TabContentManager;
+import org.chromium.chrome.browser.tabmodel.IncognitoTabModelObserver;
import org.chromium.chrome.browser.tabmodel.SupportedProfileType;
import org.chromium.chrome.browser.tabmodel.TabCreator;
import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -222,6 +223,9 @@ import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTaskTrackerFac
import org.chromium.chrome.browser.ui.device_lock.MissingDeviceLockLauncher;
import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController;
import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeUtils;
+import org.chromium.chrome.browser.ui.extensions.ExtensionActionsBridge;
+import org.chromium.chrome.browser.ui.extensions.ExtensionsMenuBridge;
+import org.chromium.chrome.browser.ui.extensions.ExtensionsToolbarBridge;
import org.chromium.chrome.browser.ui.extensions.windowing.ExtensionWindowControllerBridge;
import org.chromium.chrome.browser.ui.extensions.windowing.ExtensionWindowControllerBridgeFactory;
import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
@@ -1136,16 +1140,46 @@ public abstract class ChromeActivity extends AsyncInitializationActivity
// TODO(crbug.com/491791326): Handle multiple profiles for mobile.
Profile profile = tabModelSelector.getCurrentModel().getProfile();
assert profile != null;
- chromeAndroidTask.addFeature(
- new ChromeAndroidTaskFeatureKey(
- ExtensionWindowControllerBridge.class, profile, activityWindowAndroid),
- ExtensionWindowControllerBridgeFactory::create);
+ addFeatures(chromeAndroidTask, profile);
// 5. Make the ChromeAndroidTask available via OneshotSupplier.
mChromeAndroidTaskSupplier.set(chromeAndroidTask);
+
+ tabModelSelector.addIncognitoTabModelObserver(
+ new IncognitoTabModelObserver() {
+ @Override
+ public void onAssociateWithBrowserWindow() {
+ var chromeAndroidTask = getChromeAndroidTaskSupplier().get();
+ var profile = tabModelSelector.getModel(true).getProfile();
+ addFeatures(chromeAndroidTask, profile);
+ }
+
+ @Override
+ public void didDestroyed() {
+ }
+ });
}
}
+ private void addFeatures(ChromeAndroidTask task, Profile profile) {
+ task.addFeature(
+ new ChromeAndroidTaskFeatureKey(
+ ExtensionWindowControllerBridge.class, profile, getWindowAndroid()),
+ ExtensionWindowControllerBridgeFactory::create);
+
+ task.addFeature(
+ new ChromeAndroidTaskFeatureKey(ExtensionsToolbarBridge.class, profile, getWindowAndroid()),
+ () -> ExtensionsToolbarBridge.create(task, profile));
+
+ task.addFeature(
+ new ChromeAndroidTaskFeatureKey(ExtensionActionsBridge.class, profile, getWindowAndroid()),
+ () -> ExtensionActionsBridge.create(task, profile));
+
+ task.addFeature(
+ new ChromeAndroidTaskFeatureKey(ExtensionsMenuBridge.class, profile, getWindowAndroid()),
+ () -> ExtensionsMenuBridge.create(task, profile));
+ }
+
/** Returns an {@link OneshotSupplier} for {@link ChromeAndroidTask}. */
protected final OneshotSupplier<ChromeAndroidTask> getChromeAndroidTaskSupplier() {
return mChromeAndroidTaskSupplier;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java
@@ -349,6 +349,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
private final boolean mEnableUrlBarHiding;
private boolean mInteractWithBackground;
+ private boolean mIsExtension = false;
private List<CustomButtonParams> mCustomButtonParams;
private @Nullable Drawable mCloseButtonIcon;
private final boolean mIsCloseButtonEnabled;
@@ -754,6 +755,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
mSideSheetRoundedCornersPosition =
getActivitySideSheetRoundedCornersPositionFromIntent(intent);
+ mIsExtension = getUrlToLoad().startsWith(UrlConstants.CHROME_EXTENSIONS_URL);
logCustomTabFeatures(intent, colorScheme);
String packageName = getClientPackageNameFromSessionOrCallingActivity(mIntent, mSession);
RecordHistogram.recordBooleanHistogram(
@@ -1408,6 +1410,7 @@ public class CustomTabIntentDataProvider extends BrowserServicesIntentDataProvid
@Override
public @CustomTabProfileType int getCustomTabMode() {
+ if (mIsExtension) return CustomTabProfileType.REGULAR;
return AlwaysIncognitoLinkInterceptor.isAlwaysIncognito()
? CustomTabProfileType.INCOGNITO
: (ChromeFeatureList.sMayLaunchurlUsesSeparateStoragePartition.isEnabled()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelJniBridge.java
@@ -145,8 +145,7 @@ public abstract class TabModelJniBridge implements TabModelInternal {
@Override
public void dissociateWithBrowserWindow() {
- assert mNativeAndroidBrowserWindow != 0;
-
+ if (mNativeTabModelJniBridge == 0 || mNativeAndroidBrowserWindow == 0) return;
TabModelJniBridgeJni.get().dissociateWithBrowserWindow(mNativeTabModelJniBridge);
mNativeAndroidBrowserWindow = 0;
}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelSelectorBase.java
@@ -488,6 +488,20 @@ public abstract class TabModelSelectorBase
}
}
+ @Override
+ public void onAssociateWithBrowserWindow() {
+ for (IncognitoTabModelObserver observer : mIncognitoObservers) {
+ observer.onAssociateWithBrowserWindow();
+ }
+ }
+
+ @Override
+ public void didDestroyed() {
+ for (IncognitoTabModelObserver observer : mIncognitoObservers) {
+ observer.didDestroyed();
+ }
+ }
+
@Override
public void didBecomeEmpty() {
for (IncognitoTabModelObserver observer : mIncognitoObservers) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -80,6 +80,7 @@ import org.chromium.chrome.browser.compositor.layouts.Layout;
import org.chromium.chrome.browser.compositor.layouts.LayoutManagerImpl;
import org.chromium.chrome.browser.compositor.overlay_panel.OverlayPanelManager.OverlayPanelManagerObserver;
import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
+import org.chromium.chrome.browser.customtabs.CustomTabActivity;
import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar;
import org.chromium.chrome.browser.data_sharing.DataSharingTabManager;
import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils;
@@ -2524,11 +2525,14 @@ public class ToolbarManager
task,
assertNonNull(mTabModelSelector.getCurrentModel().getProfile()),
mActivityTabProvider.asObservable(),
- mTabCreatorManager.getTabCreator(false),
+ mTabCreatorManager.getTabCreator(AlwaysIncognitoLinkInterceptor.isAlwaysIncognito()),
getBrowsingModeThemeColorProvider(),
mToolbarLayout,
contextMenuPopulatorFactory,
- selectionDropdownMenuDelegate);
+ selectionDropdownMenuDelegate,
+ AlwaysIncognitoLinkInterceptor.isAlwaysIncognito()
+ ? (url) -> CustomTabActivity.showInfoPage(mActivity, url)
+ : null);
if (mExtensionsToolbarCoordinator != null) {
mToolbar.setExtensionsToolbarCoordinator(mExtensionsToolbarCoordinator);
}
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_functions.cc b/chrome/browser/extensions/api/developer_private/developer_private_functions.cc
--- a/chrome/browser/extensions/api/developer_private/developer_private_functions.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_functions.cc
@@ -1756,7 +1756,8 @@ DeveloperPrivateDismissSafetyHubExtensionsMenuNotificationFunction::Run() {
}
Profile* profile = Profile::FromBrowserContext(browser_context());
- SafetyHubMenuNotificationServiceFactory::GetForProfile(profile)
+ if (auto* menu_notification_service_factory = SafetyHubMenuNotificationServiceFactory::GetForProfile(profile))
+ menu_notification_service_factory
->DismissActiveNotificationOfModule(
safety_hub::SafetyHubModuleType::EXTENSIONS);
return RespondNow(NoArguments());
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -1150,7 +1150,7 @@ bool ExtensionTabUtil::OpenOptionsPageFromWebContents(
if (!url) {
return false;
}
- const bool open_in_tab = ShouldOpenInTab(extension);
+ const bool open_in_tab = false; //ShouldOpenInTab(extension);
BrowserWindowInterface* browser =
browser_window_util::GetBrowserForTabContents(*web_contents);
CHECK(browser);
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java
--- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImpl.java
@@ -155,7 +155,7 @@ class IncognitoTabModelImpl implements IncognitoTabModelInternal {
}
for (IncognitoTabModelObserver observer : mIncognitoObservers) {
- observer.didBecomeEmpty();
+ observer.didDestroyed();
}
mDelegateModel
@@ -166,6 +166,10 @@ class IncognitoTabModelImpl implements IncognitoTabModelInternal {
mCurrentTabSupplier.set(null);
mTabCountSupplier.set(0);
+ for (IncognitoTabModelObserver observer : mIncognitoObservers) {
+ observer.didBecomeEmpty();
+ }
+
mDelegateModel = EmptyTabModel.getInstance(true);
for (Callback<TabModelInternal> delegateModelObserver : mDelegateModelObservers) {
delegateModelObserver.onResult(mDelegateModel);
@@ -203,6 +207,10 @@ class IncognitoTabModelImpl implements IncognitoTabModelInternal {
assert mNativeAndroidBrowserWindow == 0;
mNativeAndroidBrowserWindow = nativeAndroidBrowserWindow;
mDelegateModel.associateWithBrowserWindow(nativeAndroidBrowserWindow);
+
+ for (IncognitoTabModelObserver observer : mIncognitoObservers) {
+ observer.onAssociateWithBrowserWindow();
+ }
}
@Override
diff --git a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelObserver.java b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelObserver.java
--- a/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelObserver.java
+++ b/chrome/browser/tabmodel/android/java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelObserver.java
@@ -33,4 +33,7 @@ public interface IncognitoTabModelObserver {
/** Called when the last tab of the {@link IncognitoTabModel} is closed. */
default void didBecomeEmpty() {}
+
+ default void onAssociateWithBrowserWindow() {}
+ default void didDestroyed() {}
}
diff --git a/chrome/browser/ui/android/extensions/extension_actions_bridge.cc b/chrome/browser/ui/android/extensions/extension_actions_bridge.cc
--- a/chrome/browser/ui/android/extensions/extension_actions_bridge.cc
+++ b/chrome/browser/ui/android/extensions/extension_actions_bridge.cc
@@ -12,6 +12,8 @@
#include "base/task/thread_pool.h"
#include "chrome/browser/extensions/extension_management.h"
#include "chrome/browser/profiles/profile.h"
+#include "extensions/browser/process_manager.h"
+#include "extensions/browser/process_manager_factory.h"
#include "chrome/browser/ui/browser_window/public/browser_window_interface.h"
#include "ui/events/android/key_event_android.h"
@@ -23,10 +25,9 @@
namespace extensions {
ExtensionActionsBridge::ExtensionActionsBridge(
- BrowserWindowInterface* browser,
+ Profile* profile,
const base::android::JavaRef<jobject>& java_object)
- : browser_(browser),
- profile_(browser->GetProfile()),
+ : profile_(profile),
java_object_(java_object) {}
ExtensionActionsBridge::~ExtensionActionsBridge() = default;
@@ -51,6 +52,16 @@ void ExtensionActionsBridge::ClearExtensionData(JNIEnv* env) {
install_directory, install_updacked_directory));
}
+void ExtensionActionsBridge::CloseBackgroundHosts(JNIEnv* env) {
+ extensions::ProcessManager* manager =
+ extensions::ProcessManagerFactory::GetForBrowserContextIfExists(profile_);
+ if (manager) {
+ manager->CloseBackgroundHosts();
+ ProcessManager::Get(profile_->GetOriginalProfile())
+ ->MaybeCreateStartupBackgroundHosts();
+ }
+}
+
void ExtensionActionsBridge::Destroy(JNIEnv* env) {
delete this;
}
@@ -58,11 +69,9 @@ void ExtensionActionsBridge::Destroy(JNIEnv* env) {
static int64_t JNI_ExtensionActionsBridge_Init(
JNIEnv* env,
const base::android::JavaRef<jobject>& java_object,
- int64_t j_browser_window_interface) {
- BrowserWindowInterface* browser =
- reinterpret_cast<BrowserWindowInterface*>(j_browser_window_interface);
+ Profile* profile) {
return reinterpret_cast<int64_t>(
- new ExtensionActionsBridge(browser, java_object));
+ new ExtensionActionsBridge(profile, java_object));
}
static bool JNI_ExtensionActionsBridge_ExtensionsEnabled(JNIEnv* env,
diff --git a/chrome/browser/ui/android/extensions/extension_actions_bridge.h b/chrome/browser/ui/android/extensions/extension_actions_bridge.h
--- a/chrome/browser/ui/android/extensions/extension_actions_bridge.h
+++ b/chrome/browser/ui/android/extensions/extension_actions_bridge.h
@@ -19,7 +19,7 @@ namespace extensions {
// This bridge is created and owned by Java UI code.
class ExtensionActionsBridge {
public:
- ExtensionActionsBridge(BrowserWindowInterface* browser,
+ ExtensionActionsBridge(Profile* profile,
const base::android::JavaRef<jobject>& java_object);
ExtensionActionsBridge(const ExtensionActionsBridge&) = delete;
ExtensionActionsBridge& operator=(const ExtensionActionsBridge&) = delete;
@@ -27,10 +27,10 @@ class ExtensionActionsBridge {
// JNI implementations.
void ClearExtensionData(JNIEnv* env);
+ void CloseBackgroundHosts(JNIEnv* env);
void Destroy(JNIEnv* env);
private:
- const raw_ptr<BrowserWindowInterface> browser_;
const raw_ptr<Profile> profile_;
const base::android::ScopedJavaGlobalRef<jobject> java_object_;
};
diff --git a/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionActionsBridge.java b/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionActionsBridge.java
--- a/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionActionsBridge.java
+++ b/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionActionsBridge.java
@@ -15,21 +15,64 @@ import org.chromium.build.annotations.Nullable;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask;
+import android.graphics.Rect;
+import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTaskFeature;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.base.Log;
+
/** A JNI bridge to interact with extension actions for the toolbar. */
@NullMarked
@JNINamespace("extensions")
-public class ExtensionActionsBridge implements Destroyable {
+public class ExtensionActionsBridge implements ChromeAndroidTaskFeature {
private final @Nullable LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
private long mNativeExtensionActionsBridge;
- public ExtensionActionsBridge(ChromeAndroidTask task, Profile profile) {
+ private static ExtensionActionsBridge currentExtensionActionsBridge;
+ private final Profile mProfile;
+ private final ChromeAndroidTask mTask;
+
+ private ExtensionActionsBridge(ChromeAndroidTask task, Profile profile) {
+ mTask = task;
+ mProfile = profile;
+ }
+
+ @Override
+ public void onAddedToTask(long nativeBrowserWindowPtr) {
mNativeExtensionActionsBridge =
ExtensionActionsBridgeJni.get()
- .init(this, task.getOrCreateNativeBrowserWindowPtr(profile));
+ .init(this, mProfile);
}
@Override
- public void destroy() {
+ public void onFeatureRemoved() {
+ destroy();
+ }
+
+ @Override
+ public void onTaskBoundsChanged(Rect newBoundsInDp) {}
+
+ @Override
+ public void onTaskFocusChanged(boolean hasFocus) {}
+
+ @Override
+ public void onTabModelSelected(ChromeAndroidTask task, TabModel tabModel) {
+ if (mTask == task && tabModel.getProfile() == mProfile) {
+ Instance().mNativeExtensionActionsBridge = mNativeExtensionActionsBridge;
+ }
+ }
+
+ public static ExtensionActionsBridge Instance() {
+ if (currentExtensionActionsBridge == null)
+ currentExtensionActionsBridge = new ExtensionActionsBridge(null, null);
+ return currentExtensionActionsBridge;
+ }
+
+ public static ExtensionActionsBridge create(ChromeAndroidTask task, Profile profile) {
+ return new ExtensionActionsBridge(task, profile);
+ }
+
+ void destroy() {
+ closeBackgroundHosts();
assert mNativeExtensionActionsBridge != 0;
ExtensionActionsBridgeJni.get().destroy(mNativeExtensionActionsBridge);
mNativeExtensionActionsBridge = 0;
@@ -46,17 +89,24 @@ public class ExtensionActionsBridge implements Destroyable {
}
public void clearExtensionData() {
- ExtensionActionsBridgeJni.get().clearExtensionData(mNativeExtensionActionsBridge);
+ ExtensionActionsBridgeJni.get().clearExtensionData(Instance().mNativeExtensionActionsBridge);
+ }
+
+ private void closeBackgroundHosts() {
+ if (mProfile.isIncognitoBranded())
+ ExtensionActionsBridgeJni.get().closeBackgroundHosts(mNativeExtensionActionsBridge);
}
@NativeMethods
public interface Natives {
boolean extensionsEnabled(@JniType("Profile*") Profile profile);
- long init(ExtensionActionsBridge bridge, long browserWindowInterfacePtr);
+ long init(ExtensionActionsBridge bridge, @JniType("Profile*") Profile profile);
void clearExtensionData(long nativeExtensionActionsBridge);
+ void closeBackgroundHosts(long nativeExtensionActionsBridge);
+
void destroy(long nativeExtensionActionsBridge);
}
}
diff --git a/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsMenuBridge.java b/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsMenuBridge.java
--- a/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsMenuBridge.java
+++ b/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsMenuBridge.java
@@ -20,24 +20,76 @@ import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask;
import java.util.List;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import java.util.Map;
+import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTaskFeature;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.base.Log;
+
/** A JNI bridge that provides native extensions menu data to the Java UI. */
@NullMarked
@JNINamespace("extensions")
-public class ExtensionsMenuBridge implements Destroyable {
+public class ExtensionsMenuBridge implements ChromeAndroidTaskFeature {
private final @Nullable LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
private long mNativeExtensionsMenuDelegateAndroid;
- private final Observer mObserver;
+ private Observer mObserver;
+
+ private static ExtensionsMenuBridge currentExtensionsMenuBridge;
+ private final Map<ChromeAndroidTask, Observer> mObservers = new ArrayMap<>();
+ private final ChromeAndroidTask mTask;
+ private final Profile mProfile;
+
+ private ExtensionsMenuBridge(ChromeAndroidTask task, Profile profile) {
+ mObserver = null;
+ mProfile = profile;
+ mTask = task;
+ }
- public ExtensionsMenuBridge(ChromeAndroidTask task, Profile profile, Observer observer) {
- mObserver = observer;
+ public static ExtensionsMenuBridge Instance() {
+ if (currentExtensionsMenuBridge == null)
+ currentExtensionsMenuBridge = new ExtensionsMenuBridge(null, null);
+ return currentExtensionsMenuBridge;
+ }
+
+ public static ExtensionsMenuBridge create(ChromeAndroidTask task, Profile profile) {
+ return new ExtensionsMenuBridge(task, profile);
+ }
+
+ public void setObserver(ChromeAndroidTask task, Observer observer) {
+ Instance().mObservers.put(task, observer);
+ Instance().mObserver = observer;
+ }
+
+ @Override
+ public void onAddedToTask(long nativeBrowserWindowPtr) {
mNativeExtensionsMenuDelegateAndroid =
ExtensionsMenuBridgeJni.get()
- .init(this, task.getOrCreateNativeBrowserWindowPtr(profile));
+ .init(this, mTask.getOrCreateNativeBrowserWindowPtr(mProfile));
}
@Override
- public void destroy() {
+ public void onFeatureRemoved() {
+ Instance().mObservers.remove(mTask);
+ destroy();
+ }
+
+ @Override
+ public void onTaskBoundsChanged(Rect newBoundsInDp) {}
+
+ @Override
+ public void onTaskFocusChanged(boolean hasFocus) {}
+
+ @Override
+ public void onTabModelSelected(ChromeAndroidTask task, TabModel tabModel) {
+ if (mTask == task && tabModel.getProfile() == mProfile) {
+ Instance().mNativeExtensionsMenuDelegateAndroid = mNativeExtensionsMenuDelegateAndroid;
+ Instance().mObserver = Instance().mObservers.get(mTask);
+ }
+ }
+
+ private void destroy() {
assert mNativeExtensionsMenuDelegateAndroid != 0;
ExtensionsMenuBridgeJni.get().destroy(mNativeExtensionsMenuDelegateAndroid);
mNativeExtensionsMenuDelegateAndroid = 0;
@@ -47,12 +99,12 @@ public class ExtensionsMenuBridge implements Destroyable {
/** Returns the icon for the given extension index from native. */
public @Nullable Bitmap getActionIcon(int actionIndex) {
return ExtensionsMenuBridgeJni.get()
- .getActionIcon(mNativeExtensionsMenuDelegateAndroid, actionIndex);
+ .getActionIcon(Instance().mNativeExtensionsMenuDelegateAndroid, actionIndex);
}
/** Returns the list of menu entries with their states from native. */
public List<ExtensionsMenuTypes.MenuEntryState> getMenuEntries() {
- return ExtensionsMenuBridgeJni.get().getMenuEntries(mNativeExtensionsMenuDelegateAndroid);
+ return ExtensionsMenuBridgeJni.get().getMenuEntries(Instance().mNativeExtensionsMenuDelegateAndroid);
}
/**
@@ -62,12 +114,12 @@ public class ExtensionsMenuBridge implements Destroyable {
*/
public ExtensionsMenuTypes.MenuEntryState getMenuEntry(int actionIndex) {
return ExtensionsMenuBridgeJni.get()
- .getMenuEntry(mNativeExtensionsMenuDelegateAndroid, actionIndex);
+ .getMenuEntry(Instance().mNativeExtensionsMenuDelegateAndroid, actionIndex);
}
/** Returns the site settings state from native. */
public ExtensionsMenuTypes.SiteSettingsState getSiteSettingsState() {
- return ExtensionsMenuBridgeJni.get().getSiteSettings(mNativeExtensionsMenuDelegateAndroid);
+ return ExtensionsMenuBridgeJni.get().getSiteSettings(Instance().mNativeExtensionsMenuDelegateAndroid);
}
/**
@@ -118,12 +170,12 @@ public class ExtensionsMenuBridge implements Destroyable {
/** Called when the reload page button is clicked. */
public void onReloadPageButtonClicked() {
ExtensionsMenuBridgeJni.get()
- .onReloadPageButtonClicked(mNativeExtensionsMenuDelegateAndroid);
+ .onReloadPageButtonClicked(Instance().mNativeExtensionsMenuDelegateAndroid);
}
/** Returns whether the native menu model is ready. */
public boolean isReady() {
- return ExtensionsMenuBridgeJni.get().isReady(mNativeExtensionsMenuDelegateAndroid);
+ return ExtensionsMenuBridgeJni.get().isReady(Instance().mNativeExtensionsMenuDelegateAndroid);
}
/**
@@ -133,7 +185,10 @@ public class ExtensionsMenuBridge implements Destroyable {
*/
@CalledByNative
public void onActionAdded(int actionIndex) {
- mObserver.onActionAdded(actionIndex);
+ if (Instance().mNativeExtensionsMenuDelegateAndroid != mNativeExtensionsMenuDelegateAndroid) return;
+ if (Instance().mObserver != null) {
+ Instance().mObserver.onActionAdded(actionIndex);
+ }
}
/**
@@ -144,7 +199,10 @@ public class ExtensionsMenuBridge implements Destroyable {
*/
@CalledByNative
public void onActionIconUpdated(int actionIndex) {
- mObserver.onActionIconUpdated(actionIndex);
+ if (Instance().mNativeExtensionsMenuDelegateAndroid != mNativeExtensionsMenuDelegateAndroid) return;
+ if (Instance().mObserver != null) {
+ Instance().mObserver.onActionIconUpdated(actionIndex);
+ }
}
/**
@@ -155,7 +213,10 @@ public class ExtensionsMenuBridge implements Destroyable {
*/
@CalledByNative
public void onActionRemoved(int actionIndex) {
- mObserver.onActionRemoved(actionIndex);
+ if (Instance().mNativeExtensionsMenuDelegateAndroid != mNativeExtensionsMenuDelegateAndroid) return;
+ if (Instance().mObserver != null) {
+ Instance().mObserver.onActionRemoved(actionIndex);
+ }
}
/**
@@ -166,7 +227,10 @@ public class ExtensionsMenuBridge implements Destroyable {
*/
@CalledByNative
public void onActionUpdated(int actionIndex) {
- mObserver.onActionUpdated(actionIndex);
+ if (Instance().mNativeExtensionsMenuDelegateAndroid != mNativeExtensionsMenuDelegateAndroid) return;
+ if (Instance().mObserver != null) {
+ Instance().mObserver.onActionUpdated(actionIndex);
+ }
}
/**
@@ -175,13 +239,14 @@ public class ExtensionsMenuBridge implements Destroyable {
*/
@CalledByNative
public void onReady() {
- mObserver.onReady();
+ //Instance().mObserver.onReady();
}
@CalledByNative
private void onModelChanged() {
- if (mObserver != null) {
- mObserver.onModelChanged();
+ if (Instance().mNativeExtensionsMenuDelegateAndroid != mNativeExtensionsMenuDelegateAndroid) return;
+ if (Instance().mObserver != null) {
+ Instance().mObserver.onModelChanged();
}
}
diff --git a/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsToolbarBridge.java b/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsToolbarBridge.java
--- a/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsToolbarBridge.java
+++ b/chrome/browser/ui/android/extensions/java/src/org/chromium/chrome/browser/ui/extensions/ExtensionsToolbarBridge.java
@@ -27,10 +27,17 @@ import org.chromium.content_public.browser.WebContents;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import java.util.Map;
+import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTaskFeature;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.base.Log;
+
/** A JNI bridge to interact with extension actions for the toolbar. */
@NullMarked
@JNINamespace("extensions")
-public class ExtensionsToolbarBridge implements Destroyable {
+public class ExtensionsToolbarBridge implements ChromeAndroidTaskFeature {
// TODO(crbug.com/423483658): Consider moving ExtensionsMenuButtonState and related types
// (e.g., RequestAccessButtonParams) into a new ExtensionControls.java file.
@IntDef({
@@ -48,21 +55,61 @@ public class ExtensionsToolbarBridge implements Destroyable {
private final @Nullable LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
private long mNativeExtensionsToolbarAndroid;
private final ObserverList<Observer> mObservers = new ObserverList<>();
- private final Profile mProfile;
+ private Profile mProfile;
// The delegate is set via a setter because of a bidirectional dependency
// with {@code ExtensionActionListMediator}.
private @Nullable Delegate mDelegate;
- public ExtensionsToolbarBridge(ChromeAndroidTask task, Profile profile) {
- mProfile = profile;
+ private final ChromeAndroidTask mTask;
+
+ private static ExtensionsToolbarBridge toolbarBridgeInstance;
+ private final Map<ChromeAndroidTask, Delegate> mDelegates = new ArrayMap<>();
+
+ @Override
+ public void onAddedToTask(long nativeBrowserWindowPtr) {
mNativeExtensionsToolbarAndroid =
ExtensionsToolbarBridgeJni.get()
- .init(this, task.getOrCreateNativeBrowserWindowPtr(profile));
+ .init(this, mTask.getOrCreateNativeBrowserWindowPtr(mProfile));
+ }
+
+ @Override
+ public void onFeatureRemoved() {
+ //Instance().mDelegates.remove(mTask);
+ destroy();
}
@Override
- public void destroy() {
+ public void onTaskBoundsChanged(Rect newBoundsInDp) {}
+
+ @Override
+ public void onTaskFocusChanged(boolean hasFocus) {}
+
+ @Override
+ public void onTabModelSelected(ChromeAndroidTask task, TabModel tabModel) {
+ if (mTask == task && tabModel.getProfile() == mProfile) {
+ Instance().mNativeExtensionsToolbarAndroid = mNativeExtensionsToolbarAndroid;
+ Instance().mDelegate = Instance().mDelegates.get(mTask);
+ Instance().mProfile = mProfile;
+ }
+ }
+
+ public static ExtensionsToolbarBridge Instance() {
+ if (toolbarBridgeInstance == null)
+ toolbarBridgeInstance = new ExtensionsToolbarBridge(null, null);
+ return toolbarBridgeInstance;
+ }
+
+ private ExtensionsToolbarBridge(ChromeAndroidTask task, Profile profile) {
+ mTask = task;
+ mProfile = profile;
+ }
+
+ public static ExtensionsToolbarBridge create(ChromeAndroidTask task, Profile profile) {
+ return new ExtensionsToolbarBridge(task, profile);
+ }
+
+ private void destroy() {
assert mNativeExtensionsToolbarAndroid != 0;
ExtensionsToolbarBridgeJni.get().destroy(mNativeExtensionsToolbarAndroid);
mNativeExtensionsToolbarAndroid = 0;
@@ -70,27 +117,30 @@ public class ExtensionsToolbarBridge implements Destroyable {
}
public void addObserver(Observer observer) {
- mObservers.addObserver(observer);
+ Instance().mObservers.addObserver(observer);
}
public void removeObserver(Observer observer) {
- mObservers.removeObserver(observer);
+ Instance().mObservers.removeObserver(observer);
}
- public void setDelegate(@Nullable Delegate delegate) {
- mDelegate = delegate;
+ public void setDelegate(ChromeAndroidTask task, @Nullable Delegate delegate) {
+ if (delegate == null) return;
+ Instance().mDelegates.put(task, delegate);
+ Instance().mDelegate = delegate;
}
@Nullable
public ExtensionAction getAction(String actionId, @Nullable WebContents webContents) {
- if (mProfile.shutdownStarted()) {
+ assert Instance().mNativeExtensionsToolbarAndroid != 0;
+ if (Instance().mProfile.shutdownStarted()) {
// TODO(crbug.com/459079170): This is to prevent tests from breaking. {@code
// ExtensionsToolbarCoordinatorImpl} should ideally be destroyed following {@code
// ChromeAndroidTask}'s destruction, and it is currently being worked on.
return null;
}
return ExtensionsToolbarBridgeJni.get()
- .getAction(mNativeExtensionsToolbarAndroid, actionId, webContents);
+ .getAction(Instance().mNativeExtensionsToolbarAndroid, actionId, webContents);
}
@Nullable
@@ -106,9 +156,10 @@ public class ExtensionsToolbarBridge implements Destroyable {
// ChromeAndroidTask}'s destruction, and it is currently being worked on.
return null;
}
+ assert Instance().mNativeExtensionsToolbarAndroid != 0;
return ExtensionsToolbarBridgeJni.get()
.getIcon(
- mNativeExtensionsToolbarAndroid,
+ Instance().mNativeExtensionsToolbarAndroid,
actionId,
webContents,
canvasWidthDp,
@@ -127,52 +178,52 @@ public class ExtensionsToolbarBridge implements Destroyable {
}
public String[] getPinnedActionIds() {
- if (mProfile.shutdownStarted()) {
+ if (Instance().mProfile.shutdownStarted()) {
// TODO(crbug.com/459079170): This is to prevent tests from breaking. {@code
// ExtensionsToolbarCoordinatorImpl} should ideally be destroyed following {@code
// ChromeAndroidTask}'s destruction, and it is currently being worked on.
return new String[0];
}
- return ExtensionsToolbarBridgeJni.get().getPinnedActionIds(mNativeExtensionsToolbarAndroid);
+ return ExtensionsToolbarBridgeJni.get().getPinnedActionIds(Instance().mNativeExtensionsToolbarAndroid);
}
public boolean isActionDraggable(String actionId) {
- if (mProfile.shutdownStarted()) {
+ if (Instance().mProfile.shutdownStarted()) {
// TODO(crbug.com/459079170): This is to prevent tests from breaking. {@code
// ExtensionsToolbarCoordinatorImpl} should ideally be destroyed following {@code
// ChromeAndroidTask}'s destruction, and it is currently being worked on.
return false;
}
return ExtensionsToolbarBridgeJni.get()
- .isActionDraggable(mNativeExtensionsToolbarAndroid, actionId);
+ .isActionDraggable(Instance().mNativeExtensionsToolbarAndroid, actionId);
}
public void executeUserAction(String actionId, @InvocationSource int source) {
- if (mProfile.shutdownStarted()) {
+ if (Instance().mProfile.shutdownStarted()) {
// TODO(crbug.com/459079170): This is to prevent tests from breaking. {@code
// ExtensionsToolbarCoordinatorImpl} should ideally be destroyed following {@code
// ChromeAndroidTask}'s destruction, and it is currently being worked on.
return;
}
ExtensionsToolbarBridgeJni.get()
- .executeUserAction(mNativeExtensionsToolbarAndroid, actionId, source);
+ .executeUserAction(Instance().mNativeExtensionsToolbarAndroid, actionId, source);
}
public void movePinnedAction(String actionId, int targetIndex) {
- if (mProfile.shutdownStarted()) {
+ if (Instance().mProfile.shutdownStarted()) {
// TODO(crbug.com/459079170): This is to prevent tests from breaking. {@code
// ExtensionsToolbarCoordinatorImpl} should ideally be destroyed following {@code
// ChromeAndroidTask}'s destruction, and it is currently being worked on.
return;
}
ExtensionsToolbarBridgeJni.get()
- .movePinnedAction(mNativeExtensionsToolbarAndroid, actionId, targetIndex);
+ .movePinnedAction(Instance().mNativeExtensionsToolbarAndroid, actionId, targetIndex);
}
public @ExtensionsMenuButtonState int getExtensionsMenuButtonState(WebContents webContents) {
- assert mNativeExtensionsToolbarAndroid != 0;
+ assert Instance().mNativeExtensionsToolbarAndroid != 0;
return ExtensionsToolbarBridgeJni.get()
- .getExtensionsMenuButtonState(mNativeExtensionsToolbarAndroid, webContents);
+ .getExtensionsMenuButtonState(Instance().mNativeExtensionsToolbarAndroid, webContents);
}
public void onRequestAccessButtonClicked(WebContents webContents) {
@@ -184,10 +235,10 @@ public class ExtensionsToolbarBridge implements Destroyable {
}
public RequestAccessButtonParams getRequestAccessButtonParams(WebContents webContents) {
- assert mNativeExtensionsToolbarAndroid != 0;
+ assert Instance().mNativeExtensionsToolbarAndroid != 0;
RequestAccessButtonParams params =
ExtensionsToolbarBridgeJni.get()
- .getRequestAccessButtonParams(mNativeExtensionsToolbarAndroid, webContents);
+ .getRequestAccessButtonParams(Instance().mNativeExtensionsToolbarAndroid, webContents);
assert params != null;
return params;
}
@@ -201,29 +252,29 @@ public class ExtensionsToolbarBridge implements Destroyable {
@CalledByNative
public void triggerPopup(@JniType("std::string") String actionId, long nativeHostPtr) {
// {@link mDelegate} should be set in {@code ExtensionActionListMediator}'s constructor.
- assert mDelegate != null;
+ assert Instance().mDelegate != null;
- mDelegate.triggerPopup(actionId, nativeHostPtr);
+ Instance().mDelegate.triggerPopup(actionId, nativeHostPtr);
}
@CalledByNative
void showContextMenu(@JniType("std::string") String actionId) {
// {@link mDelegate} should be set in {@code ExtensionActionListMediator}'s constructor.
- assert mDelegate != null;
+ assert Instance().mDelegate != null;
- mDelegate.showContextMenu(actionId);
+ Instance().mDelegate.showContextMenu(actionId);
}
@CalledByNative
public void onRequestAccessButtonParamsChanged() {
- for (Observer observer : mObservers) {
+ for (Observer observer : Instance().mObservers) {
observer.onRequestAccessButtonParamsChanged();
}
}
@CalledByNative
public void onToolbarControlStateUpdated() {
- for (Observer observer : mObservers) {
+ for (Observer observer : Instance().mObservers) {
observer.onToolbarControlStateUpdated();
}
}
@@ -231,65 +282,65 @@ public class ExtensionsToolbarBridge implements Destroyable {
@CalledByNative
public boolean hasPoppedOutAction() {
// {@link mDelegate} should be set in {@code ExtensionActionListMediator}'s constructor.
- assert mDelegate != null;
+ assert Instance().mDelegate != null;
- return mDelegate.hasPoppedOutAction();
+ return Instance().mDelegate.hasPoppedOutAction();
}
@CalledByNative
public void hideActivePopup() {
// {@link mDelegate} should be set in {@code ExtensionActionListMediator}'s constructor.
- assert mDelegate != null;
+ assert Instance().mDelegate != null;
- mDelegate.hideActivePopup();
+ Instance().mDelegate.hideActivePopup();
}
@CalledByNative
public boolean hasActivePopup() {
// {@link mDelegate} should be set in {@code ExtensionActionListMediator}'s constructor.
- assert mDelegate != null;
+ assert Instance().mDelegate != null;
- return mDelegate.hasActivePopup();
+ return Instance().mDelegate.hasActivePopup();
}
@CalledByNative
public void onActionsInitialized() {
- for (Observer observer : mObservers) {
+ for (Observer observer : Instance().mObservers) {
observer.onActionsInitialized();
}
}
@CalledByNative
public void onActionAdded(@JniType("std::string") String actionId) {
- for (Observer observer : mObservers) {
+ for (Observer observer : Instance().mObservers) {
observer.onActionAdded(actionId);
}
}
@CalledByNative
public void onActionRemoved(@JniType("std::string") String actionId) {
- for (Observer observer : mObservers) {
+ for (Observer observer : Instance().mObservers) {
observer.onActionRemoved(actionId);
}
}
@CalledByNative
public void onActionUpdated(@JniType("std::string") String actionId) {
- for (Observer observer : mObservers) {
+ for (Observer observer : Instance().mObservers) {
observer.onActionUpdated(actionId);
}
}
@CalledByNative
public void onPinnedActionsChanged() {
- for (Observer observer : mObservers) {
+ for (Observer observer : Instance().mObservers) {
observer.onPinnedActionsChanged();
}
}
@CalledByNative
public void onActiveWebContentsChanged(WebContents webContents) {
- for (Observer observer : mObservers) {
+ for (Observer observer : Instance().mObservers) {
observer.onActiveWebContentsChanged(webContents);
}
}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListCoordinator.java
@@ -44,17 +44,20 @@ public class ExtensionActionListCoordinator implements Destroyable {
private final Context mContext;
private final ExtensionActionListRecyclerView mContainer;
+ private final ListMenuButton mExtensionsMenuButton;
private final ModelList mModels;
private final ExtensionActionListMediator mMediator;
private final DragReorderableRecyclerViewAdapter mAdapter;
@Nullable private final LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this);
private final RecyclerViewDelegate mRecyclerViewDelegate = new RecyclerViewDelegate();
+ public final ExtensionsToolbarBridge mExtensionsToolbarBridge;
private boolean mIsDragging;
public ExtensionActionListCoordinator(
Context context,
ExtensionActionListRecyclerView container,
+ ListMenuButton extensionsMenuButton,
WindowAndroid windowAndroid,
ChromeAndroidTask task,
Profile profile,
@@ -65,6 +68,8 @@ public class ExtensionActionListCoordinator implements Destroyable {
@Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate) {
mContext = context;
mContainer = container;
+ mExtensionsMenuButton = extensionsMenuButton;
+ mExtensionsToolbarBridge = extensionsToolbarBridge;
mModels = new ModelList();
mMediator =
@@ -78,7 +83,8 @@ public class ExtensionActionListCoordinator implements Destroyable {
mRecyclerViewDelegate,
extensionsToolbarBridge,
contextMenuPopulatorFactory,
- selectionDropdownMenuDelegate);
+ selectionDropdownMenuDelegate,
+ extensionsMenuButton);
ExtensionsToolbarDragTouchHandler dragTouchHandler =
new ExtensionsToolbarDragTouchHandler(context, mModels);
@@ -134,6 +140,10 @@ public class ExtensionActionListCoordinator implements Destroyable {
LifetimeAssert.setSafeToGc(mLifetimeAssert, true);
}
+ public void openPopup(String actionId) {
+ mMediator.onPrimaryClick(actionId);
+ }
+
/**
* Executes the given action.
*
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionActionListMediator.java
@@ -87,11 +87,11 @@ class ExtensionActionListMediator implements Destroyable {
private final WindowAndroid mWindowAndroid;
private final ModelList mModels;
private final ChromeAndroidTask mTask;
- private final Profile mProfile;
private final NullableObservableSupplier<Tab> mCurrentTabSupplier;
private final @Nullable ContextMenuPopulatorFactory mContextMenuPopulatorFactory;
private final @Nullable SelectionDropdownMenuDelegate mSelectionDropdownMenuDelegate;
private final ExtensionActionListCoordinator.RecyclerViewDelegate mRecyclerViewDelegate;
+ private final ListMenuButton mExtensionsMenuButton;
private final ExtensionsToolbarBridge mExtensionsToolbarBridge;
private final ToolbarDelegate mToolbarDelegate = new ToolbarDelegate();
@@ -124,19 +124,20 @@ class ExtensionActionListMediator implements Destroyable {
ExtensionActionListCoordinator.RecyclerViewDelegate recyclerViewDelegate,
ExtensionsToolbarBridge extensionsToolbarBridge,
@Nullable ContextMenuPopulatorFactory contextMenuPopulatorFactory,
- @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate) {
+ @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate,
+ ListMenuButton extensionsMenuButton) {
mContext = context;
mWindowAndroid = windowAndroid;
mModels = models;
mTask = task;
- mProfile = profile;
mCurrentTabSupplier = currentTabSupplier;
mRecyclerViewDelegate = recyclerViewDelegate;
mExtensionsToolbarBridge = extensionsToolbarBridge;
mContextMenuPopulatorFactory = contextMenuPopulatorFactory;
mSelectionDropdownMenuDelegate = selectionDropdownMenuDelegate;
+ mExtensionsMenuButton = extensionsMenuButton;
- mExtensionsToolbarBridge.setDelegate(mToolbarDelegate);
+ mExtensionsToolbarBridge.setDelegate(mTask, mToolbarDelegate);
mExtensionsToolbarBridge.addObserver(mToolbarObserver);
reconcileActionItems();
}
@@ -149,7 +150,7 @@ class ExtensionActionListMediator implements Destroyable {
assert mActionState instanceof ActionState.Idle;
mExtensionsToolbarBridge.removeObserver(mToolbarObserver);
- mExtensionsToolbarBridge.setDelegate(null);
+ mExtensionsToolbarBridge.setDelegate(mTask, null);
LifetimeAssert.setSafeToGc(mLifetimeAssert, true);
}
@@ -401,7 +402,8 @@ class ExtensionActionListMediator implements Destroyable {
return mModels.get(index).model.get(ExtensionActionButtonProperties.ID);
}
- private void onPrimaryClick(String actionId) {
+ public void onPrimaryClick(String actionId) {
+ if (!mTask.isActive()) return;
if (mActionState instanceof ActionState.PopupActive activeState) {
boolean closeOnly = activeState.getActionId().equals(actionId);
closePopup();
@@ -470,16 +472,14 @@ class ExtensionActionListMediator implements Destroyable {
closeContextMenu();
ExtensionActionPopupContents contents = ExtensionActionPopupContents.create(nativeHostPtr);
- requestActionVisibility(actionId, () -> showPopupOnAnchor(actionId, contents));
+ showPopupOnAnchor(actionId, contents);
}
private void showPopupOnAnchor(String actionId, ExtensionActionPopupContents contents) {
ListMenuButton buttonView =
(ListMenuButton) mRecyclerViewDelegate.getButtonViewForId(actionId);
if (buttonView == null) {
- contents.destroy();
- undoPopout();
- return;
+ buttonView = mExtensionsMenuButton;
}
Activity activity = mWindowAndroid.getActivity().get();
@@ -564,7 +564,7 @@ class ExtensionActionListMediator implements Destroyable {
assert mActionState instanceof ActionState.Idle;
ExtensionActionContextMenuBridge bridge =
new ExtensionActionContextMenuBridge(
- mTask, mProfile, actionId, webContents, ContextMenuSource.TOOLBAR_ACTION);
+ mTask, currentTab.getProfile(), actionId, webContents, ContextMenuSource.TOOLBAR_ACTION);
ExtensionActionContextMenuUtils.showContextMenu(
mContext,
buttonView,
@@ -597,7 +597,7 @@ class ExtensionActionListMediator implements Destroyable {
/** Updates the list of displayed actions to fit within the provided width constraint. */
public void fitActionsWithinWidth(int availableWidth) {
- mAvailableWidthForPinnedActions = availableWidth;
+ // mAvailableWidthForPinnedActions = availableWidth;
// If this is called during an animation (e.g. the user resizes window during pinning /
// unpinning animation), we abandon the animation and update to the new state instantly.
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuCoordinator.java
@@ -14,6 +14,7 @@ import androidx.core.widget.ImageViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import org.chromium.base.Callback;
import org.chromium.base.lifetime.Destroyable;
import org.chromium.base.supplier.NullableObservableSupplier;
import org.chromium.build.annotations.NullMarked;
@@ -71,6 +72,7 @@ public class ExtensionsMenuCoordinator implements Destroyable, ExtensionsToolbar
private final ExtensionActionListCoordinator mExtensionActionListCoordinator;
@Nullable @VisibleForTesting ExtensionsMenuMediator mMediator;
+ private Callback<String> mOpenUrlInCustomTab;
/**
* Constructor.
@@ -96,7 +98,9 @@ public class ExtensionsMenuCoordinator implements Destroyable, ExtensionsToolbar
TabCreator tabCreator,
ExtensionsToolbarBridge extensionsToolbarBridge,
MenuButtonPinningDelegate menuButtonPinningDelegate,
- ExtensionActionListCoordinator extensionActionListCoordinator) {
+ ExtensionActionListCoordinator extensionActionListCoordinator,
+ Callback<String> openUrlInCustomTab) {
+ mOpenUrlInCustomTab = openUrlInCustomTab;
mExtensionActionListCoordinator = extensionActionListCoordinator;
mContext = context;
mCurrentTabSupplier = currentTabSupplier;
@@ -234,6 +238,14 @@ public class ExtensionsMenuCoordinator implements Destroyable, ExtensionsToolbar
private void openUrlFromMenu(String url) {
mExtensionsMenuButton.dismiss();
+ if (mOpenUrlInCustomTab != null) {
+ Tab currentTab = mCurrentTabSupplier.get();
+ if (currentTab != null && currentTab.isIncognitoBranded()) {
+ mOpenUrlInCustomTab.onResult(url);
+ return;
+ }
+ }
+
LoadUrlParams params = new LoadUrlParams(url, PageTransition.AUTO_TOPLEVEL);
mTabCreator.createNewTab(params, TabLaunchType.FROM_CHROME_UI, null);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsMenuMediator.java
@@ -44,7 +44,6 @@ class ExtensionsMenuMediator implements Destroyable, ExtensionsMenuBridge.Observ
private final PropertyModel mSitePermissionsPageModel;
private final Runnable mOnReady;
private final ChromeAndroidTask mTask;
- private final Profile mProfile;
private final ExtensionActionListCoordinator mExtensionActionListCoordinator;
/**
@@ -73,8 +72,8 @@ class ExtensionsMenuMediator implements Destroyable, ExtensionsMenuBridge.Observ
mCurrentTabSupplier = currentTabSupplier;
mOnReady = onReady;
mTask = task;
- mProfile = profile;
- mMenuBridge = new ExtensionsMenuBridge(mTask, mProfile, /* observer= */ this);
+ mMenuBridge = ExtensionsMenuBridge.Instance();
+ mMenuBridge.setObserver(task, /* observer= */ this);
mMainPageModel = mainPageModel;
mMainPageModel.set(
@@ -112,7 +111,7 @@ class ExtensionsMenuMediator implements Destroyable, ExtensionsMenuBridge.Observ
ExtensionActionContextMenuBridge contextMenuBridge =
new ExtensionActionContextMenuBridge(
- mTask, mProfile, actionId, webContents, ContextMenuSource.MENU_ITEM);
+ mTask, currentTab.getProfile(), actionId, webContents, ContextMenuSource.MENU_ITEM);
ExtensionActionContextMenuUtils.showContextMenu(
mContext,
@@ -142,7 +141,7 @@ class ExtensionsMenuMediator implements Destroyable, ExtensionsMenuBridge.Observ
public void destroy() {
mMainPageModel.set(ExtensionsMenuProperties.SITE_SETTINGS_TOGGLE_CLICK_LISTENER, null);
mSitePermissionsPageModel.set(SitePermissionsPageProperties.BACK_CLICK_LISTENER, null);
- mMenuBridge.destroy();
+ //mMenuBridge.destroy();
}
/**
@@ -253,6 +252,7 @@ class ExtensionsMenuMediator implements Destroyable, ExtensionsMenuBridge.Observ
break;
}
}
+ if (oldIndex < 0) return;
assert oldIndex != -1
: "Action model with ID " + entry.id + " should exist in mActionModels.";
@@ -479,7 +479,7 @@ class ExtensionsMenuMediator implements Destroyable, ExtensionsMenuBridge.Observ
// open web store button present in the zero state view.
mMainPageModel.set(ExtensionsMenuProperties.DISCOVER_EXTENSIONS_VISIBLE, false);
} else {
- mMainPageModel.set(ExtensionsMenuProperties.DISCOVER_EXTENSIONS_VISIBLE, true);
+ mMainPageModel.set(ExtensionsMenuProperties.DISCOVER_EXTENSIONS_VISIBLE, false);
updateSiteSettingsToggle();
}
}
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsToolbarCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsToolbarCoordinator.java
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsToolbarCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsToolbarCoordinator.java
@@ -9,6 +9,7 @@ import android.view.KeyEvent;
import android.view.ViewGroup;
import android.view.ViewStub;
+import org.chromium.base.Callback;
import org.chromium.base.ServiceLoaderUtil;
import org.chromium.base.lifetime.Destroyable;
import org.chromium.base.supplier.NullableObservableSupplier;
@@ -53,7 +54,8 @@ public interface ExtensionsToolbarCoordinator extends Destroyable {
ThemeColorProvider themeColorProvider,
ViewGroup rootView,
@Nullable ContextMenuPopulatorFactory contextMenuPopulatorFactory,
- @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate) {
+ @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate,
+ Callback<String> openUrlInCustomTab) {
// Check if the extension UI is enabled first.
if (!ExtensionUi.isEnabled(profile)) {
return null;
@@ -75,7 +77,8 @@ public interface ExtensionsToolbarCoordinator extends Destroyable {
themeColorProvider,
rootView,
contextMenuPopulatorFactory,
- selectionDropdownMenuDelegate);
+ selectionDropdownMenuDelegate,
+ openUrlInCustomTab);
return coordinator;
}
@@ -97,7 +100,8 @@ public interface ExtensionsToolbarCoordinator extends Destroyable {
ThemeColorProvider themeColorProvider,
ViewGroup rootView,
@Nullable ContextMenuPopulatorFactory contextMenuPopulatorFactory,
- @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate);
+ @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate,
+ Callback<String> openUrlInCustomTab);
/**
* Dispatches the key event to trigger the corresponding extension action if any.
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsToolbarCoordinatorImpl.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsToolbarCoordinatorImpl.java
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsToolbarCoordinatorImpl.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/extensions/ExtensionsToolbarCoordinatorImpl.java
@@ -6,6 +6,7 @@ package org.chromium.chrome.browser.toolbar.extensions;
import android.animation.Animator;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -13,6 +14,7 @@ import android.view.ViewStub;
import android.widget.LinearLayout;
import android.widget.TextView;
+import org.chromium.base.Callback;
import org.chromium.base.lifetime.LifetimeAssert;
import org.chromium.base.supplier.NullableObservableSupplier;
import org.chromium.build.annotations.NullMarked;
@@ -25,6 +27,8 @@ import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabCreator;
import org.chromium.chrome.browser.theme.ThemeColorProvider;
+import org.chromium.chrome.browser.theme.ThemeUtils;
+import org.chromium.chrome.browser.ui.theme.BrandedColorScheme;
import org.chromium.chrome.browser.ui.browser_window.ChromeAndroidTask;
import org.chromium.chrome.browser.ui.extensions.ExtensionActionsBridge;
import org.chromium.chrome.browser.ui.extensions.ExtensionsToolbarBridge;
@@ -58,6 +62,8 @@ public class ExtensionsToolbarCoordinatorImpl implements ExtensionsToolbarCoordi
private ExtensionAccessControlButtonCoordinator mExtensionAccessControlButtonCoordinator;
private PropertyModel mToolbarModel;
private PropertyModelChangeProcessor mMenuButtonChangeProcessor;
+ private Context mContext;
+ private ThemeColorProvider mThemeColorProvider;
private final MenuButtonWidthConsumer mMenuButtonWidthConsumer = new MenuButtonWidthConsumer();
private final RequestAccessButtonWidthConsumer mRequestAccessButtonWidthConsumer =
@@ -86,7 +92,9 @@ public class ExtensionsToolbarCoordinatorImpl implements ExtensionsToolbarCoordi
ThemeColorProvider themeColorProvider,
ViewGroup rootView,
@Nullable ContextMenuPopulatorFactory contextMenuPopulatorFactory,
- @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate) {
+ @Nullable SelectionDropdownMenuDelegate selectionDropdownMenuDelegate,
+ Callback<String> openUrlInCustomTab) {
+ mThemeColorProvider = themeColorProvider;
mBridge = ExtensionActionsBridge.Instance();
mProfile = profile;
@@ -127,7 +135,8 @@ public class ExtensionsToolbarCoordinatorImpl implements ExtensionsToolbarCoordi
currentTabSupplier,
tabCreator,
mExtensionsToolbarBridge,
- mMenuButtonPinningDelegate);
+ mMenuButtonPinningDelegate,
+ mExtensionActionListCoordinator, openUrlInCustomTab);
mExtensionAccessControlButtonCoordinator =
new ExtensionAccessControlButtonCoordinator(
@@ -174,6 +183,8 @@ public class ExtensionsToolbarCoordinatorImpl implements ExtensionsToolbarCoordi
mToolbarModel.set(
ExtensionsToolbarProperties.EXTENSIONS_MENU_BUTTON_DEFAULT_BACKGROUND,
backgroundResource);
+ mExtensionsMenuCoordinator.onTintChanged(
+ /*tintList*/ null, mThemeColorProvider.getTint(), BrandedColorScheme.APP_DEFAULT);
}
@Override
@@ -202,6 +213,8 @@ public class ExtensionsToolbarCoordinatorImpl implements ExtensionsToolbarCoordi
mExtensionsMenuCoordinator.setMenuButtonPinned(isMenuButtonPinned());
}
+ updateMenuIconVisibility();
+
// Trigger layout and wait for the toolbar to provide us with width allocation.
ViewUtils.requestLayout(
mContainer, "ExtensionsToolbarCoordinatorImpl.updateMenuButtonPinState()");
@@ -223,9 +236,7 @@ public class ExtensionsToolbarCoordinatorImpl implements ExtensionsToolbarCoordi
}
private boolean shouldShowMenuIcon() {
- return mExtensionsMenuCoordinator.isExtensionsMenuOpen()
- || mShowExtensionsMenuPending
- || (mCanShowMenuIcon && isMenuButtonPinned());
+ return isMenuButtonPinned();
}
public class MenuButtonPinningDelegate {
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/ToolbarPhone.java
@@ -87,6 +87,7 @@ import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
import org.chromium.chrome.browser.toolbar.ToolbarProgressBar;
import org.chromium.chrome.browser.toolbar.ToolbarTabController;
import org.chromium.chrome.browser.toolbar.back_button.BackButtonCoordinator;
+import org.chromium.chrome.browser.toolbar.extensions.ExtensionsToolbarCoordinator;
import org.chromium.chrome.browser.toolbar.forward_button.ForwardButtonCoordinator;
import org.chromium.chrome.browser.toolbar.home_button.HomeButtonCoordinator;
import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator;
@@ -324,6 +325,8 @@ public class ToolbarPhone extends ToolbarLayout
// to webpages.
private boolean mIsInLoadingPhaseFromNtpToWebpage;
+ private @Nullable ExtensionsToolbarCoordinator mExtensionsToolbarCoordinator;
+
// The following are some properties used during animation. We use explicit property classes
// to avoid the cost of reflection for each animation setup.
@@ -514,6 +517,14 @@ public class ToolbarPhone extends ToolbarLayout
}
}
+ @Override
+ public void setExtensionsToolbarCoordinator(
+ ExtensionsToolbarCoordinator extensionsToolbarCoordinator) {
+ mExtensionsToolbarCoordinator = extensionsToolbarCoordinator;
+ mExtensionsToolbarCoordinator.getMenuButtonWidthConsumer().updateVisibility(99999);
+ updateRippleBackground();
+ }
+
@Override
public void destroy() {
cancelAnimations();
@@ -2894,6 +2905,7 @@ public class ToolbarPhone extends ToolbarLayout
@Override
public void onTabOrModelChanged() {
super.onTabOrModelChanged();
+ updateRippleBackground();
updateNtpAnimationState();
updateVisualsForLocationBarState();
}
@@ -2911,6 +2923,10 @@ public class ToolbarPhone extends ToolbarLayout
mHomeButton.setBackgroundResource(toolbarIconRippleId);
getMenuButtonCoordinator().updateButtonBackground(toolbarIconRippleId);
mLocationBar.updateButtonBackground(omniboxIconRippleId);
+ if (mExtensionsToolbarCoordinator != null) {
+ mExtensionsToolbarCoordinator.updateMenuButtonBackground(
+ ToolbarUtils.getToolbarIconRippleId(isIncognitoBranded()));
+ }
}
private static boolean isVisualStateValidForBrandColorTransition(@VisualState int state) {
diff --git a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java
--- a/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java
+++ b/chrome/browser/ui/browser_window/internal/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskImpl.java
@@ -329,7 +329,7 @@ final class ChromeAndroidTaskImpl
// profile is destroyed. This should be fixed. For now we can just defer the
// destruction until the activity is destroyed since there should never be more
// than one profile/window on desktop Android.
- if (!BuildConfig.IS_DESKTOP_ANDROID) {
+ if ((true)) {
if (mPendingBrowserWindow != null
&& mPendingBrowserWindow.getProfile() == profile) {
assert mActivityScopedObjectsDeque.isEmpty();
@@ -425,6 +425,10 @@ final class ChromeAndroidTaskImpl
}
}
}
+
+ @Override
+ public void didDestroyed() {
+ }
}
private @Nullable Integer mId;
@@ -738,7 +742,7 @@ final class ChromeAndroidTaskImpl
? null
: topActivityScopedObjects.mTabModelSelector;
if (tabModelSelector != null) {
- feature.onTabModelSelected(tabModelSelector.getCurrentModel());
+ feature.onTabModelSelected(this, tabModelSelector.getCurrentModel());
}
}
@@ -1208,6 +1212,14 @@ final class ChromeAndroidTaskImpl
for (var feature : mFeatures.values()) {
feature.onTaskFocusChanged(isTopResumedActivity);
}
+ if (isTopResumedActivity) {
+ var internalActivityScopedObjects = mActivityScopedObjectsDeque.peekFirst();
+ var topActivityScopedObjects = internalActivityScopedObjects.mActivityScopedObjects;
+ TabModelSelector tabModelSelector = topActivityScopedObjects.mTabModelSelector;
+ for (var feature : mFeatures.values()) {
+ feature.onTabModelSelected(this, tabModelSelector.getCurrentModel());
+ }
+ }
}
@Override
@@ -1867,7 +1879,7 @@ final class ChromeAndroidTaskImpl
private void onTabModelSelected(TabModel tabModel) {
for (var feature : mFeatures.values()) {
- feature.onTabModelSelected(tabModel);
+ feature.onTabModelSelected(this, tabModel);
}
}
diff --git a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java
--- a/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java
+++ b/chrome/browser/ui/browser_window/public/android/java/src/org/chromium/chrome/browser/ui/browser_window/ChromeAndroidTaskFeature.java
@@ -72,5 +72,5 @@ public interface ChromeAndroidTaskFeature {
*
* @param tabModel The selected {@link TabModel}.
*/
- default void onTabModelSelected(TabModel tabModel) {}
+ default void onTabModelSelected(ChromeAndroidTask task, TabModel tabModel) {}
}
diff --git a/components/tabs/impl/tab_collection.cc b/components/tabs/impl/tab_collection.cc
--- a/components/tabs/impl/tab_collection.cc
+++ b/components/tabs/impl/tab_collection.cc
@@ -137,6 +137,22 @@ TabCollection::TabCollection(Type type,
TabCollection::~TabCollection() {
DispatchPendingNotifications();
+
+ auto& childrens = GetChildren();
+ for (auto it = childrens.begin(); it != childrens.end(); ) {
+ auto& child = *it;
+ if (std::holds_alternative<std::unique_ptr<TabInterface>>(child)) {
+ TabInterface* tab =
+ std::get<std::unique_ptr<TabInterface>>(child).get();
+ auto removed_tab = MaybeRemoveTab(tab);
+ } else if (std::holds_alternative<std::unique_ptr<TabCollection>>(child)) {
+ TabCollection* collection =
+ std::get<std::unique_ptr<TabCollection>>(child).get();
+ auto removed_collection = MaybeRemoveCollection(collection);
+ } else {
+ it++;
+ }
+ }
}
void TabCollection::AddObserver(TabCollectionObserver* observer) const {
diff --git a/components/tabs/impl/tab_strip_collection.cc b/components/tabs/impl/tab_strip_collection.cc
--- a/components/tabs/impl/tab_strip_collection.cc
+++ b/components/tabs/impl/tab_strip_collection.cc
@@ -329,13 +329,13 @@ std::unique_ptr<TabInterface> TabStripCollection::RemoveTabAtIndexRecursive(
std::unique_ptr<TabInterface> TabStripCollection::MaybeRemoveTab(
TabInterface* tab) {
CHECK(tab);
- return nullptr;
+ return RemoveTabImpl(tab);
}
std::unique_ptr<TabCollection> TabStripCollection::MaybeRemoveCollection(
TabCollection* collection) {
CHECK(collection);
- return nullptr;
+ return TabStripCollection::RemoveTabCollection(collection);
}
void TabStripCollection::InsertTabCollectionAt(
--