Commit ddad167d authored by Henrique Nakashima's avatar Henrique Nakashima Committed by Chromium LUCI CQ

Reland "Create glue-layer TabModelOrchestrators"

This is a reland of 314cbf4c

Patchset 1 is the original change.

The main difference is that now the TabPersistentStore is created
with the actual index that TabWindowManagerImpl assigned to the
TabModelSelector, rather than the index that was "requested".

Other changes are to adapt tests.

Original change's description:
> Create glue-layer TabModelOrchestrators
>
> TabModelSelectorImpl does not create or destroy TabPersistentStore
> anymore. Instead, TabModelOrchestrators manage the lifetime of TabModelSelectorImpl and
> TabPersistentStore.
>
> Give TabModelSelectorImpl a Supplier<TabPersistentStore> instead of
> passing TabPersistentStore directly.
>
> This is a step to break the two-way dependency between
> TabModelSelectorImpl and TabPersistentStore.
>
> Bug: 1138561
> Change-Id: Ie2fa4a2735e509ff816b3e2cf5f8f6fffda7999c
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2572639
> Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
> Reviewed-by: David Trainor <dtrainor@chromium.org>
> Reviewed-by: Ella Ge <eirage@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#835819}

Bug: 1138561,1158259
Change-Id: Iac6eaaed149e853536813cd627d28236638657de
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2590427
Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
Reviewed-by: default avatarElla Ge <eirage@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843752}
parent 79de88f2
......@@ -84,8 +84,11 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/app/tabmodel/AsyncTabParamsManagerSingleton.java",
"java/src/org/chromium/chrome/browser/app/tabmodel/ChromeNextTabPolicySupplier.java",
"java/src/org/chromium/chrome/browser/app/tabmodel/ChromeTabModelFilterFactory.java",
"java/src/org/chromium/chrome/browser/app/tabmodel/CustomTabsTabModelOrchestrator.java",
"java/src/org/chromium/chrome/browser/app/tabmodel/DefaultTabModelSelectorFactory.java",
"java/src/org/chromium/chrome/browser/app/tabmodel/TabModelOrchestrator.java",
"java/src/org/chromium/chrome/browser/app/tabmodel/TabWindowManagerSingleton.java",
"java/src/org/chromium/chrome/browser/app/tabmodel/TabbedModeTabModelOrchestrator.java",
"java/src/org/chromium/chrome/browser/app/video_tutorials/ChromeLanguageInfoProvider.java",
"java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java",
"java/src/org/chromium/chrome/browser/app/video_tutorials/VideoPlayerActivity.java",
......
......@@ -60,7 +60,9 @@ import org.chromium.chrome.browser.accessibility_tab_switcher.OverviewListLayout
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton;
import org.chromium.chrome.browser.app.tabmodel.ChromeNextTabPolicySupplier;
import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator;
import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
import org.chromium.chrome.browser.app.tabmodel.TabbedModeTabModelOrchestrator;
import org.chromium.chrome.browser.bookmarks.BookmarkUtils;
import org.chromium.chrome.browser.compositor.CompositorViewHolder;
import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCoordinator;
......@@ -247,6 +249,7 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
private ToolbarControlContainer mControlContainer;
private TabbedModeTabModelOrchestrator mTabModelOrchestrator;
private TabModelSelectorImpl mTabModelSelectorImpl;
private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
private TabModelSelectorTabModelObserver mTabModelObserver;
......@@ -1628,7 +1631,13 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
}
@Override
protected TabModelSelector createTabModelSelector() {
protected TabModelOrchestrator createTabModelOrchestrator() {
mTabModelOrchestrator = new TabbedModeTabModelOrchestrator();
return mTabModelOrchestrator;
}
@Override
protected void createTabModels() {
assert mTabModelSelectorImpl == null;
Bundle savedInstanceState = getSavedInstanceState();
......@@ -1639,17 +1648,15 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
int index = savedInstanceState != null ? savedInstanceState.getInt(WINDOW_INDEX, 0) : 0;
mNextTabPolicySupplier = new ChromeNextTabPolicySupplier(mOverviewModeBehaviorSupplier);
mTabModelSelectorImpl =
(TabModelSelectorImpl) TabWindowManagerSingleton.getInstance().requestSelector(
this, this, mNextTabPolicySupplier, index);
if (mTabModelSelectorImpl == null) {
Toast.makeText(
this, getString(R.string.unsupported_number_of_windows), Toast.LENGTH_LONG)
.show();
boolean tabModelWasCreated =
mTabModelOrchestrator.createTabModels(this, this, mNextTabPolicySupplier, index);
if (!tabModelWasCreated) {
finish();
return null;
return;
}
mTabModelSelectorImpl = mTabModelOrchestrator.getTabModelSelector();
mTabModelSelectorImpl.addObserver(new EmptyTabModelSelectorObserver() {
@Override
public void onTabStateInitialized() {
......@@ -1673,8 +1680,6 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
mAppIndexingUtil = new AppIndexingUtil(mTabModelSelectorImpl);
if (startIncognito) mTabModelSelectorImpl.selectModel(true);
return mTabModelSelectorImpl;
}
@Override
......@@ -2223,6 +2228,13 @@ public class ChromeTabbedActivity extends ChromeActivity<ChromeActivityComponent
super.onDestroyInternal();
}
@Override
protected void destroyTabModels() {
if (mTabModelOrchestrator != null) {
mTabModelOrchestrator.destroy();
}
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
......
......@@ -71,6 +71,7 @@ import org.chromium.chrome.browser.app.flags.ChromeCachedFlags;
import org.chromium.chrome.browser.app.tab_activity_glue.ReparentingDelegateFactory;
import org.chromium.chrome.browser.app.tab_activity_glue.TabReparentingController;
import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton;
import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator;
import org.chromium.chrome.browser.bookmarks.BookmarkBridge;
import org.chromium.chrome.browser.bookmarks.BookmarkBridge.BookmarkItem;
import org.chromium.chrome.browser.bookmarks.BookmarkModel;
......@@ -241,7 +242,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
new TabModelSelectorProfileSupplier(mTabModelSelectorSupplier);
protected ObservableSupplierImpl<BookmarkBridge> mBookmarkBridgeSupplier =
new ObservableSupplierImpl<>();
private TabModelSelector mTabModelSelector;
private TabModelOrchestrator mTabModelOrchestrator;
private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
private TabCreator mRegularTabCreator;
private TabCreator mIncognitoTabCreator;
......@@ -263,7 +264,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
/** Whether or not {@link #postDeferredStartupIfNeeded()} has already successfully run. */
private boolean mDeferredStartupPosted;
private boolean mTabModelsInitialized;
private boolean mNativeInitialized;
private boolean mRemoveWindowBackgroundDone;
protected AccessibilityVisibilityHandler mAccessibilityVisibilityHandler;
......@@ -358,6 +358,9 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
// onPreInflationStartup event.
mComponent = createComponent();
// Create the orchestrator that manages Tab models and persistence
mTabModelOrchestrator = createTabModelOrchestrator();
// There's no corresponding call to removeObserver() for this addObserver() because
// mTabModelProfileSupplier has the same lifecycle as this activity.
mTabModelProfileSupplier.addObserver((profile) -> {
......@@ -483,9 +486,10 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
mCompositorViewHolder.getCompositorView());
initializeTabModels();
TabModelSelector tabModelSelector = mTabModelOrchestrator.getTabModelSelector();
setTabContentManager(new TabContentManager(this, getContentOffsetProvider(),
!SysUtils.isLowEndDevice(),
mTabModelSelector != null ? mTabModelSelector::getTabById : null));
tabModelSelector != null ? tabModelSelector::getTabById : null));
if (!isFinishing()) {
getBrowserControlsManager().initialize(
......@@ -647,28 +651,28 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
* this activity.
*/
public final void initializeTabModels() {
if (mTabModelsInitialized) return;
if (mTabModelOrchestrator.areTabModelsInitialized()) return;
mTabModelSelector = createTabModelSelector();
createTabModels();
TabModelSelector tabModelSelector = mTabModelOrchestrator.getTabModelSelector();
if (mTabModelSelector == null) {
if (tabModelSelector == null) {
assert isFinishing();
mTabModelsInitialized = true;
return;
}
mTabModelSelectorSupplier.set(mTabModelSelector);
mActivityTabProvider.setTabModelSelector(mTabModelSelector);
getStatusBarColorController().setTabModelSelector(mTabModelSelector);
mTabModelSelectorSupplier.set(tabModelSelector);
mActivityTabProvider.setTabModelSelector(tabModelSelector);
getStatusBarColorController().setTabModelSelector(tabModelSelector);
Pair<? extends TabCreator, ? extends TabCreator> tabCreators = createTabCreators();
mRegularTabCreator = tabCreators.first;
mIncognitoTabCreator = tabCreators.second;
OfflinePageUtils.observeTabModelSelector(this, mTabModelSelector);
OfflinePageUtils.observeTabModelSelector(this, tabModelSelector);
if (mTabModelSelectorTabObserver != null) mTabModelSelectorTabObserver.destroy();
mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(mTabModelSelector) {
mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(tabModelSelector) {
@Override
public void onLoadStopped(Tab tab, boolean toDifferentDocument) {
postDeferredStartupIfNeeded();
......@@ -685,8 +689,6 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
postDeferredStartupIfNeeded();
}
};
mTabModelsInitialized = true;
}
/**
......@@ -702,9 +704,19 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
}
/**
* @return The {@link TabModelSelector} owned by this {@link ChromeActivity}.
* @return The {@link TabModelOrchestrator} owned by this {@link ChromeActivity}.
*/
protected abstract TabModelOrchestrator createTabModelOrchestrator();
/**
* Call the {@link TabModelOrchestrator} to initialize its members.
*/
protected abstract TabModelSelector createTabModelSelector();
protected abstract void createTabModels();
/**
* Call the {@link TabModelOrchestrator} to destroy its members.
*/
protected abstract void destroyTabModels();
/**
* @return The {@link TabCreator}s owned
......@@ -843,7 +855,8 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
VrModuleProvider.getDelegate().onActivityHidden(this);
Tab tab = getActivityTab();
if (mTabModelSelector != null && !mTabModelSelector.isReparentingInProgress()
TabModelSelector tabModelSelector = mTabModelOrchestrator.getTabModelSelector();
if (tabModelSelector != null && !tabModelSelector.isReparentingInProgress()
&& tab != null) {
tab.hide(TabHidingType.ACTIVITY_HIDDEN);
}
......@@ -1304,10 +1317,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
mActivityTabStartupMetricsTracker = null;
}
if (mTabModelsInitialized) {
TabModelSelector selector = getTabModelSelector();
if (selector != null) selector.destroy();
}
destroyTabModels();
if (mBookmarkBridgeSupplier != null) {
BookmarkBridge bookmarkBridge = mBookmarkBridgeSupplier.get();
......@@ -1583,7 +1593,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
* @return Whether the tab models have been fully initialized.
*/
public boolean areTabModelsInitialized() {
return mTabModelsInitialized;
return mTabModelOrchestrator.areTabModelsInitialized();
}
/**
......@@ -1592,11 +1602,11 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
* @return The {@link TabModelSelector}, possibly null.
*/
public TabModelSelector getTabModelSelector() {
if (!mTabModelsInitialized) {
if (!mTabModelOrchestrator.areTabModelsInitialized()) {
throw new IllegalStateException(
"Attempting to access TabModelSelector before initialization");
}
return mTabModelSelector;
return mTabModelOrchestrator.getTabModelSelector();
}
/**
......@@ -1617,7 +1627,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
@Override
public TabCreator getTabCreator(boolean incognito) {
if (!mTabModelsInitialized) {
if (!mTabModelOrchestrator.areTabModelsInitialized()) {
throw new IllegalStateException(
"Attempting to access TabCreator before initialization");
}
......@@ -1684,7 +1694,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
* null if the Tab does not exist or the system is not initialized.
*/
public Tab getActivityTab() {
if (!mTabModelsInitialized) {
if (!mTabModelOrchestrator.areTabModelsInitialized()) {
return null;
}
return TabModelUtils.getCurrentTab(getCurrentTabModel());
......@@ -1695,7 +1705,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
* WebContents.
*/
public WebContents getCurrentWebContents() {
if (!mTabModelsInitialized) {
if (!mTabModelOrchestrator.areTabModelsInitialized()) {
return null;
}
return TabModelUtils.getCurrentWebContents(getCurrentTabModel());
......@@ -2019,7 +2029,7 @@ public abstract class ChromeActivity<C extends ChromeActivityComponent>
if (id == R.id.help_id) {
String url = currentTab != null ? currentTab.getUrlString() : "";
Profile profile = mTabModelSelector.isIncognitoSelected()
Profile profile = getTabModelSelector().isIncognitoSelected()
? Profile.getLastUsedRegularProfile().getPrimaryOTRProfile()
: Profile.getLastUsedRegularProfile();
startHelpAndFeedback(url, "MobileMenuFeedback", profile);
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.app.tabmodel;
import androidx.annotation.Nullable;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
import org.chromium.chrome.browser.tabmodel.NextTabPolicy;
import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier;
import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
import org.chromium.chrome.browser.tabmodel.TabModelFilterFactory;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy;
import org.chromium.chrome.browser.tabmodel.TabPersistentStore;
import org.chromium.ui.base.WindowAndroid;
import javax.inject.Inject;
/**
* Glue-level class that manages lifetime of root .tabmodel objects: {@link TabPersistentStore} and
* {@link TabModelSelectorImpl} for custom tabs.
*/
@ActivityScope
public class CustomTabsTabModelOrchestrator extends TabModelOrchestrator {
@Inject
public CustomTabsTabModelOrchestrator() {}
/**
* Creates the TabModelSelector and the TabPersistentStore.
*/
public void createTabModels(@Nullable Supplier<WindowAndroid> windowAndroidSupplier,
TabCreatorManager tabCreatorManager, TabModelFilterFactory tabModelFilterFactory,
TabPersistencePolicy persistencePolicy, AsyncTabParamsManager asyncTabParamsManager) {
// Instantiate TabModelSelectorImpl
NextTabPolicySupplier nextTabPolicySupplier = () -> NextTabPolicy.LOCATIONAL;
mTabModelSelector = new TabModelSelectorImpl(windowAndroidSupplier, tabCreatorManager,
tabModelFilterFactory, nextTabPolicySupplier, asyncTabParamsManager, false, false,
false);
// Instantiate TabPersistentStore
mTabPersistentStore =
new TabPersistentStore(persistencePolicy, mTabModelSelector, tabCreatorManager);
wireSelectorAndStore();
markTabModelsInitialized();
}
}
......@@ -5,19 +5,15 @@
package org.chromium.chrome.browser.app.tabmodel;
import android.app.Activity;
import android.os.Build;
import org.chromium.base.annotations.VerifiesOnN;
import org.chromium.chrome.browser.multiwindow.MultiInstanceManager;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier;
import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
import org.chromium.chrome.browser.tabmodel.TabModelFilterFactory;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorFactory;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy;
import org.chromium.chrome.browser.tabmodel.TabbedModeTabPersistencePolicy;
/**
* Default {@link TabModelSelectorFactory} for Chrome.
......@@ -29,32 +25,11 @@ public class DefaultTabModelSelectorFactory implements TabModelSelectorFactory {
@Override
public TabModelSelector buildSelector(Activity activity, TabCreatorManager tabCreatorManager,
NextTabPolicySupplier nextTabPolicySupplier, int selectorIndex) {
// Merge tabs if this TabModelSelector is for a ChromeTabbedActivity created in
// fullscreen mode and there are no TabModelSelector's currently alive. This indicates
// that it is a cold start or process restart in fullscreen mode.
boolean mergeTabs = Build.VERSION.SDK_INT > Build.VERSION_CODES.M
&& MultiInstanceManager.isTabModelMergingEnabled()
&& !activity.isInMultiWindowMode();
if (MultiInstanceManager.shouldMergeOnStartup(activity)) {
mergeTabs = mergeTabs
&& (!MultiWindowUtils.getInstance().isInMultiDisplayMode(activity)
|| TabWindowManagerSingleton.getInstance()
.getNumberOfAssignedTabModelSelectors()
== 0);
} else {
mergeTabs = mergeTabs
&& TabWindowManagerSingleton.getInstance()
.getNumberOfAssignedTabModelSelectors()
== 0;
}
if (mergeTabs) {
MultiInstanceManager.mergedOnStartup();
}
TabPersistencePolicy persistencePolicy =
new TabbedModeTabPersistencePolicy(selectorIndex, mergeTabs);
TabModelFilterFactory tabModelFilterFactory = new ChromeTabModelFilterFactory();
return new TabModelSelectorImpl(activity, /*windowAndroidSupplier=*/null, tabCreatorManager,
persistencePolicy, tabModelFilterFactory, nextTabPolicySupplier,
AsyncTabParamsManagerSingleton.getInstance(), true, true, false);
AsyncTabParamsManager asyncTabParamsManager = AsyncTabParamsManagerSingleton.getInstance();
return new TabModelSelectorImpl(/*windowAndroidSupplier=*/null, tabCreatorManager,
tabModelFilterFactory, nextTabPolicySupplier, asyncTabParamsManager, true, true,
false);
}
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.app.tabmodel;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.tabmodel.TabPersistentStore;
import org.chromium.chrome.browser.tabmodel.TabPersistentStore.TabPersistentStoreObserver;
/**
* Implementers are glue-level objects that manage lifetime of root .tabmodel objects: {@link
* TabPersistentStore} and {@link TabModelSelectorImpl}.
*/
public abstract class TabModelOrchestrator {
protected TabPersistentStore mTabPersistentStore;
protected TabModelSelectorImpl mTabModelSelector;
private boolean mTabModelsInitialized;
/**
* @return Whether the tab models have been fully initialized.
*/
public boolean areTabModelsInitialized() {
return mTabModelsInitialized;
}
/**
* @return The {@link TabModelSelectorImpl} managed by this orchestrator.
*/
public TabModelSelectorImpl getTabModelSelector() {
return mTabModelSelector;
}
/**
* Destroy the {@link TabPersistentStore} and {@link TabModelSelectorImpl} members.
*/
public void destroy() {
if (!mTabModelsInitialized) {
return;
}
if (mTabPersistentStore != null) {
mTabPersistentStore.destroy();
mTabPersistentStore = null;
}
if (mTabModelSelector != null) {
mTabModelSelector.destroy();
mTabModelSelector = null;
}
mTabModelsInitialized = false;
}
protected void wireSelectorAndStore() {
// Supply TabModelSelectorImpl with TabPersistentStore.
//
// TODO(crbug.com/1138561): Remove this dependency by making TabModelSelectorImpl emit
// events and TabPersistentStore react to them as an observer.
ObservableSupplierImpl<TabPersistentStore> tabPersistentStoreSupplier =
new ObservableSupplierImpl<>();
tabPersistentStoreSupplier.set(mTabPersistentStore);
mTabModelSelector.setTabPersistentStoreSupplier(tabPersistentStoreSupplier);
// Notify TabModelSelectorImpl when TabPersistentStore initializes tab state
final TabPersistentStoreObserver persistentStoreObserver =
new TabPersistentStoreObserver() {
@Override
public void onStateLoaded() {
mTabModelSelector.markTabStateInitialized();
}
};
mTabPersistentStore.addObserver(persistentStoreObserver);
}
protected void markTabModelsInitialized() {
mTabModelsInitialized = true;
}
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.app.tabmodel;
import android.app.Activity;
import android.os.Build;
import android.util.Pair;
import org.chromium.chrome.browser.multiwindow.MultiInstanceManager;
import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier;
import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy;
import org.chromium.chrome.browser.tabmodel.TabPersistentStore;
import org.chromium.chrome.browser.tabmodel.TabbedModeTabPersistencePolicy;
import org.chromium.ui.widget.Toast;
/**
* Glue-level class that manages lifetime of root .tabmodel objects: {@link TabPersistentStore} and
* {@link TabModelSelectorImpl} for tabbed mode.
*/
public class TabbedModeTabModelOrchestrator extends TabModelOrchestrator {
public TabbedModeTabModelOrchestrator() {}
/**
* Creates the TabModelSelector and the TabPersistentStore.
*
* @return Whether the creation was successful. It may fail is we reached the limit of number of
* windows.
*/
public boolean createTabModels(Activity activity, TabCreatorManager tabCreatorManager,
NextTabPolicySupplier nextTabPolicySupplier, int selectorIndex) {
boolean mergeTabs = shouldMergeTabs(activity);
if (mergeTabs) {
MultiInstanceManager.mergedOnStartup();
}
// Instantiate TabModelSelectorImpl
Pair<Integer, TabModelSelector> selectorAssignment =
TabWindowManagerSingleton.getInstance().requestSelector(
activity, tabCreatorManager, nextTabPolicySupplier, selectorIndex);
int assignedIndex = selectorAssignment.first;
mTabModelSelector = (TabModelSelectorImpl) selectorAssignment.second;
if (mTabModelSelector == null) {
markTabModelsInitialized();
Toast.makeText(activity,
activity.getString(
org.chromium.chrome.R.string.unsupported_number_of_windows),
Toast.LENGTH_LONG)
.show();
return false;
}
// Instantiate TabPersistentStore
TabPersistencePolicy tabPersistencePolicy =
new TabbedModeTabPersistencePolicy(assignedIndex, mergeTabs);
mTabPersistentStore =
new TabPersistentStore(tabPersistencePolicy, mTabModelSelector, tabCreatorManager);
wireSelectorAndStore();
markTabModelsInitialized();
return true;
}
private boolean shouldMergeTabs(Activity activity) {
// Merge tabs if this TabModelSelector is for a ChromeTabbedActivity created in
// fullscreen mode and there are no TabModelSelector's currently alive. This indicates
// that it is a cold start or process restart in fullscreen mode.
boolean mergeTabs = Build.VERSION.SDK_INT > Build.VERSION_CODES.M
&& MultiInstanceManager.isTabModelMergingEnabled()
&& !activity.isInMultiWindowMode();
if (MultiInstanceManager.shouldMergeOnStartup(activity)) {
mergeTabs = mergeTabs
&& (!MultiWindowUtils.getInstance().isInMultiDisplayMode(activity)
|| TabWindowManagerSingleton.getInstance()
.getNumberOfAssignedTabModelSelectors()
== 0);
} else {
mergeTabs = mergeTabs
&& TabWindowManagerSingleton.getInstance()
.getNumberOfAssignedTabModelSelectors()
== 0;
}
return mergeTabs;
}
}
......@@ -24,6 +24,7 @@ import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeApplication;
import org.chromium.chrome.browser.KeyboardShortcuts;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.ui.controller.Verifier;
import org.chromium.chrome.browser.browserservices.ui.trustedwebactivity.TrustedWebActivityCoordinator;
......@@ -45,7 +46,6 @@ import org.chromium.chrome.browser.night_mode.SystemNightModeMonitor;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabState;
import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.theme.TopUiThemeColorProvider;
import org.chromium.chrome.browser.ui.RootUiCoordinator;
......@@ -293,8 +293,20 @@ public abstract class BaseCustomTabActivity extends ChromeActivity<BaseCustomTab
}
@Override
protected TabModelSelector createTabModelSelector() {
return mTabFactory.createTabModelSelector();
protected TabModelOrchestrator createTabModelOrchestrator() {
return mTabFactory.createTabModelOrchestrator();
}
@Override
protected void destroyTabModels() {
if (mTabFactory != null) {
mTabFactory.destroyTabModelOrchestrator();
}
}
@Override
protected void createTabModels() {
mTabFactory.createTabModels();
}
@Override
......
......@@ -15,6 +15,8 @@ import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton;
import org.chromium.chrome.browser.app.tabmodel.ChromeTabModelFilterFactory;
import org.chromium.chrome.browser.app.tabmodel.CustomTabsTabModelOrchestrator;
import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
import org.chromium.chrome.browser.customtabs.CustomTabTabPersistencePolicy;
......@@ -26,7 +28,6 @@ import org.chromium.chrome.browser.tab.TabDelegateFactory;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
import org.chromium.chrome.browser.tabmodel.NextTabPolicy;
import org.chromium.chrome.browser.tabmodel.TabModelFilterFactory;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
......@@ -56,7 +57,7 @@ public class CustomTabActivityTabFactory {
private final Lazy<AsyncTabParamsManager> mAsyncTabParamsManager;
@Nullable
private TabModelSelectorImpl mTabModelSelector;
private CustomTabsTabModelOrchestrator mTabModelOrchestrator;
@Inject
public CustomTabActivityTabFactory(ChromeActivity<?> activity,
......@@ -77,21 +78,35 @@ public class CustomTabActivityTabFactory {
mAsyncTabParamsManager = asyncTabParamsManager;
}
/** Creates a {@link TabModelSelector} for the custom tab. */
public TabModelSelectorImpl createTabModelSelector() {
mTabModelSelector = new TabModelSelectorImpl(mActivity, mActivityWindowAndroid::get,
mActivity, mPersistencePolicy, mTabModelFilterFactory,
() -> NextTabPolicy.LOCATIONAL, mAsyncTabParamsManager.get(), false, false, false);
return mTabModelSelector;
/** Creates a {@link TabModelOrchestrator} for the custom tab. */
public TabModelOrchestrator createTabModelOrchestrator() {
mTabModelOrchestrator = new CustomTabsTabModelOrchestrator();
return mTabModelOrchestrator;
}
public void destroyTabModelOrchestrator() {
if (mTabModelOrchestrator != null) {
mTabModelOrchestrator.destroy();
}
}
/** Calls the {@link TabModelOrchestrator} to create TabModels and TabPersistentStore. */
public void createTabModels() {
mTabModelOrchestrator.createTabModels(mActivityWindowAndroid::get, mActivity,
mTabModelFilterFactory, mPersistencePolicy, mAsyncTabParamsManager.get());
}
/** Returns the previously created {@link TabModelSelector}. */
public TabModelSelectorImpl getTabModelSelector() {
if (mTabModelSelector == null) {
if (mTabModelOrchestrator == null) {
assert false;
createTabModelOrchestrator();
}
if (mTabModelOrchestrator.getTabModelSelector() == null) {
assert false;
return createTabModelSelector();
createTabModels();
}
return mTabModelSelector;
return mTabModelOrchestrator.getTabModelSelector();
}
/** Creates a {@link ChromeTabCreator}s for the custom tab. */
......
......@@ -34,12 +34,11 @@ import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton;
import org.chromium.chrome.browser.app.tabmodel.ChromeTabModelFilterFactory;
import org.chromium.chrome.browser.app.tabmodel.CustomTabsTabModelOrchestrator;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.tab.MockTab;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabStateFileManager;
import org.chromium.chrome.browser.tabmodel.NextTabPolicy;
import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.tabmodel.TabPersistencePolicy;
......@@ -456,12 +455,11 @@ public class CustomTabTabPersistencePolicyTest {
CustomTabActivity activity = new CustomTabActivity();
ApplicationStatus.onStateChangeForTesting(activity, ActivityState.CREATED);
NextTabPolicySupplier nextTabPolicySupplier = () -> NextTabPolicy.LOCATIONAL;
TabModelSelectorImpl selector = new TabModelSelectorImpl(activity,
activity::getWindowAndroid, activity, buildTestPersistencePolicy(),
new ChromeTabModelFilterFactory(), nextTabPolicySupplier,
AsyncTabParamsManagerSingleton.getInstance(), false, false, false);
CustomTabsTabModelOrchestrator orchestrator = new CustomTabsTabModelOrchestrator();
orchestrator.createTabModels(activity::getWindowAndroid, activity,
new ChromeTabModelFilterFactory(), buildTestPersistencePolicy(),
AsyncTabParamsManagerSingleton.getInstance());
TabModelSelectorImpl selector = orchestrator.getTabModelSelector();
selector.initializeForTesting(normalTabModel, incognitoTabModel);
ApplicationStatus.onStateChangeForTesting(activity, ActivityState.DESTROYED);
return selector;
......
......@@ -74,8 +74,7 @@ public class ContextMenuLoadUrlParamsTest {
public RecordingTabModelSelector(Activity activity, TabCreatorManager tabCreatorManager,
TabModelFilterFactory tabModelFilterFactory, int selectorIndex) {
super(activity, null, tabCreatorManager,
new TabbedModeTabPersistencePolicy(selectorIndex, false), tabModelFilterFactory,
super(null, tabCreatorManager, tabModelFilterFactory,
()
-> NextTabPolicy.HIERARCHICAL,
AsyncTabParamsManagerSingleton.getInstance(), false, false, false);
......
......@@ -361,7 +361,9 @@ public class TabModelMergingTest {
MockTabPersistentStoreObserver mockObserver = new MockTabPersistentStoreObserver();
TabModelSelectorImpl tabModelSelector =
(TabModelSelectorImpl) mActivity2.getTabModelSelector();
tabModelSelector.getTabPersistentStoreForTesting().addObserver(mockObserver);
TestThreadUtils.runOnUiThreadBlocking(() -> {
tabModelSelector.getTabPersistentStoreForTesting().addObserver(mockObserver);
});
// Merge tabs into ChromeTabbedActivity2. Wait for the merge to finish, ensuring the
// tab metadata file for ChromeTabbedActivity gets deleted before attempting to merge
......
......@@ -32,6 +32,7 @@ import org.chromium.chrome.browser.accessibility_tab_switcher.OverviewListLayout
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.app.tabmodel.AsyncTabParamsManagerSingleton;
import org.chromium.chrome.browser.app.tabmodel.ChromeTabModelFilterFactory;
import org.chromium.chrome.browser.app.tabmodel.TabModelOrchestrator;
import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelper;
import org.chromium.chrome.browser.flags.ActivityType;
......@@ -246,10 +247,16 @@ public class TabPersistentStoreTest {
}
@Override
protected TabModelSelector createTabModelSelector() {
protected TabModelOrchestrator createTabModelOrchestrator() {
return null;
}
@Override
protected void createTabModels() {}
@Override
protected void destroyTabModels() {}
@Override
protected BrowserControlsManager createBrowserControlsManager() {
return null;
......@@ -721,8 +728,9 @@ public class TabPersistentStoreTest {
// createAndRestoreRealTabModelImpls is called multiple times in one test).
sTabWindowManager.onActivityStateChange(
mChromeActivity, ActivityState.DESTROYED);
return (TestTabModelSelector) sTabWindowManager.requestSelector(
mChromeActivity, mChromeActivity, null, 0);
return (TestTabModelSelector) sTabWindowManager
.requestSelector(mChromeActivity, mChromeActivity, null, 0)
.second;
}
});
......
......@@ -8,8 +8,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import android.app.Activity;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
......@@ -17,7 +15,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner;
......@@ -37,8 +34,6 @@ import org.chromium.ui.base.WindowAndroid;
@RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class TabModelSelectorImplTest {
@Mock
TabPersistencePolicy mMockTabPersistencePolicy;
@Mock
TabModelFilterFactory mMockTabModelFilterFactory;
@Mock
......@@ -50,27 +45,22 @@ public class TabModelSelectorImplTest {
private TabModelSelectorImpl mTabModelSelector;
private MockTabCreatorManager mTabCreatorManager;
private Activity mActivity;
@Before
public void setUp() {
mActivity = Robolectric.buildActivity(Activity.class).setup().get();
MockitoAnnotations.initMocks(this);
doReturn(TabPersistentStore.SAVED_STATE_FILE_PREFIX)
.when(mMockTabPersistencePolicy)
.getStateFileName();
doReturn(mock(TabModelFilter.class))
.when(mMockTabModelFilterFactory)
.createTabModelFilter(any());
mTabCreatorManager = new MockTabCreatorManager();
AsyncTabParamsManager realAsyncTabParamsManager =
AsyncTabParamsManagerFactory.createAsyncTabParamsManager();
mTabModelSelector = new TabModelSelectorImpl(mActivity, null, mTabCreatorManager,
mMockTabPersistencePolicy, mMockTabModelFilterFactory, mNextTabPolicySupplier,
realAsyncTabParamsManager, /*supportUndo=*/false,
mTabModelSelector = new TabModelSelectorImpl(null, mTabCreatorManager,
mMockTabModelFilterFactory, mNextTabPolicySupplier, realAsyncTabParamsManager,
/*supportUndo=*/false,
/*isTabbedActivity=*/false, /*startIncognito=*/false);
mTabModelSelector.setTabPersistentStoreSupplier(() -> null);
mTabCreatorManager.initialize(mTabModelSelector);
mTabModelSelector.onNativeLibraryReadyInternal(mMockTabContentManager,
new MockTabModel(false, null), new MockTabModel(true, null));
......
......@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.tabmodel;
import android.app.Activity;
import android.util.Pair;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.NextTabPolicy.NextTabPolicySupplier;
......@@ -34,11 +35,13 @@ public interface TabWindowManager {
* @param nextTabPolicySupplier An instance of {@link NextTabPolicySupplier}.
* @param index The index of the requested {@link TabModelSelector}. Not guaranteed to be the
* index of the {@link TabModelSelector} returned.
* @return A {@link TabModelSelector} index, or {@code null} if there are too many
* @return {@link Pair} of the index and the {@link TabModelSelector} assigned to that index, or
* {@code null} if there are too many
* {@link TabModelSelector}s already built.
*/
TabModelSelector requestSelector(Activity activity, TabCreatorManager tabCreatorManager,
NextTabPolicySupplier nextTabPolicySupplier, int index);
Pair<Integer, TabModelSelector> requestSelector(Activity activity,
TabCreatorManager tabCreatorManager, NextTabPolicySupplier nextTabPolicySupplier,
int index);
/**
* An index that represents the invalid state (i.e. when the window wasn't found in the list).
......
......@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.tabmodel;
import android.app.Activity;
import android.util.Pair;
import android.util.SparseArray;
import org.chromium.base.ActivityState;
......@@ -43,10 +44,18 @@ public class TabWindowManagerImpl implements ActivityStateListener, TabWindowMan
}
@Override
public TabModelSelector requestSelector(Activity activity, TabCreatorManager tabCreatorManager,
NextTabPolicySupplier nextTabPolicySupplier, int index) {
public Pair<Integer, TabModelSelector> requestSelector(Activity activity,
TabCreatorManager tabCreatorManager, NextTabPolicySupplier nextTabPolicySupplier,
int index) {
if (mAssignments.get(activity) != null) {
return mAssignments.get(activity);
TabModelSelector assignedSelector = mAssignments.get(activity);
for (int i = 0; i < mSelectors.size(); i++) {
if (mSelectors.get(i) == assignedSelector) {
return Pair.create(i, assignedSelector);
}
}
throw new IllegalStateException(
"TabModelSelector is assigned to an Activity but has no index.");
}
if (index < 0 || index >= mSelectors.size()) index = 0;
......@@ -68,7 +77,7 @@ public class TabWindowManagerImpl implements ActivityStateListener, TabWindowMan
mSelectors.set(index, selector);
mAssignments.put(activity, selector);
return selector;
return Pair.create(index, selector);
}
@Override
......
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