Commit 40a4a6b6 authored by Xi Han's avatar Xi Han Committed by Commit Bot

[Instant Start] Supports stack tab switcher.

In this CL, we remove the check of stack tab switcher in
TabUiFeatureUtilities#supportInstantStart(). Thus instant start can be
enabled in MVP++. These changes can be verified by:
- StartSurfaceTest#testShow_SingleAsHomepage_V2__Instant*.

The following changes are made to support stack tab switcher in instant
start:
1) Defer the creation of TabList in StackLayoutBase. It allows the
   StackLayoutBase/StartSurfaceStackLayout to be created pre-native.
2) Add pending observer list in TabModelFilterProvider. Any observer
   which is added before the TabModelFilterProvider is initialized, will
   be cached and notified when the initialization is completed.
3) StartSurfaceLayout and StackLayoutBase will create its SceneLayer if
   hasn't yet before calling updateSceneLayer().

Bug: 1116449, 1076449
Change-Id: I42a730045d4b9799d4bb08dc7d7dc947956f42ac
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2356167Reviewed-by: default avatarHenrique Nakashima <hnakashima@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Commit-Queue: Xi Han <hanxi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810924}
parent dc7c12e1
......@@ -108,7 +108,7 @@ public class StartSurfaceLayout extends Layout implements StartSurface.OverviewM
mIsInitialized = true;
mStartSurface.initWithNative();
mSceneLayer = new TabListSceneLayer();
ensureSceneLayerCreated();
mSceneLayer.setTabModelSelector(mTabModelSelector);
}
......@@ -214,6 +214,7 @@ public class StartSurfaceLayout extends Layout implements StartSurface.OverviewM
@Override
protected void updateLayout(long time, long dt) {
ensureSceneLayerCreated();
super.updateLayout(time, dt);
if (mLayoutTabs == null) return;
......@@ -274,6 +275,11 @@ public class StartSurfaceLayout extends Layout implements StartSurface.OverviewM
return mSceneLayer;
}
private void ensureSceneLayerCreated() {
if (mSceneLayer != null) return;
mSceneLayer = new TabListSceneLayer();
}
@Override
public boolean handlesTabClosing() {
return true;
......@@ -478,6 +484,7 @@ public class StartSurfaceLayout extends Layout implements StartSurface.OverviewM
protected void updateSceneLayer(RectF viewport, RectF contentViewport,
LayerTitleCache layerTitleCache, TabContentManager tabContentManager,
ResourceManager resourceManager, BrowserControlsStateProvider browserControls) {
ensureSceneLayerCreated();
super.updateSceneLayer(viewport, contentViewport, layerTitleCache, tabContentManager,
resourceManager, browserControls);
assert mSceneLayer != null;
......
......@@ -35,6 +35,7 @@ public class StartSurfaceStackLayout extends StackLayout {
mIsInitialized = true;
super.onFinishNativeInitialization();
super.initWithNative();
mCoordinator.initWithNative();
}
......@@ -44,6 +45,9 @@ public class StartSurfaceStackLayout extends StackLayout {
mCoordinator.initialize();
mController.showOverview(false);
if (!mIsInitialized) {
return;
}
super.show(time, animate);
}
......
......@@ -690,7 +690,15 @@ public class StartSurfaceTest {
instanceOf(StackLayout.class));
pressBack();
onViewWaiting(withId(R.id.primary_tasks_surface_view));
onView(withId(R.id.primary_tasks_surface_view));
if (isInstantReturn()
&& (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.O)) {
// TODO(crbug.com/1092642): Fix androidx.test.espresso.PerformException issue when
// performing a single click on position: 0. See code below.
return;
}
OverviewModeBehaviorWatcher hideWatcher =
TabUiTestHelper.createOverviewHideWatcher(mActivityTestRule.getActivity());
......
......@@ -175,11 +175,8 @@ public class TabUiFeatureUtilities {
* @return Whether the instant start is supported.
*/
public static boolean supportInstantStart(boolean isTablet) {
// TODO(crbug.com/1076449): Support instant start when the stack tab switcher is
// enabled.
return !DeviceClassManager.enableAccessibilityLayout()
&& CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START) && !isTablet
&& !StartSurfaceConfiguration.isStartSurfaceStackTabSwitcherEnabled();
&& CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START) && !isTablet;
}
/**
......
......@@ -56,6 +56,7 @@ public class ChromeCachedFlags {
ChromeFeatureList.CONDITIONAL_TAB_STRIP_ANDROID,
ChromeFeatureList.DOWNLOADS_AUTO_RESUMPTION_NATIVE,
ChromeFeatureList.HOMEPAGE_LOCATION_POLICY,
ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID,
ChromeFeatureList.IMMERSIVE_UI_MODE,
ChromeFeatureList.INSTANT_START,
ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS,
......
......@@ -453,6 +453,9 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
// Initialize Layouts
mStaticLayout.onFinishNativeInitialization();
if (mTabModelSelector == null) {
setTabModelSelector(selector);
}
// Contextual Search scene overlay.
mContextualSearchPanel = new ContextualSearchPanel(mContext, this, mOverlayPanelManager);
......@@ -477,10 +480,6 @@ public class LayoutManager implements LayoutUpdateHost, LayoutProvider,
// Set the dynamic resource loader for all overlay panels.
mOverlayPanelManager.setDynamicResourceLoader(dynamicResourceLoader);
mOverlayPanelManager.setContainerView(mContentContainer);
if (mTabModelSelector != selector) {
setTabModelSelector(selector);
}
}
// TODO(hanxi): Passes the TabModelSelectorSupplier in the constructor since the
......
......@@ -198,8 +198,8 @@ public class LayoutManagerChrome
mToolbarSwipeLayout.setTabModelSelector(selector, content);
mOverviewListLayout.setTabModelSelector(selector, content);
if (mOverviewLayout != null) {
mOverviewLayout.onFinishNativeInitialization();
mOverviewLayout.setTabModelSelector(selector, content);
mOverviewLayout.onFinishNativeInitialization();
}
}
......
......@@ -56,6 +56,9 @@ public class StackLayout extends StackLayoutBase {
@Override
public void setTabModelSelector(TabModelSelector modelSelector, TabContentManager manager) {
super.setTabModelSelector(modelSelector, manager);
if (modelSelector.getTabModelFilterProvider().getCurrentTabModelFilter() == null) {
return;
}
ArrayList<TabList> tabLists = new ArrayList<TabList>();
tabLists.add(modelSelector.getTabModelFilterProvider().getTabModelFilter(false));
tabLists.add(modelSelector.getTabModelFilterProvider().getTabModelFilter(true));
......
......@@ -43,6 +43,7 @@ import org.chromium.chrome.browser.compositor.layouts.phone.stack.Stack;
import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackTab;
import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer;
import org.chromium.chrome.browser.compositor.scene_layer.TabListSceneLayer;
import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.homepage.HomepageManager;
import org.chromium.chrome.browser.tab.Tab;
......@@ -226,7 +227,6 @@ public abstract class StackLayoutBase extends Layout {
private final ViewGroup mViewContainer;
private final GestureEventFilter mGestureEventFilter;
private final TabListSceneLayer mSceneLayer;
private StackLayoutGestureHandler mGestureHandler;
......@@ -236,6 +236,8 @@ public abstract class StackLayoutBase extends Layout {
private final ObservableSupplier<BrowserControlsStateProvider> mBrowserControlsSupplier;
private final BrowserControlsStateProvider.Observer mBrowserControlsObserver;
private Callback<BrowserControlsStateProvider> mBrowserControlsSupplierObserver;
private TabListSceneLayer mSceneLayer;
private boolean mShowPending;
private class StackLayoutGestureHandler implements GestureHandler {
@Override
......@@ -394,7 +396,7 @@ public abstract class StackLayoutBase extends Layout {
mStacks = new ArrayList<Stack>();
mStackRects = new ArrayList<RectF>();
mViewContainer = new FrameLayout(getContext());
mSceneLayer = new TabListSceneLayer();
mDpToPx = context.getResources().getDisplayMetrics().density;
mBrowserControlsSupplier = browserControlsStateProviderSupplier;
mBrowserControlsObserver = new BrowserControlsStateProvider.Observer() {
......@@ -413,6 +415,14 @@ public abstract class StackLayoutBase extends Layout {
mBrowserControlsSupplier.addObserver(mBrowserControlsSupplierObserver);
}
public void initWithNative() {
ensureSceneLayerCreated();
if (mShowPending) {
mShowPending = false;
show(LayoutManager.time(), false);
}
}
@Override
public void destroy() {
if (mBrowserControlsSupplier != null) {
......@@ -441,7 +451,7 @@ public abstract class StackLayoutBase extends Layout {
* switcher in both portrait and landscape mode) is enabled.
*/
protected boolean isHorizontalTabSwitcherFlagEnabled() {
return ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID);
return CachedFeatureFlags.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID);
}
/**
......@@ -526,7 +536,9 @@ public abstract class StackLayoutBase extends Layout {
@Override
public void setTabModelSelector(TabModelSelector modelSelector, TabContentManager manager) {
super.setTabModelSelector(modelSelector, manager);
if (mSceneLayer != null) {
mSceneLayer.setTabModelSelector(modelSelector);
}
resetScrollData();
new TabModelSelectorTabModelObserver(mTabModelSelector) {
......@@ -713,6 +725,10 @@ public abstract class StackLayoutBase extends Layout {
super.onTabRestored(time, tabId);
// Call show() so that new stack tabs and potentially new stacks get created.
// TODO(twellington): add animation for showing the restored tab.
if (mSceneLayer == null) {
mShowPending = true;
return;
}
show(time, false);
}
......@@ -1321,6 +1337,8 @@ public abstract class StackLayoutBase extends Layout {
@Override
protected void updateLayout(long time, long dt) {
if (mStacks.size() == 0) return;
super.updateLayout(time, dt);
boolean needUpdate = false;
......@@ -1641,10 +1659,16 @@ public abstract class StackLayoutBase extends Layout {
return mSceneLayer;
}
private void ensureSceneLayerCreated() {
if (mSceneLayer != null) return;
mSceneLayer = new TabListSceneLayer();
}
@Override
protected void updateSceneLayer(RectF viewport, RectF contentViewport,
LayerTitleCache layerTitleCache, TabContentManager tabContentManager,
ResourceManager resourceManager, BrowserControlsStateProvider browserControls) {
ensureSceneLayerCreated();
super.updateSceneLayer(viewport, contentViewport, layerTitleCache, tabContentManager,
resourceManager, browserControls);
assert mSceneLayer != null;
......
......@@ -24,6 +24,7 @@ import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
import org.chromium.chrome.browser.compositor.layouts.eventfilter.ScrollDirection;
import org.chromium.chrome.browser.compositor.layouts.phone.StackLayoutBase;
import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackAnimation.OverviewAnimationType;
import org.chromium.chrome.browser.flags.CachedFeatureFlags;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.TabList;
......@@ -450,6 +451,8 @@ public abstract class Stack {
* @return Whether or not the TabList represented by this TabStackState should be displayed.
*/
public boolean isDisplayable() {
if (mTabList == null) return false;
return !mTabList.isIncognito() || (!mIsDying && mTabList.getCount() > 0);
}
......@@ -1714,6 +1717,8 @@ public abstract class Stack {
* restored if we're calling this while the switcher is already visible.
*/
private void createStackTabs(boolean restoreState) {
if (mTabList == null) return;
final int count = mTabList.getCount();
if (count == 0) {
cleanupTabs();
......@@ -2027,7 +2032,7 @@ public abstract class Stack {
}
protected void updateCurrentMode(@Orientation int orientation) {
if (ChromeFeatureList.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) {
if (CachedFeatureFlags.isEnabled(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID)) {
mCurrentMode = Orientation.LANDSCAPE;
} else {
mCurrentMode = orientation;
......
......@@ -58,7 +58,7 @@ public abstract class TabModelSelectorBase implements TabModelSelector, Incognit
mIncognitoTabModel = incognitoModel;
mActiveModelIndex = getModelIndex(mStartIncognito);
assert mActiveModelIndex != MODEL_NOT_FOUND;
mTabModelFilterProvider = new TabModelFilterProvider(mTabModelFilterFactory, mTabModels);
mTabModelFilterProvider.init(mTabModelFilterFactory, mTabModels);
addObserver(mTabModelFilterProvider);
TabModelObserver tabModelObserver = new TabModelObserver() {
......
......@@ -156,6 +156,9 @@ public class LayoutManagerTest implements MockTabModelDelegate {
TabModelUtils.setIndex(mTabModelSelector.getModel(true), incognitoIndexSelected);
}
mTabModelSelector.selectModel(incognitoSelected);
Assert.assertNotNull(
mTabModelSelector.getTabModelFilterProvider().getCurrentTabModelFilter());
LayoutManagerHost layoutManagerHost = new MockLayoutHost(context);
TabContentManager tabContentManager = new TabContentManager(context, null, false, null);
tabContentManager.initWithNative();
......
......@@ -51,6 +51,7 @@ public class CachedFeatureFlags {
put(ChromeFeatureList.ANDROID_PARTNER_CUSTOMIZATION_PHENOTYPE, true);
put(ChromeFeatureList.CONDITIONAL_TAB_STRIP_ANDROID, false);
put(ChromeFeatureList.HOMEPAGE_LOCATION_POLICY, false);
put(ChromeFeatureList.HORIZONTAL_TAB_SWITCHER_ANDROID, false);
put(ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD, false);
put(ChromeFeatureList.SERVICE_MANAGER_FOR_BACKGROUND_PREFETCH, true);
put(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS, true);
......
......@@ -15,23 +15,40 @@ import java.util.List;
*/
public class TabModelFilterProvider extends EmptyTabModelSelectorObserver {
private List<TabModelFilter> mTabModelFilterList = Collections.emptyList();
private final List<TabModelObserver> mPendingTabModelObserver = new ArrayList<>();
TabModelFilterProvider() {}
TabModelFilterProvider(TabModelFilterFactory tabModelFilterFactory, List<TabModel> tabModels) {
public void init(TabModelFilterFactory tabModelFilterFactory, List<TabModel> tabModels) {
assert mTabModelFilterList.isEmpty();
assert tabModels.size() > 0;
List<TabModelFilter> filters = new ArrayList<>();
for (int i = 0; i < tabModels.size(); i++) {
filters.add(tabModelFilterFactory.createTabModelFilter(tabModels.get(i)));
}
mTabModelFilterList = Collections.unmodifiableList(filters);
// Registers the pending observers.
for (TabModelObserver observer : mPendingTabModelObserver) {
for (TabModelFilter tabModelFilter : mTabModelFilterList) {
tabModelFilter.addObserver(observer);
}
}
mPendingTabModelObserver.clear();
}
/**
* This method adds {@link TabModelObserver} to both {@link TabModelFilter}s.
* This method adds {@link TabModelObserver} to both {@link TabModelFilter}s. Caches the
* observer until {@link TabModelFilter}s are created.
* @param observer {@link TabModelObserver} to add.
*/
public void addTabModelFilterObserver(TabModelObserver observer) {
if (mTabModelFilterList.isEmpty()) {
mPendingTabModelObserver.add(observer);
return;
}
for (int i = 0; i < mTabModelFilterList.size(); i++) {
mTabModelFilterList.get(i).addObserver(observer);
}
......@@ -42,6 +59,11 @@ public class TabModelFilterProvider extends EmptyTabModelSelectorObserver {
* @param observer {@link TabModelObserver} to remove.
*/
public void removeTabModelFilterObserver(TabModelObserver observer) {
if (mTabModelFilterList.isEmpty() && !mPendingTabModelObserver.isEmpty()) {
mPendingTabModelObserver.remove(observer);
return;
}
for (int i = 0; i < mTabModelFilterList.size(); i++) {
mTabModelFilterList.get(i).removeObserver(observer);
}
......@@ -83,6 +105,7 @@ public class TabModelFilterProvider extends EmptyTabModelSelectorObserver {
for (int i = 0; i < mTabModelFilterList.size(); i++) {
mTabModelFilterList.get(i).destroy();
}
mPendingTabModelObserver.clear();
}
private void markTabStateInitialized() {
......
......@@ -42,6 +42,7 @@ public class MockTabModel extends EmptyTabModel implements IncognitoTabModel {
private final ArrayList<Tab> mTabs = new ArrayList<Tab>();
private final boolean mIncognito;
private final MockTabModelDelegate mDelegate;
private boolean mIsCurrentModel;
public MockTabModel(boolean incognito, MockTabModelDelegate delegate) {
mIncognito = incognito;
......@@ -122,4 +123,13 @@ public class MockTabModel extends EmptyTabModel implements IncognitoTabModel {
@Override
public void removeIncognitoObserver(IncognitoTabModelObserver observer) {}
@Override
public boolean isCurrentModel() {
return mIsCurrentModel;
}
public void setAsCurrentModelForTesting() {
mIsCurrentModel = true;
}
}
......@@ -64,4 +64,10 @@ public class MockTabModelSelector extends TabModelSelectorBase {
public int getTotalTabCount() {
throw new UnsupportedOperationException();
}
@Override
public void selectModel(boolean incognito) {
super.selectModel(incognito);
((MockTabModel) getModel(incognito)).setAsCurrentModelForTesting();
}
}
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