[go: up one dir, main page]

[Merge M104][TabSwitcher][Tablet] Create start surface on first switcher load instead of on startup

(cherry picked from commit 5162b6e71f750cd98596ef7f8c0ea718eac8ed57)

Bug: 1333479
Change-Id: Idb40978699078b7f3b99d1470b4fe14eec993bb1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3735147
Reviewed-by: Theresa Sullivan <twellington@chromium.org>
Commit-Queue: Sirisha Kavuluru <skavuluru@google.com>
Auto-Submit: Sirisha Kavuluru <skavuluru@google.com>
Reviewed-by: Mei Liang <meiliang@chromium.org>
Reviewed-by: Neil Coronado <nemco@google.com>
Reviewed-by: Michael Thiessen <mthiesse@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1021262}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3756816
Cr-Commit-Position: refs/branch-heads/5112@{#818}
Cr-Branched-From: b13d3fe7b3c47a56354ef54b221008afa754412e-refs/heads/main@{#1012729}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
index 305c6ee..70f0903 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherCoordinator.java
@@ -8,6 +8,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
+import android.os.SystemClock;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
@@ -18,6 +19,8 @@
 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
 
 import org.chromium.base.Callback;
+import org.chromium.base.TraceEvent;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.Supplier;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
@@ -39,6 +42,7 @@
 import org.chromium.chrome.browser.tasks.pseudotab.TabAttributeCache;
 import org.chromium.chrome.browser.tasks.tab_management.PriceMessageService.PriceMessageType;
 import org.chromium.chrome.browser.tasks.tab_management.TabListCoordinator.TabListMode;
+import org.chromium.chrome.browser.tasks.tab_management.TabSelectionEditorCoordinator.TabSelectionEditorController;
 import org.chromium.chrome.browser.tasks.tab_management.TabSelectionEditorCoordinator.TabSelectionEditorNavigationProvider;
 import org.chromium.chrome.browser.tasks.tab_management.suggestions.TabSuggestionsOrchestrator;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
@@ -107,6 +111,7 @@
     private final TabListCoordinator mTabListCoordinator;
     private final TabSwitcherMediator mMediator;
     private final MultiThumbnailCardProvider mMultiThumbnailCardProvider;
+    @Nullable
     private final TabGridDialogCoordinator mTabGridDialogCoordinator;
     private final TabModelSelector mTabModelSelector;
     private final @TabListCoordinator.TabListMode int mMode;
@@ -115,8 +120,9 @@
     private final Supplier<DynamicResourceLoader> mDynamicResourceLoaderSupplier;
     private final SnackbarManager mSnackbarManager;
     private final ModalDialogManager mModalDialogManager;
-
+    @Nullable
     private TabSelectionEditorCoordinator mTabSelectionEditorCoordinator;
+    @Nullable
     private TabGroupManualSelectionMode mTabGroupManualSelectionMode;
     private TabSuggestionsOrchestrator mTabSuggestionsOrchestrator;
     private NewTabTileCoordinator mNewTabTileCoordinator;
@@ -144,7 +150,7 @@
                             || (!sIsGridTabSwitcherShowing && mMode == TabListMode.GRID)) {
                         return false;
                     }
-                    if (id == R.id.menu_group_tabs) {
+                    if (id == R.id.menu_group_tabs && mTabSelectionEditorCoordinator != null) {
                         assert mTabGroupManualSelectionMode != null;
 
                         mTabSelectionEditorCoordinator.getController().configureToolbar(
@@ -218,6 +224,7 @@
                     R.plurals.bottom_tab_grid_title_placeholder, numRelatedTabs, numRelatedTabs);
         };
 
+        long startTimeMs = SystemClock.uptimeMillis();
         mTabListCoordinator = new TabListCoordinator(mode, activity, tabModelSelector,
                 mMultiThumbnailCardProvider, titleProvider, true, mMediator, null,
                 TabProperties.UiType.CLOSABLE, null, this, container, true, COMPONENT_NAME,
@@ -225,6 +232,9 @@
         mContainerViewChangeProcessor = PropertyModelChangeProcessor.create(containerViewModel,
                 mTabListCoordinator.getContainerView(), TabListContainerViewBinder::bind);
 
+        RecordHistogram.recordTimesHistogram("Android.TabSwitcher.SetupRecyclerView.Time",
+                SystemClock.uptimeMillis() - startTimeMs);
+
         mMediator.addTabSwitcherViewObserver(new TabSwitcherViewObserver() {
             @Override
             public void startedShowing() {
@@ -378,68 +388,84 @@
     @Override
     public void initWithNative() {
         if (mIsInitialized) return;
+        try (TraceEvent e = TraceEvent.scoped("TabSwitcherCoordinator.initWithNative")) {
+            mTabListCoordinator.initWithNative(mDynamicResourceLoaderSupplier.get());
 
-        setUpTabGroupManualSelectionMode(mActivity, mTabContentManager, mSnackbarManager);
-
-        mTabListCoordinator.initWithNative(mDynamicResourceLoaderSupplier.get());
-        if (mTabGridDialogCoordinator != null) {
-            mTabGridDialogCoordinator.initWithNative(mActivity, mTabModelSelector,
-                    mTabContentManager, mTabListCoordinator.getTabGroupTitleEditor());
-        }
-
-        mMultiThumbnailCardProvider.initWithNative();
-
-        if (mMode == TabListCoordinator.TabListMode.GRID) {
-            if (CachedFeatureFlags.isEnabled(ChromeFeatureList.CLOSE_TAB_SUGGESTIONS)) {
-                mTabSuggestionsOrchestrator = new TabSuggestionsOrchestrator(
-                        mActivity, mTabModelSelector, mLifecycleDispatcher);
-                TabSuggestionMessageService tabSuggestionMessageService =
-                        new TabSuggestionMessageService(mActivity, mTabModelSelector,
-                                mTabSelectionEditorCoordinator.getController());
-                mTabSuggestionsOrchestrator.addObserver(tabSuggestionMessageService);
-                mMessageCardProviderCoordinator.subscribeMessageService(
-                        tabSuggestionMessageService);
-            }
-
-            if (TabUiFeatureUtilities.isTabGridLayoutAndroidNewTabTileEnabled()) {
-                mNewTabTileCoordinator =
-                        new NewTabTileCoordinator(mTabModelSelector, mTabCreatorManager);
-            }
-
+            // Selector editor required for tab groups and close tab suggestions.
             if (TabUiFeatureUtilities.isTabGroupsAndroidEnabled(mActivity)
-                    && !TabSwitcherCoordinator.isShowingTabsInMRUOrder(mMode)) {
-                mTabGridIphDialogCoordinator =
-                        new TabGridIphDialogCoordinator(mActivity, mContainer, mModalDialogManager);
-                IphMessageService iphMessageService =
-                        new IphMessageService(mTabGridIphDialogCoordinator);
-                mMessageCardProviderCoordinator.subscribeMessageService(iphMessageService);
+                    || CachedFeatureFlags.isEnabled(ChromeFeatureList.CLOSE_TAB_SUGGESTIONS)) {
+                setUpTabSelectionEditorCoordinator(mActivity, mTabContentManager);
             }
+            if (TabUiFeatureUtilities.isTabGroupsAndroidEnabled(mActivity)) {
+                setUpTabGroupManualSelectionMode(mActivity);
+                if (mTabGridDialogCoordinator != null) {
+                    mTabGridDialogCoordinator.initWithNative(mActivity, mTabModelSelector,
+                            mTabContentManager, mTabListCoordinator.getTabGroupTitleEditor());
+                }
+            }
+
+            final TabSelectionEditorController controller = mTabSelectionEditorCoordinator != null
+                    ? mTabSelectionEditorCoordinator.getController()
+                    : null;
+
+            if (mMode == TabListCoordinator.TabListMode.GRID) {
+                if (CachedFeatureFlags.isEnabled(ChromeFeatureList.CLOSE_TAB_SUGGESTIONS)) {
+                    mTabSuggestionsOrchestrator = new TabSuggestionsOrchestrator(
+                            mActivity, mTabModelSelector, mLifecycleDispatcher);
+                    TabSuggestionMessageService tabSuggestionMessageService =
+                            new TabSuggestionMessageService(
+                                    mActivity, mTabModelSelector, controller);
+                    mTabSuggestionsOrchestrator.addObserver(tabSuggestionMessageService);
+                    mMessageCardProviderCoordinator.subscribeMessageService(
+                            tabSuggestionMessageService);
+                }
+
+                if (TabUiFeatureUtilities.isTabGridLayoutAndroidNewTabTileEnabled()) {
+                    mNewTabTileCoordinator =
+                            new NewTabTileCoordinator(mTabModelSelector, mTabCreatorManager);
+                }
+
+                if (TabUiFeatureUtilities.isTabGroupsAndroidEnabled(mActivity)
+                        && !TabSwitcherCoordinator.isShowingTabsInMRUOrder(mMode)) {
+                    mTabGridIphDialogCoordinator = new TabGridIphDialogCoordinator(
+                            mActivity, mContainer, mModalDialogManager);
+                    IphMessageService iphMessageService =
+                            new IphMessageService(mTabGridIphDialogCoordinator);
+                    mMessageCardProviderCoordinator.subscribeMessageService(iphMessageService);
+                }
+            }
+
+            mMultiThumbnailCardProvider.initWithNative();
+            mMediator.initWithNative(controller, mSnackbarManager);
+            // TODO(crbug.com/1222762): Only call setUpPriceTracking in GRID TabSwitcher.
+            setUpPriceTracking(mActivity, mModalDialogManager);
+
+            mIsInitialized = true;
         }
-
-        // TODO(crbug.com/1222762): Only call setUpPriceTracking in GRID TabSwitcher.
-        setUpPriceTracking(mActivity, mModalDialogManager);
-
-        mIsInitialized = true;
     }
 
-    private void setUpTabGroupManualSelectionMode(
-            Context context, TabContentManager tabContentManager, SnackbarManager snackbarManager) {
-        // For tab switcher in carousel mode, the selection editor should still follow grid style.
-        int selectionEditorMode = mMode == TabListCoordinator.TabListMode.CAROUSEL
-                ? TabListCoordinator.TabListMode.GRID
-                : mMode;
+    private void setUpTabGroupManualSelectionMode(Context context) {
+        try (TraceEvent e = TraceEvent.scoped(
+                     "TabSwitcherCoordintor.setUpTabGroupManualSelectionMode")) {
+            mTabGroupManualSelectionMode = new TabGroupManualSelectionMode(
+                    context.getString(R.string.tab_selection_editor_group),
+                    R.plurals.accessibility_tab_selection_editor_group_button, 2,
+                    new TabSelectionEditorActionProvider(
+                            mTabSelectionEditorCoordinator.getController(),
+                            TabSelectionEditorActionProvider.TabSelectionEditorAction.GROUP),
+                    new TabSelectionEditorNavigationProvider(
+                            mTabSelectionEditorCoordinator.getController()));
+        }
+    }
+
+    private void setUpTabSelectionEditorCoordinator(
+            Context context, TabContentManager tabContentManager) {
+        // For tab switcher in carousel mode, the selection editor should still follow grid
+        // style.
+        int selectionEditorMode = mMode == TabListMode.CAROUSEL ? TabListMode.GRID : mMode;
         mTabSelectionEditorCoordinator =
                 new TabSelectionEditorCoordinator(context, mCoordinatorView, mTabModelSelector,
                         tabContentManager, selectionEditorMode, mRootView);
-        mMediator.initWithNative(mTabSelectionEditorCoordinator.getController(), snackbarManager);
-
-        mTabGroupManualSelectionMode = new TabGroupManualSelectionMode(
-                context.getString(R.string.tab_selection_editor_group),
-                R.plurals.accessibility_tab_selection_editor_group_button, 2,
-                new TabSelectionEditorActionProvider(mTabSelectionEditorCoordinator.getController(),
-                        TabSelectionEditorActionProvider.TabSelectionEditorAction.GROUP),
-                new TabSelectionEditorNavigationProvider(
-                        mTabSelectionEditorCoordinator.getController()));
     }
 
     private void setUpPriceTracking(Context context, ModalDialogManager modalDialogManager) {
@@ -474,7 +500,10 @@
 
     @Override
     public Supplier<Boolean> getTabGridDialogVisibilitySupplier() {
-        return mTabGridDialogCoordinator::isVisible;
+        if (mTabGridDialogCoordinator != null) {
+            return mTabGridDialogCoordinator::isVisible;
+        }
+        return () -> false;
     }
 
     @Override
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
index 40293c0b..66fb460 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherMediator.java
@@ -457,12 +457,14 @@
      * @param tabSelectionEditorController The controller that can control the visibility of the
      *                                     TabSelectionEditor.
      */
-    public void initWithNative(
-            TabSelectionEditorCoordinator.TabSelectionEditorController tabSelectionEditorController,
+    public void initWithNative(@Nullable TabSelectionEditorCoordinator
+                                       .TabSelectionEditorController tabSelectionEditorController,
             @Nullable SnackbarManager snackbarManager) {
-        mTabSelectionEditorController = tabSelectionEditorController;
-        mTabSelectionEditorController.getHandleBackPressChangedSupplier().addObserver(
-                this::notifyBackPressStateChanged);
+        if (tabSelectionEditorController != null) {
+            mTabSelectionEditorController = tabSelectionEditorController;
+            mTabSelectionEditorController.getHandleBackPressChangedSupplier().addObserver(
+                    this::notifyBackPressStateChanged);
+        }
         mSnackbarManager = snackbarManager;
     }
 
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java
index 2bdb98d..d1ee3b11 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabUiFeatureUtilities.java
@@ -106,6 +106,12 @@
             new BooleanCachedFieldTrialParameter(ChromeFeatureList.GRID_TAB_SWITCHER_FOR_TABLETS,
                     GRID_TAB_SWITCHER_FOR_TABLETS_POLISH_PARAM, false);
 
+    // Field trial parameter for controlling delay grid tab switcher creation for tablets.
+    private static final String DELAY_GTS_CREATION_PARAM = "delay_creation";
+    public static final BooleanCachedFieldTrialParameter DELAY_GTS_CREATION =
+            new BooleanCachedFieldTrialParameter(ChromeFeatureList.GRID_TAB_SWITCHER_FOR_TABLETS,
+                    DELAY_GTS_CREATION_PARAM, false);
+
     // Field trial parameter for defining tab width for tab strip improvements.
     private static final String TAB_STRIP_IMPROVEMENTS_TAB_WIDTH_PARAM = "min_tab_width";
     public static final DoubleCachedFieldTrialParameter TAB_STRIP_TAB_WIDTH =
@@ -176,6 +182,14 @@
     }
 
     /**
+     * @return Whether the tablet Grid Tab Switcher creation should be delayed to on GTS load
+     *         instead of on startup.
+     */
+    public static boolean isTabletGridTabSwitcherDelayCreationEnabled() {
+        return DELAY_GTS_CREATION.getValue();
+    }
+
+    /**
      * @return Whether the tab group feature is enabled and available for use.
      * @param context The activity context.
      */
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java
index c36dd05..1623912 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabSwitcherTabletTest.java
@@ -18,10 +18,14 @@
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Bitmap;
 import android.support.test.InstrumentationRegistry;
+import android.view.ViewGroup;
+import android.view.ViewStub;
 
 import androidx.test.filters.MediumTest;
 
@@ -35,10 +39,13 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.GarbageCollectionTestUtils;
+import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.RequiresRestart;
 import org.chromium.base.test.util.Restriction;
+import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerImpl;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
@@ -57,6 +64,7 @@
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.chrome.test.batch.BlankCTATabInitialStateRule;
 import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.chrome.test.util.TabStripUtils;
 import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
@@ -83,13 +91,18 @@
 @DisableFeatures(ChromeFeatureList.TAB_TO_GTS_ANIMATION)
 @Restriction(
         {Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE, UiRestriction.RESTRICTION_TYPE_TABLET})
+@Batch(Batch.PER_CLASS)
 public class TabSwitcherTabletTest {
     private static final long CALLBACK_WAIT_TIMEOUT = 15L;
     @ClassRule
     public static DisableAnimationsTestRule sEnableAnimationsRule =
             new DisableAnimationsTestRule(false);
+    @ClassRule
+    public static final ChromeTabbedActivityTestRule sActivityTestRule =
+            new ChromeTabbedActivityTestRule();
     @Rule
-    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+    public final BlankCTATabInitialStateRule mInitialStateRule =
+            new BlankCTATabInitialStateRule(sActivityTestRule, false);
 
     private List<WeakReference<Bitmap>> mAllBitmaps = new LinkedList<>();
     private TabSwitcher.TabListDelegate mTabListDelegate;
@@ -100,21 +113,10 @@
 
     @Before
     public void setUp() throws ExecutionException {
-        mActivityTestRule.startMainActivityOnBlankPage();
-        CriteriaHelper.pollUiThread(mActivityTestRule.getActivity()
+        CriteriaHelper.pollUiThread(sActivityTestRule.getActivity()
                                             .getTabModelSelectorSupplier()
                                             .get()::isTabStateInitialized);
 
-        Layout layout = mActivityTestRule.getActivity().getLayoutManager().getOverviewLayout();
-        assertTrue(layout instanceof TabSwitcherAndStartSurfaceLayout);
-        TabSwitcherAndStartSurfaceLayout mTabSwitcherAndStartSurfaceLayout =
-                (TabSwitcherAndStartSurfaceLayout) layout;
-
-        mTabListDelegate = mTabSwitcherAndStartSurfaceLayout.getStartSurfaceForTesting()
-                                   .getGridTabListDelegate();
-        Callback<Bitmap> mBitmapListener = (bitmap) -> mAllBitmaps.add(new WeakReference<>(bitmap));
-        mTabListDelegate.setBitmapCallbackForTesting(mBitmapListener);
-
         LayoutStateObserver mLayoutObserver = new LayoutStateProvider.LayoutStateObserver() {
             @Override
             public void onFinishedHiding(int layoutType) {
@@ -125,50 +127,51 @@
         mLayoutManagerCallback = (manager) -> manager.addObserver(mLayoutObserver);
         TestThreadUtils.runOnUiThreadBlocking(
                 ()
-                        -> mActivityTestRule.getActivity().getLayoutManagerSupplier().addObserver(
+                        -> sActivityTestRule.getActivity().getLayoutManagerSupplier().addObserver(
                                 mLayoutManagerCallback));
     }
 
     @After
-    public void cleanup() {
-        TestThreadUtils.runOnUiThreadBlocking(
-                ()
-                        -> mActivityTestRule.getActivity()
-                                   .getLayoutManagerSupplier()
-                                   .removeObserver(mLayoutManagerCallback));
+    public void cleanup() throws TimeoutException {
+        final ChromeTabbedActivity activity = sActivityTestRule.getActivity();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            activity.getLayoutManagerSupplier().removeObserver(mLayoutManagerCallback);
+        });
     }
 
     @Test
     @MediumTest
+    @RequiresRestart
     public void testEnterAndExitTabSwitcherVerifyThumbnails()
             throws ExecutionException, TimeoutException {
-        prepareTabs(1, 1);
+        prepareTabsWithThumbnail(1, 1);
         enterGTSWithThumbnailChecking();
         exitGTSAndVerifyThumbnailsAreReleased();
     }
 
     @Test
     @MediumTest
-    public void testToggleIncognitoSwitcher() throws InterruptedException, ExecutionException {
+    public void testToggleIncognitoSwitcher() throws Exception {
         prepareTabs(1, 1);
-        TabUiTestHelper.enterTabSwitcher(mActivityTestRule.getActivity());
+        TabUiTestHelper.enterTabSwitcher(sActivityTestRule.getActivity());
 
         // Start with incognito switcher.
-        final Tab currTab = mActivityTestRule.getActivity().getCurrentTabModel().getTabAt(0);
-        assertTrue(currTab.isIncognito());
+        assertTrue("Expected to be in Incognito model",
+                sActivityTestRule.getActivity().getCurrentTabModel().isIncognito());
         // Toggle to normal switcher.
         clickIncognitoToggleButton();
 
-        final Tab newTab = mActivityTestRule.getActivity().getCurrentTabModel().getTabAt(0);
+        final Tab newTab = sActivityTestRule.getActivity().getCurrentTabModel().getTabAt(0);
         assertFalse(newTab.isIncognito());
+
+        exitSwitcherWithTabClick(0);
     }
 
     @Test
     @MediumTest
-    public void testTabSwitcherToolbar()
-            throws InterruptedException, ExecutionException, TimeoutException {
+    public void testTabSwitcherToolbar() throws Exception {
         prepareTabs(1, 1);
-        TabUiTestHelper.enterTabSwitcher(mActivityTestRule.getActivity());
+        TabUiTestHelper.enterTabSwitcher(sActivityTestRule.getActivity());
 
         // Assert hidden views.
         onView(allOf(withId(R.id.toolbar), withClassName(is(ToolbarTablet.class.getName()))))
@@ -206,10 +209,9 @@
     @Test
     @MediumTest
     @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_launch_polish/true"})
-    public void testTabSwitcherToolbar_withPolishFlag_incognitoTabsOpen()
-            throws InterruptedException, ExecutionException, TimeoutException {
+    public void testTabSwitcherToolbar_withPolishFlag_incognitoTabsOpen() throws Exception {
         prepareTabs(1, 1);
-        TabUiTestHelper.enterTabSwitcher(mActivityTestRule.getActivity());
+        TabUiTestHelper.enterTabSwitcher(sActivityTestRule.getActivity());
 
         // Assert hidden views.
         onView(allOf(withId(R.id.incognito_switch),
@@ -250,9 +252,9 @@
     @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_launch_polish/true"})
     public void testTabSwitcherV1Scrim() throws TimeoutException {
         prepareTabs(1, 1);
-        TabUiTestHelper.enterTabSwitcher(mActivityTestRule.getActivity());
+        TabUiTestHelper.enterTabSwitcher(sActivityTestRule.getActivity());
 
-        ScrimCoordinator scrimCoordinator = mActivityTestRule.getActivity()
+        ScrimCoordinator scrimCoordinator = sActivityTestRule.getActivity()
                                                     .getRootUiCoordinatorForTesting()
                                                     .getScrimCoordinator();
         assertTrue(scrimCoordinator.isShowingScrim());
@@ -264,19 +266,45 @@
     @Test
     @MediumTest
     @CommandLineFlags.Add({"force-fieldtrial-params=Study.Group:enable_launch_polish/true"})
-    public void testGridTabSwitcherOnNoNextTab() {
-        TabUiTestHelper.createTabs(mActivityTestRule.getActivity(), false, 1);
-
+    public void testGridTabSwitcherOnNoNextTab() throws ExecutionException {
         // Assert the grid tab switcher is not yet showing.
         onView(withId(R.id.grid_tab_switcher_view_holder))
                 .check(matches(withEffectiveVisibility(GONE)));
 
         // Close the only tab through the tab strip.
-        closeTab(false, mActivityTestRule.getActivity().getCurrentTabModel().getTabAt(0).getId());
+        closeTab(false, sActivityTestRule.getActivity().getCurrentTabModel().getTabAt(0).getId());
 
         // Assert the grid tab switcher is shown automatically, since there is no next tab.
         onView(withId(R.id.grid_tab_switcher_view_holder))
                 .check(matches(withEffectiveVisibility(VISIBLE)));
+
+        TestThreadUtils.runOnUiThreadBlocking(()
+                                                      -> sActivityTestRule.getActivity()
+                                                                 .findViewById(R.id.new_tab_button)
+                                                                 .performClick());
+    }
+
+    @Test
+    @MediumTest
+    @CommandLineFlags.
+    Add({"force-fieldtrial-params=Study.Group:enable_launch_polish/true/delay_creation/true"})
+    public void testGridTabSwitcherV1DelayCreate() {
+        Layout layout = sActivityTestRule.getActivity().getLayoutManager().getOverviewLayout();
+        assertNull("StartSurface layout should not be initialized", layout);
+        ViewStub tabSwitcherStub = (ViewStub) sActivityTestRule.getActivity().findViewById(
+                R.id.grid_tab_switcher_view_holder_stub);
+        assertTrue("TabSwitcher view stub should not be inflated",
+                tabSwitcherStub.getParent() != null);
+
+        // Click tab switcher button
+        TabUiTestHelper.enterTabSwitcher(sActivityTestRule.getActivity());
+
+        layout = sActivityTestRule.getActivity().getLayoutManager().getOverviewLayout();
+        assertTrue("OverviewLayout should be TabSwitcherAndStartSurfaceLayout layout",
+                layout instanceof TabSwitcherAndStartSurfaceLayout);
+        ViewGroup tabSwitcherViewHolder =
+                sActivityTestRule.getActivity().findViewById(R.id.grid_tab_switcher_view_holder);
+        assertNotNull("TabSwitcher view should be inflated", tabSwitcherViewHolder);
     }
 
     protected void clickIncognitoToggleButton() {
@@ -288,68 +316,86 @@
             }
         };
         TestThreadUtils.runOnUiThreadBlocking(()
-                                                      -> mActivityTestRule.getActivity()
+                                                      -> sActivityTestRule.getActivity()
                                                                  .getTabModelSelectorSupplier()
                                                                  .get()
                                                                  .addObserver(observer));
         StripLayoutHelperManager manager =
-                TabStripUtils.getStripLayoutHelperManager(mActivityTestRule.getActivity());
+                TabStripUtils.getStripLayoutHelperManager(sActivityTestRule.getActivity());
         TabStripUtils.clickCompositorButton(manager.getModelSelectorButton(),
-                InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity());
+                InstrumentationRegistry.getInstrumentation(), sActivityTestRule.getActivity());
         try {
             tabModelSelectedCallback.waitForCallback(0);
         } catch (TimeoutException e) {
             Assert.fail("Tab model selected event never occurred.");
         }
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            mActivityTestRule.getActivity().getTabModelSelector().removeObserver(observer);
+            sActivityTestRule.getActivity().getTabModelSelector().removeObserver(observer);
         });
     }
 
-    private void prepareTabs(int numTabs, int numIncognitoTabs) {
+    private void prepareTabsWithThumbnail(int numTabs, int numIncognitoTabs) {
+        setupForThumbnailCheck();
         int oldCount = mTabListDelegate.getBitmapFetchCountForTesting();
         TabUiTestHelper.prepareTabsWithThumbnail(
-                mActivityTestRule, numTabs, numIncognitoTabs, null);
+                sActivityTestRule, numTabs, numIncognitoTabs, null);
         assertEquals(0, mTabListDelegate.getBitmapFetchCountForTesting() - oldCount);
     }
 
+    private void prepareTabs(int numTabs, int numIncognitoTabs) {
+        TabUiTestHelper.createTabs(sActivityTestRule.getActivity(), false, numTabs);
+        TabUiTestHelper.createTabs(sActivityTestRule.getActivity(), true, numIncognitoTabs);
+    }
+
+    private void setupForThumbnailCheck() {
+        Layout layout = sActivityTestRule.getActivity().getLayoutManager().getOverviewLayout();
+        assertTrue(layout instanceof TabSwitcherAndStartSurfaceLayout);
+        TabSwitcherAndStartSurfaceLayout mTabSwitcherAndStartSurfaceLayout =
+                (TabSwitcherAndStartSurfaceLayout) layout;
+
+        mTabListDelegate = mTabSwitcherAndStartSurfaceLayout.getStartSurfaceForTesting()
+                                   .getGridTabListDelegate();
+        Callback<Bitmap> mBitmapListener = (bitmap) -> mAllBitmaps.add(new WeakReference<>(bitmap));
+        mTabListDelegate.setBitmapCallbackForTesting(mBitmapListener);
+    }
+
     private void exitGTSAndVerifyThumbnailsAreReleased()
             throws TimeoutException, ExecutionException {
-        assertTrue(mActivityTestRule.getActivity().getLayoutManager().isLayoutVisible(
+        assertTrue(sActivityTestRule.getActivity().getLayoutManager().isLayoutVisible(
                 LayoutType.TAB_SWITCHER));
 
-        final int index = mActivityTestRule.getActivity().getCurrentTabModel().index();
+        final int index = sActivityTestRule.getActivity().getCurrentTabModel().index();
         exitSwitcherWithTabClick(index);
 
         assertThumbnailsAreReleased();
     }
 
     private void exitSwitcherWithTabClick(int index) throws TimeoutException {
-        TabUiTestHelper.clickNthCardFromTabSwitcher(mActivityTestRule.getActivity(), index);
+        TabUiTestHelper.clickNthCardFromTabSwitcher(sActivityTestRule.getActivity(), index);
         mLayoutChangedCallbackHelper.waitForCallback(1, 1, CALLBACK_WAIT_TIMEOUT, TimeUnit.SECONDS);
         assertTrue(mCurrentlyActiveLayout == LayoutType.TAB_SWITCHER);
     }
 
     private void exitSwitcherPolishWithTabClick(int index) throws TimeoutException {
         TabUiTestHelper.clickNthCardFromTabletTabSwitcherPolish(
-                mActivityTestRule.getActivity(), index);
+                sActivityTestRule.getActivity(), index);
         mLayoutChangedCallbackHelper.waitForCallback(1, 1, CALLBACK_WAIT_TIMEOUT, TimeUnit.SECONDS);
         assertTrue(mCurrentlyActiveLayout == LayoutType.TAB_SWITCHER);
     }
 
     private void enterGTSWithThumbnailChecking() {
-        Tab currentTab = mActivityTestRule.getActivity().getTabModelSelector().getCurrentTab();
+        Tab currentTab = sActivityTestRule.getActivity().getTabModelSelector().getCurrentTab();
         // Native tabs need to be invalidated first to trigger thumbnail taking, so skip them.
         boolean checkThumbnail = !currentTab.isNativePage();
 
         if (checkThumbnail) {
-            mActivityTestRule.getActivity().getTabContentManager().removeTabThumbnail(
+            sActivityTestRule.getActivity().getTabContentManager().removeTabThumbnail(
                     currentTab.getId());
         }
-        TabUiTestHelper.enterTabSwitcher(mActivityTestRule.getActivity());
+        TabUiTestHelper.enterTabSwitcher(sActivityTestRule.getActivity());
 
         TabUiTestHelper.verifyAllTabsHaveThumbnail(
-                mActivityTestRule.getActivity().getCurrentTabModel());
+                sActivityTestRule.getActivity().getCurrentTabModel());
     }
 
     private void assertThumbnailsAreReleased() {
@@ -365,12 +411,12 @@
 
     private void closeTab(final boolean incognito, final int id) {
         ChromeTabUtils.closeTabWithAction(InstrumentationRegistry.getInstrumentation(),
-                mActivityTestRule.getActivity(), () -> {
+                sActivityTestRule.getActivity(), () -> {
                     StripLayoutTab tab = TabStripUtils.findStripLayoutTab(
-                            mActivityTestRule.getActivity(), incognito, id);
+                            sActivityTestRule.getActivity(), incognito, id);
                     TabStripUtils.clickCompositorButton(tab.getCloseButton(),
                             InstrumentationRegistry.getInstrumentation(),
-                            mActivityTestRule.getActivity());
+                            sActivityTestRule.getActivity());
                 });
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 7502070..97a5fc2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -22,6 +22,7 @@
 import android.view.View.OnClickListener;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.view.Window;
 import android.view.WindowManager;
 
@@ -285,6 +286,8 @@
 
     // Count histogram used to track number of tabs when we show the Overview on Return to Chrome.
     private static final String TAB_COUNT_ON_RETURN = "Tabs.TabCountOnStartScreenShown";
+    // Time histogram used to track time to inflate tab switcher views.
+    private static final String TAB_SWITCHER_CREATION_TIME = "Android.TabSwitcher.CreationTime";
 
     private final MainIntentBehaviorMetrics mMainIntentMetrics;
     private @Nullable MultiInstanceManager mMultiInstanceManager;
@@ -694,12 +697,12 @@
             // TODO(1239025): Remove all GTS enabled checks after GTS is enabled by default on
             // tablets.
             if (TabUiFeatureUtilities.isGridTabSwitcherEnabled(this)) {
-                createStartSurface(compositorViewHolder);
+                createStartSurface(compositorViewHolder, compositorViewHolder);
             }
 
             // clang-format off
             mLayoutManager = new LayoutManagerChromePhone(compositorViewHolder, mContentContainer,
-                    mStartSurfaceSupplier.get(), getTabContentManagerSupplier(),
+                    mStartSurfaceSupplier, getTabContentManagerSupplier(),
                     mRootUiCoordinator::getTopUiThemeColorProvider, mJankTracker);
             mLayoutStateProviderSupplier.set(mLayoutManager);
             // clang-format on
@@ -715,33 +718,32 @@
 
             // TODO(1239025): Remove all GTS enabled checks after GTS is enabled by default on
             // tablets.
-            if (TabUiFeatureUtilities.isGridTabSwitcherEnabled(this)) {
-                createStartSurface(compositorViewHolder);
+            if (TabUiFeatureUtilities.isGridTabSwitcherEnabled(this)
+                    && !TabUiFeatureUtilities.isTabletGridTabSwitcherDelayCreationEnabled()) {
+                createAndSetStartSurfaceForTablet();
             }
 
             // clang-format off
             ViewGroup tabSwitcherViewHolder = findViewById(R.id.grid_tab_switcher_view_holder);
             mLayoutManager = new LayoutManagerChromeTablet(compositorViewHolder, mContentContainer,
-                    mStartSurfaceSupplier.get(), getTabContentManagerSupplier(),
-                    mRootUiCoordinator::getTopUiThemeColorProvider, mJankTracker,
-                    tabSwitcherViewHolder, mRootUiCoordinator.getScrimCoordinator(),
-                    getLifecycleDispatcher());
+                mStartSurfaceSupplier, getTabContentManagerSupplier(),
+                mRootUiCoordinator::getTopUiThemeColorProvider, mJankTracker,
+                tabSwitcherViewHolder, mRootUiCoordinator.getScrimCoordinator(),
+                getLifecycleDispatcher(), () -> createAndSetStartSurfaceForTablet());
             mLayoutStateProviderSupplier.set(mLayoutManager);
             // clang-format on
         }
     }
 
-    private void createStartSurface(CompositorViewHolder compositorViewHolder) {
-        ViewGroup containerView = TabUiFeatureUtilities.isTabletGridTabSwitcherPolishEnabled(this)
-                ? findViewById(R.id.grid_tab_switcher_view_holder)
-                : compositorViewHolder;
+    private void createStartSurface(
+            CompositorViewHolder compositorViewHolder, ViewGroup tabSwitcherContainer) {
         StartSurfaceDelegate.createStartSurface(this, mRootUiCoordinator.getScrimCoordinator(),
                 mRootUiCoordinator.getBottomSheetController(), mStartSurfaceSupplier,
-                mStartSurfaceParentTabSupplier, hadWarmStart(), getWindowAndroid(), containerView,
-                compositorViewHolder::getDynamicResourceLoader, getTabModelSelector(),
-                getBrowserControlsManager(), getSnackbarManager(), getShareDelegateSupplier(),
-                getToolbarManager()::getOmniboxStub, getTabContentManager(),
-                getModalDialogManager(),
+                mStartSurfaceParentTabSupplier, hadWarmStart(), getWindowAndroid(),
+                tabSwitcherContainer, compositorViewHolder::getDynamicResourceLoader,
+                getTabModelSelector(), getBrowserControlsManager(), getSnackbarManager(),
+                getShareDelegateSupplier(), getToolbarManager()::getOmniboxStub,
+                getTabContentManager(), getModalDialogManager(),
                 /* chromeActivityNativeDelegate= */ this, getLifecycleDispatcher(),
                 getTabCreatorManagerSupplier().get(), getMenuOrKeyboardActionController(),
                 getMultiWindowModeStateDispatcher(), mJankTracker, getToolbarManager()::getToolbar,
@@ -841,6 +843,29 @@
         }
     }
 
+    private ViewGroup createAndSetStartSurfaceForTablet() {
+        assert isTablet();
+        final long startTimeMs = SystemClock.uptimeMillis();
+        CompositorViewHolder compositorViewHolder = getCompositorViewHolderSupplier().get();
+        ViewGroup containerView = compositorViewHolder;
+        if (TabUiFeatureUtilities.isTabletGridTabSwitcherPolishEnabled(this)) {
+            // Inflate view holder for polish GTS.
+            containerView =
+                    (ViewGroup) ((ViewStub) findViewById(R.id.grid_tab_switcher_view_holder_stub))
+                            .inflate();
+            // Set view in toolbar manager to set toolbar stub.
+            getToolbarManager().setTabSwitcherFullScreenView(containerView);
+        }
+
+        // create start surface.
+        createStartSurface(compositorViewHolder, containerView);
+        mStartSurfaceSupplier.get().getController().enableRecordingFirstMeaningfulPaint(
+                getOnCreateTimestampMs());
+        RecordHistogram.recordTimesHistogram(
+                TAB_SWITCHER_CREATION_TIME, SystemClock.uptimeMillis() - startTimeMs);
+        return containerView;
+    }
+
     private void maybeCreateIncognitoTabSnapshotController() {
         try (TraceEvent e = TraceEvent.scoped(
                      "ChromeTabbedActivity.maybeCreateIncognitoTabSnapshotController")) {
@@ -1154,7 +1179,8 @@
                 RecordHistogram.recordCount1MHistogram(
                         TAB_COUNT_ON_RETURN, getCurrentTabModel().getCount());
             }
-            if (TabUiFeatureUtilities.isGridTabSwitcherEnabled(this)) {
+
+            if (mStartSurfaceSupplier.hasValue()) {
                 mStartSurfaceSupplier.get().getController().enableRecordingFirstMeaningfulPaint(
                         getOnCreateTimestampMs());
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
index ee1e395..b2e701d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/flags/ChromeCachedFlags.java
@@ -167,6 +167,7 @@
                         add(TabContentManager.ALLOW_TO_REFETCH_TAB_THUMBNAIL_VARIATION);
                         add(TabUiFeatureUtilities.ENABLE_LAUNCH_BUG_FIX);
                         add(TabUiFeatureUtilities.ENABLE_LAUNCH_POLISH);
+                        add(TabUiFeatureUtilities.DELAY_GTS_CREATION);
                         add(TabUiFeatureUtilities.ENABLE_SEARCH_CHIP);
                         add(TabUiFeatureUtilities.ENABLE_SEARCH_CHIP_ADAPTIVE);
                         add(TabUiFeatureUtilities.ENABLE_TAB_GROUP_AUTO_CREATION);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
index 1ca6b4d..7d24d2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
@@ -8,7 +8,7 @@
 import android.view.MotionEvent;
 import android.view.ViewGroup;
 
-import androidx.annotation.Nullable;
+import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.Callback;
@@ -67,28 +67,28 @@
     private LayoutStateObserver mTabSwitcherFocusLayoutStateObserver;
 
     protected ObservableSupplier<TabContentManager> mTabContentManagerSupplier;
+    private boolean mFinishNativeInitialization;
 
     /**
      * Creates the {@link LayoutManagerChrome} instance.
      * @param host         A {@link LayoutManagerHost} instance.
      * @param contentContainer A {@link ViewGroup} for Android views to be bound to.
-     * @param createOverviewLayout Whether overview layout should be created or not.
-     * @param startSurface An interface to talk to the Grid Tab Switcher. If it's NULL, VTS
-     *                     should be used, otherwise GTS should be used.
+     * @param startSurfaceSupplier Supplier for an interface to talk to the Grid Tab Switcher.
+     *         Creates overviewLayout with this surface if this is has value. If not, {@link
+     *         #showLayout(int, boolean)} will create overviewLayout.
      * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance.
      * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI.
+     * @param jankTracker Tracker for surface jank.
      * @param tabSwitcherScrimAnchor {@link ViewGroup} used by tab switcher layout to show scrim
      *         when overview is visible.
      * @param scrimCoordinator {@link ScrimCoordinator} to show/hide scrim.
      */
     public LayoutManagerChrome(LayoutManagerHost host, ViewGroup contentContainer,
-            boolean createOverviewLayout, @Nullable StartSurface startSurface,
+            Supplier<StartSurface> startSurfaceSupplier,
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, JankTracker jankTracker,
             ViewGroup tabSwitcherScrimAnchor, ScrimCoordinator scrimCoordinator) {
         super(host, contentContainer, tabContentManagerSupplier, topUiThemeColorProvider);
-        Context context = host.getContext();
-        LayoutRenderHost renderHost = host.getLayoutRenderHost();
 
         // Build Event Filter Handlers
         mToolbarSwipeHandler = createToolbarSwipeHandler(/* supportSwipeDown = */ true);
@@ -105,26 +105,50 @@
             }
         });
 
-        if (createOverviewLayout) {
-            if (startSurface != null) {
-                assert TabUiFeatureUtilities.isGridTabSwitcherEnabled(context);
+        if (startSurfaceSupplier.hasValue()) {
+            createOverviewLayout(startSurfaceSupplier.get(), jankTracker, scrimCoordinator,
+                    tabSwitcherScrimAnchor);
+        }
+    }
 
-                mOverviewLayout = StartSurfaceDelegate.createTabSwitcherAndStartSurfaceLayout(
-                        context, this, renderHost, startSurface, jankTracker,
-                        tabSwitcherScrimAnchor, scrimCoordinator);
+    /**
+     * Creates @{@link org.chromium.chrome.features.start_surface.TabSwitcherAndStartSurfaceLayout}
+     * @param startSurface An interface to talk to the Grid Tab Switcher
+     * @param jankTracker Jank tracker.
+     * @param scrimCoordinator scrim coordinator for GTS
+     * @param tabSwitcherScrimAnchor scrim anchor view for GTS
+     */
+    protected void createOverviewLayout(@NonNull StartSurface startSurface,
+            @NonNull JankTracker jankTracker, ScrimCoordinator scrimCoordinator,
+            ViewGroup tabSwitcherScrimAnchor) {
+        assert mOverviewLayout == null
+                && TabUiFeatureUtilities.isGridTabSwitcherEnabled(mHost.getContext());
+        mOverviewLayout = StartSurfaceDelegate.createTabSwitcherAndStartSurfaceLayout(
+                mHost.getContext(), this, mHost.getLayoutRenderHost(), startSurface, jankTracker,
+                tabSwitcherScrimAnchor, scrimCoordinator);
 
-                if (TabUiFeatureUtilities.isTabletGridTabSwitcherEnabled(context)) {
-                    mTabSwitcherFocusLayoutStateObserver = new LayoutStateObserver() {
-                        @Override
-                        public void onFinishedShowing(int layoutType) {
-                            if (layoutType == LayoutType.TAB_SWITCHER) {
-                                startSurface.getGridTabListDelegate().requestFocusOnCurrentTab();
-                            }
-                        }
-                    };
-                    addObserver(mTabSwitcherFocusLayoutStateObserver);
+        if (TabUiFeatureUtilities.isTabletGridTabSwitcherEnabled(mHost.getContext())) {
+            mTabSwitcherFocusLayoutStateObserver = new LayoutStateObserver() {
+                @Override
+                public void onFinishedShowing(int layoutType) {
+                    if (layoutType == LayoutType.TAB_SWITCHER) {
+                        startSurface.getGridTabListDelegate().requestFocusOnCurrentTab();
+                    }
                 }
-            }
+            };
+            addObserver(mTabSwitcherFocusLayoutStateObserver);
+        }
+
+        if (mTabContentManagerSupplier.hasValue()) {
+            mOverviewLayout.setTabContentManager(mTabContentManagerSupplier.get());
+        }
+
+        if (getTabModelSelector() != null) {
+            mOverviewLayout.setTabModelSelector(
+                    getTabModelSelector(), mTabContentManagerSupplier.get());
+        }
+        if (mFinishNativeInitialization) {
+            mOverviewLayout.onFinishNativeInitialization();
         }
     }
 
@@ -178,6 +202,7 @@
             mOverviewLayout.setTabModelSelector(selector, content);
             mOverviewLayout.onFinishNativeInitialization();
         }
+        mFinishNativeInitialization = true;
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
index 488aeec..739534a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
@@ -36,16 +36,18 @@
      * Creates an instance of a {@link LayoutManagerChromePhone}.
      * @param host         A {@link LayoutManagerHost} instance.
      * @param contentContainer A {@link ViewGroup} for Android views to be bound to.
-     * @param startSurface An interface to talk to the Grid Tab Switcher. If it's NULL, VTS
-     *                     should be used, otherwise GTS should be used.
+     * @param startSurfaceSupplier Supplier for an interface to talk to the Grid Tab Switcher. Used
+     *         to create overviewLayout if it has value, otherwise will use the accessibility
+     *         overview layout.
      * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance.
      * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI.
+     * @param jankTracker tracker for surface jank.
      */
     public LayoutManagerChromePhone(LayoutManagerHost host, ViewGroup contentContainer,
-            StartSurface startSurface,
+            Supplier<StartSurface> startSurfaceSupplier,
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, JankTracker jankTracker) {
-        super(host, contentContainer, true, startSurface, tabContentManagerSupplier,
+        super(host, contentContainer, startSurfaceSupplier, tabContentManagerSupplier,
                 topUiThemeColorProvider, jankTracker, null, null);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
index f684c72..3c79fb4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -13,6 +13,7 @@
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
 import org.chromium.chrome.browser.device.DeviceClassManager;
+import org.chromium.chrome.browser.layouts.LayoutType;
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.tab.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -26,11 +27,17 @@
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
 
+import java.util.concurrent.Callable;
+
 /**
  * {@link LayoutManagerChromeTablet} is the specialization of {@link LayoutManagerChrome} for
  * the tablet.
  */
 public class LayoutManagerChromeTablet extends LayoutManagerChrome {
+    // Tab Switcher
+    private final JankTracker mJankTracker;
+    private final ScrimCoordinator mScrimCoordinator;
+    private final Callable<ViewGroup> mCreateStartSurfaceCallable;
     // Tab Strip
     private StripLayoutHelperManager mTabStripLayoutHelperManager;
 
@@ -42,40 +49,41 @@
     /** A {@link TitleCache} instance that stores all title/favicon bitmaps as CC resources. */
     protected LayerTitleCache mLayerTitleCache;
 
+    private final Supplier<StartSurface> mStartSurfaceSupplier;
+
     /**
      * Creates an instance of a {@link LayoutManagerChromePhone}.
      * @param host                     A {@link LayoutManagerHost} instance.
      * @param contentContainer A {@link ViewGroup} for Android views to be bound to.
-     * @param startSurface An interface to talk to the Grid Tab Switcher.
+     * @param startSurfaceSupplier Supplier for an interface to talk to the Grid Tab Switcher.
      * @param tabContentManagerSupplier Supplier of the {@link TabContentManager} instance.
      * @param topUiThemeColorProvider {@link ThemeColorProvider} for top UI.
+     * @param jankTracker Tracker for surface jank.
      * @param tabSwitcherViewHolder {@link ViewGroup} used by tab switcher layout to show scrim
      *         when overview is visible.
      * @param scrimCoordinator {@link ScrimCoordinator} to show/hide scrim.
+     * @param lifecycleDispatcher @{@link ActivityLifecycleDispatcher} to be passed to TabStrip
+     *         helper.
+     * @param delayedStartSurfaceCallable Callable to create StartSurface/GTS views.
      */
     public LayoutManagerChromeTablet(LayoutManagerHost host, ViewGroup contentContainer,
-            StartSurface startSurface,
+            Supplier<StartSurface> startSurfaceSupplier,
             ObservableSupplier<TabContentManager> tabContentManagerSupplier,
             Supplier<TopUiThemeColorProvider> topUiThemeColorProvider, JankTracker jankTracker,
             ViewGroup tabSwitcherViewHolder, ScrimCoordinator scrimCoordinator,
-            ActivityLifecycleDispatcher lifecycleDispatcher) {
-        super(host, contentContainer,
-                TabUiFeatureUtilities.isGridTabSwitcherEnabled(host.getContext()), startSurface,
-                tabContentManagerSupplier, topUiThemeColorProvider, jankTracker,
-                tabSwitcherViewHolder, scrimCoordinator);
-
+            ActivityLifecycleDispatcher lifecycleDispatcher,
+            Callable<ViewGroup> delayedStartSurfaceCallable) {
+        super(host, contentContainer, startSurfaceSupplier, tabContentManagerSupplier,
+                topUiThemeColorProvider, jankTracker, tabSwitcherViewHolder, scrimCoordinator);
+        mStartSurfaceSupplier = startSurfaceSupplier;
         mTabStripLayoutHelperManager = new StripLayoutHelperManager(host.getContext(), this,
                 mHost.getLayoutRenderHost(), () -> mLayerTitleCache, lifecycleDispatcher);
+        mJankTracker = jankTracker;
+        mScrimCoordinator = scrimCoordinator;
+        mCreateStartSurfaceCallable = delayedStartSurfaceCallable;
         addSceneOverlay(mTabStripLayoutHelperManager);
         addObserver(mTabStripLayoutHelperManager.getTabSwitcherObserver());
 
-        if (TabUiFeatureUtilities.isTabletGridTabSwitcherPolishEnabled(mHost.getContext())) {
-            mThemeColorObserver =
-                    (color, shouldAnimate) -> tabSwitcherViewHolder.setBackgroundColor(color);
-            mTopUiThemeColorProvider = topUiThemeColorProvider.get();
-            mTopUiThemeColorProvider.addThemeColorObserver(mThemeColorObserver);
-        }
-
         setNextLayout(null, true);
     }
 
@@ -122,7 +130,6 @@
             DynamicResourceLoader dynamicResourceLoader,
             TopUiThemeColorProvider topUiColorProvider) {
         super.init(selector, creator, controlContainer, dynamicResourceLoader, topUiColorProvider);
-
         if (DeviceClassManager.enableLayerDecorationCache()) {
             mLayerTitleCache = new LayerTitleCache(mHost.getContext(), getResourceManager());
             // TODO: TitleCache should be a part of the ResourceManager.
@@ -135,6 +142,30 @@
     }
 
     @Override
+    public void showLayout(int layoutType, boolean animate) {
+        if (layoutType == LayoutType.TAB_SWITCHER && mOverviewLayout == null
+                && TabUiFeatureUtilities.isTabletGridTabSwitcherEnabled(mHost.getContext())) {
+            try {
+                if (!mStartSurfaceSupplier.hasValue()) {
+                    final ViewGroup containerView = mCreateStartSurfaceCallable.call();
+                    createOverviewLayout(mStartSurfaceSupplier.get(), mJankTracker,
+                            mScrimCoordinator, containerView);
+                    if (TabUiFeatureUtilities.isTabletGridTabSwitcherPolishEnabled(
+                                mHost.getContext())) {
+                        mThemeColorObserver =
+                                (color, shouldAnimate) -> containerView.setBackgroundColor(color);
+                        mTopUiThemeColorProvider = getTopUiThemeColorProvider().get();
+                        mTopUiThemeColorProvider.addThemeColorObserver(mThemeColorObserver);
+                    }
+                }
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to initialize start surface.", e);
+            }
+        }
+        super.showLayout(layoutType, animate);
+    }
+
+    @Override
     protected void emptyCachesExcept(int tabId) {
         super.emptyCachesExcept(tabId);
         if (mLayerTitleCache != null) mLayerTitleCache.clearExcept(tabId);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
index 3ea3c98..5c9eaae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerImpl.java
@@ -764,6 +764,10 @@
         getActiveLayout().onTabsAllClosing(incognito);
     }
 
+    protected Supplier<TopUiThemeColorProvider> getTopUiThemeColorProvider() {
+        return mTopUiThemeColorProvider;
+    }
+
     @Override
     public void initLayoutTabFromHost(final int tabId) {
         if (getTabModelSelector() == null || getActiveLayout() == null) return;
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
index c2b591f..421b405 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -988,6 +988,16 @@
     }
 
     /**
+     * Set container view on which GTS toolbar needs to inflate.
+     * @param containerView view containing GTS fullscreen toolbar.
+     */
+    public void setTabSwitcherFullScreenView(ViewGroup containerView) {
+        ViewStub toolbarStub =
+                containerView.findViewById(R.id.fullscreen_tab_switcher_toolbar_stub);
+        mToolbar.setFullScreenToolbarStub(toolbarStub);
+    }
+
+    /**
      * Handle a layout change event.
      * @param layoutType The layout being switched to.
      * @param showToolbar Whether the toolbar should be shown.
@@ -1035,13 +1045,7 @@
             Callback<LoadUrlParams> logoClickedCallback) {
         ViewStub tabSwitcherToolbarStub = mActivity.findViewById(R.id.tab_switcher_toolbar_stub);
         ViewStub tabSwitcherFullscreenToolbarStub = null;
-        if (TabUiFeatureUtilities.isTabletGridTabSwitcherPolishEnabled(mActivity)) {
-            // Need to inflate grid_tab_switcher_view_holder_stub, as it contains
-            // fullscreen_tab_switcher_toolbar_stub.
-            ((ViewStub) mActivity.findViewById(R.id.grid_tab_switcher_view_holder_stub)).inflate();
-            tabSwitcherFullscreenToolbarStub =
-                    mActivity.findViewById(R.id.fullscreen_tab_switcher_toolbar_stub);
-        }
+
         // clang-format off
         TopToolbarCoordinator toolbar = new TopToolbarCoordinator(controlContainer,
                 tabSwitcherToolbarStub, tabSwitcherFullscreenToolbarStub, toolbarLayout,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
index 7a44b526..c05ebaac 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
@@ -45,6 +45,7 @@
 import org.chromium.base.MathUtils;
 import org.chromium.base.jank_tracker.DummyJankTracker;
 import org.chromium.base.supplier.ObservableSupplierImpl;
+import org.chromium.base.supplier.Supplier;
 import org.chromium.base.test.UiThreadTest;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -118,6 +119,7 @@
     private long mLastDownTime;
 
     private TabModelSelector mTabModelSelector;
+    private Supplier<StartSurface> mStartSurfaceSupplier;
     private LayoutManagerChrome mManager;
     private LayoutManagerChromePhone mManagerPhone;
 
@@ -214,9 +216,9 @@
 
         ObservableSupplierImpl<TabContentManager> tabContentManagerSupplier =
                 new ObservableSupplierImpl<>();
-
-        mManagerPhone = new LayoutManagerChromePhone(layoutManagerHost, container, mStartSurface,
-                tabContentManagerSupplier, () -> mTopUiThemeColorProvider, new DummyJankTracker());
+        mManagerPhone = new LayoutManagerChromePhone(layoutManagerHost, container,
+                mStartSurfaceSupplier, tabContentManagerSupplier,
+                () -> mTopUiThemeColorProvider, new DummyJankTracker());
         verify(mStartSurfaceController)
                 .addTabSwitcherViewObserver(mTabSwitcherViewObserverArgumentCaptor.capture());
 
@@ -705,6 +707,8 @@
         // Load the browser process.
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> { ChromeBrowserInitializer.getInstance().handleSynchronousStartup(); });
+
+        mStartSurfaceSupplier = () -> mStartSurface;
     }
 
     @After
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 334c4e7..0a6de01 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -3144,10 +3144,17 @@
 const FeatureEntry::FeatureParam kGridTabSwitcherForTabletsPolished[] = {
     {"enable_launch_polish", "true"}};
 
+const FeatureEntry::FeatureParam kGridTabSwitcherForTabletsDelayCreation[] = {
+    {"delay_creation", "true"},
+    {"enable_launch_polish", "true"}};
+
 const FeatureEntry::FeatureVariation kGridTabSwitcherForTabletsVariations[] = {
     {"(Polished)", kGridTabSwitcherForTabletsPolished,
      std::size(kGridTabSwitcherForTabletsPolished), nullptr},
+    {"(DelayCreatePolish)", kGridTabSwitcherForTabletsDelayCreation,
+     std::size(kGridTabSwitcherForTabletsDelayCreation), nullptr},
 };
+
 #endif  // BUILDFLAG(IS_ANDROID)
 
 #if BUILDFLAG(IS_ANDROID)
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTCoordinator.java
index 5ed0c07..8fc1088 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TabSwitcherModeTTCoordinator.java
@@ -27,7 +27,7 @@
  */
 class TabSwitcherModeTTCoordinator {
     private final ViewStub mTabSwitcherToolbarStub;
-    private final ViewStub mTabSwitcherFullscreenToolbarStub;
+    private ViewStub mTabSwitcherFullscreenToolbarStub;
 
     // TODO(twellington): Create a model to hold all of these properties. Consider using
     // LazyConstructionPropertyMcp to collect all of the properties since it is designed to
@@ -69,6 +69,14 @@
     }
 
     /**
+     * Set stub for GTS fullscreen toolbar.
+     * @param toolbarStub stub to set.
+     */
+    void setFullScreenToolbarStub(ViewStub toolbarStub) {
+        mTabSwitcherFullscreenToolbarStub = toolbarStub;
+    }
+
+    /**
      * Cleans up any code and removes observers as necessary.
      */
     void destroy() {
@@ -202,6 +210,7 @@
     private TabSwitcherModeTopToolbar maybeInflateActiveToolbar(boolean useFullscreenToolbar) {
         if (useFullscreenToolbar) {
             if (mTabSwitcherFullscreenToolbar == null) {
+                assert mTabSwitcherFullscreenToolbarStub != null;
                 mTabSwitcherFullscreenToolbar =
                         (TabSwitcherModeTopToolbar) mTabSwitcherFullscreenToolbarStub.inflate();
                 initializeToolbar(mTabSwitcherFullscreenToolbar, true);
diff --git a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index c478f5c..7f697bc 100644
--- a/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -201,6 +201,16 @@
         mToolbarLayout.setInvalidatorCallback(invalidatorCallback);
     }
 
+    /**
+     * Set fullscreen GTS toolbar stub
+     * @param toolbarStub stub to set.
+     */
+    public void setFullScreenToolbarStub(ViewStub toolbarStub) {
+        if (mTabSwitcherModeCoordinator != null) {
+            mTabSwitcherModeCoordinator.setFullScreenToolbarStub(toolbarStub);
+        }
+    }
+
     private boolean isTabletGridTabSwitcherEnabled() {
         return CachedFeatureFlags.isEnabled(ChromeFeatureList.GRID_TAB_SWITCHER_FOR_TABLETS);
     }
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 1c1e56b..845e18a 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -4124,11 +4124,32 @@
                 {
                     "name": "Enabled",
                     "params": {
+                        "delay_creation": "false",
                         "enable_launch_polish": "false"
                     },
                     "enable_features": [
                         "GridTabSwitcherForTablets"
                     ]
+                },
+                {
+                    "name": "Enabled_Polish",
+                    "params": {
+                        "delay_creation": "false",
+                        "enable_launch_polish": "true"
+                    },
+                    "enable_features": [
+                        "GridTabSwitcherForTablets"
+                    ]
+                },
+                {
+                    "name": "Enabled_Polish_Delay",
+                    "params": {
+                        "delay_creation": "true",
+                        "enable_launch_polish": "true"
+                    },
+                    "enable_features": [
+                        "GridTabSwitcherForTablets"
+                    ]
                 }
             ]
         }
diff --git a/tools/metrics/histograms/metadata/android/histograms.xml b/tools/metrics/histograms/metadata/android/histograms.xml
index a538537..e0350f1 100644
--- a/tools/metrics/histograms/metadata/android/histograms.xml
+++ b/tools/metrics/histograms/metadata/android/histograms.xml
@@ -3312,6 +3312,17 @@
   </summary>
 </histogram>
 
+<histogram name="Android.TabSwitcher.CreationTime" units="ms"
+    expires_after="2022-12-31">
+  <owner>skavuluru@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <owner>clank-large-form-factors@google.com</owner>
+  <summary>
+    Records the time taken to create the StartSurfaceCoordinator and grid tab
+    switcher views. Only recorded for tablets.
+  </summary>
+</histogram>
+
 <histogram name="Android.TabSwitcher.IncognitoClickedIsEmpty" enum="Boolean"
     expires_after="2022-09-01">
   <owner>sideyilmaz@chromium.org</owner>
@@ -3322,6 +3333,17 @@
   </summary>
 </histogram>
 
+<histogram name="Android.TabSwitcher.SetupRecyclerView.Time" units="ms"
+    expires_after="2022-12-31">
+  <owner>skavuluru@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <owner>clank-large-form-factors@google.com</owner>
+  <summary>
+    Records the time taken to create TabListCoordinator, which inflates the
+    RecyclerView for the grid tab switcher, and bind views.
+  </summary>
+</histogram>
+
 <histogram name="Android.TaskScheduling.BootstrapTaskRunnerType"
     enum="BootstrapTaskRunnerType" expires_after="2022-12-04">
   <owner>blundell@chromium.org</owner>