1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.toolbar.top; 6 7 import android.view.View; 8 import android.view.ViewStub; 9 10 import androidx.annotation.Nullable; 11 12 import org.chromium.chrome.R; 13 import org.chromium.chrome.browser.flags.ChromeFeatureList; 14 import org.chromium.chrome.browser.incognito.IncognitoUtils; 15 import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider; 16 import org.chromium.chrome.browser.tabmodel.IncognitoTabModelObserver; 17 import org.chromium.chrome.browser.tabmodel.TabModelSelector; 18 import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities; 19 import org.chromium.chrome.browser.toolbar.TabCountProvider; 20 import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator; 21 22 /** 23 * The coordinator for the tab switcher mode top toolbar shown on phones, responsible for 24 * communication with other UI components and lifecycle. Lazily creates the tab 25 * switcher mode top toolbar the first time it's needed. 26 */ 27 class TabSwitcherModeTTCoordinatorPhone { 28 private final ViewStub mTabSwitcherToolbarStub; 29 30 // TODO(twellington): Create a model to hold all of these properties. Consider using 31 // LazyConstructionPropertyMcp to collect all of the properties since it is designed to 32 // aggregate properties and bind them to a view the first time it's shown. 33 private View.OnClickListener mTabSwitcherListener; 34 private View.OnClickListener mNewTabListener; 35 private TabCountProvider mTabCountProvider; 36 private TabModelSelector mTabModelSelector; 37 private IncognitoStateProvider mIncognitoStateProvider; 38 private MenuButtonCoordinator mMenuButtonCoordinator; 39 private boolean mAccessibilityEnabled; 40 41 private TabSwitcherModeTTPhone mTabSwitcherModeToolbar; 42 43 @Nullable 44 private IncognitoTabModelObserver mIncognitoTabModelObserver; 45 TabSwitcherModeTTCoordinatorPhone( ViewStub tabSwitcherToolbarStub, MenuButtonCoordinator menuButtonCoordinator)46 TabSwitcherModeTTCoordinatorPhone( 47 ViewStub tabSwitcherToolbarStub, MenuButtonCoordinator menuButtonCoordinator) { 48 mTabSwitcherToolbarStub = tabSwitcherToolbarStub; 49 mMenuButtonCoordinator = menuButtonCoordinator; 50 } 51 52 /** 53 * Cleans up any code and removes observers as necessary. 54 */ destroy()55 void destroy() { 56 if (mTabSwitcherModeToolbar != null) { 57 mTabSwitcherModeToolbar.destroy(); 58 mTabSwitcherModeToolbar = null; 59 } 60 if (mTabModelSelector != null && mIncognitoTabModelObserver != null) { 61 mTabModelSelector.removeIncognitoTabModelObserver(mIncognitoTabModelObserver); 62 } 63 if (mMenuButtonCoordinator != null) { 64 mMenuButtonCoordinator.destroy(); 65 mMenuButtonCoordinator = null; 66 } 67 } 68 69 /** 70 * Called when tab switcher mode is entered or exited. 71 * @param inTabSwitcherMode Whether or not tab switcher mode should be shown or hidden. 72 */ setTabSwitcherMode(boolean inTabSwitcherMode)73 void setTabSwitcherMode(boolean inTabSwitcherMode) { 74 if (inTabSwitcherMode) { 75 if (mTabSwitcherModeToolbar == null) { 76 initializeTabSwitcherToolbar(); 77 } 78 79 mTabSwitcherModeToolbar.setTabSwitcherMode(inTabSwitcherMode); 80 } else if (mTabSwitcherModeToolbar != null) { 81 mTabSwitcherModeToolbar.setTabSwitcherMode(inTabSwitcherMode); 82 } 83 } 84 85 /** 86 * Sets the OnClickListener that will be notified when the TabSwitcher button is pressed. 87 * @param listener The callback that will be notified when the TabSwitcher button is pressed. 88 */ setOnTabSwitcherClickHandler(View.OnClickListener listener)89 void setOnTabSwitcherClickHandler(View.OnClickListener listener) { 90 mTabSwitcherListener = listener; 91 if (mTabSwitcherModeToolbar != null) { 92 mTabSwitcherModeToolbar.setOnTabSwitcherClickHandler(listener); 93 } 94 } 95 96 /** 97 * Sets the OnClickListener that will be notified when the New Tab button is pressed. 98 * @param listener The callback that will be notified when the New Tab button is pressed. 99 */ setOnNewTabClickHandler(View.OnClickListener listener)100 void setOnNewTabClickHandler(View.OnClickListener listener) { 101 mNewTabListener = listener; 102 if (mTabSwitcherModeToolbar != null) { 103 mTabSwitcherModeToolbar.setOnNewTabClickHandler(listener); 104 } 105 } 106 107 /** 108 * @param tabCountProvider The {@link TabCountProvider} used to observe the number of tabs in 109 * the current model. 110 */ setTabCountProvider(TabCountProvider tabCountProvider)111 void setTabCountProvider(TabCountProvider tabCountProvider) { 112 mTabCountProvider = tabCountProvider; 113 if (mTabSwitcherModeToolbar != null) { 114 mTabSwitcherModeToolbar.setTabCountProvider(tabCountProvider); 115 } 116 } 117 118 /** 119 * Sets the current TabModelSelector so the toolbar can pass it into buttons that need access to 120 * it. 121 */ setTabModelSelector(TabModelSelector selector)122 void setTabModelSelector(TabModelSelector selector) { 123 mTabModelSelector = selector; 124 if (mTabSwitcherModeToolbar != null) { 125 mTabSwitcherModeToolbar.setTabModelSelector(selector); 126 } 127 128 maybeInitializeIncognitoTabModelObserver(); 129 maybeNotifyOnIncognitoTabsExistenceChanged(); 130 } 131 132 /** 133 * @param provider The provider used to determine incognito state. 134 */ setIncognitoStateProvider(IncognitoStateProvider provider)135 void setIncognitoStateProvider(IncognitoStateProvider provider) { 136 mIncognitoStateProvider = provider; 137 if (mTabSwitcherModeToolbar != null) { 138 mTabSwitcherModeToolbar.setIncognitoStateProvider(provider); 139 } 140 } 141 142 /** Called when accessibility status changes. */ onAccessibilityStatusChanged(boolean enabled)143 void onAccessibilityStatusChanged(boolean enabled) { 144 mAccessibilityEnabled = enabled; 145 if (mTabSwitcherModeToolbar != null) { 146 mTabSwitcherModeToolbar.onAccessibilityStatusChanged(enabled); 147 } 148 } 149 initializeTabSwitcherToolbar()150 private void initializeTabSwitcherToolbar() { 151 mTabSwitcherModeToolbar = (TabSwitcherModeTTPhone) mTabSwitcherToolbarStub.inflate(); 152 mMenuButtonCoordinator.setMenuButton( 153 mTabSwitcherModeToolbar.findViewById(R.id.menu_button_wrapper)); 154 155 // It's expected that these properties are set by the time the tab switcher is entered. 156 assert mTabSwitcherListener != null; 157 mTabSwitcherModeToolbar.setOnTabSwitcherClickHandler(mTabSwitcherListener); 158 159 assert mNewTabListener != null; 160 mTabSwitcherModeToolbar.setOnNewTabClickHandler(mNewTabListener); 161 162 assert mTabCountProvider != null; 163 mTabSwitcherModeToolbar.setTabCountProvider(mTabCountProvider); 164 165 assert mTabModelSelector != null; 166 mTabSwitcherModeToolbar.setTabModelSelector(mTabModelSelector); 167 168 assert mIncognitoStateProvider != null; 169 mTabSwitcherModeToolbar.setIncognitoStateProvider(mIncognitoStateProvider); 170 171 maybeInitializeIncognitoTabModelObserver(); 172 maybeNotifyOnIncognitoTabsExistenceChanged(); 173 174 if (mAccessibilityEnabled) { 175 mTabSwitcherModeToolbar.onAccessibilityStatusChanged(mAccessibilityEnabled); 176 } 177 } 178 isNewTabVariationEnabled()179 private boolean isNewTabVariationEnabled() { 180 return TabUiFeatureUtilities.isGridTabSwitcherEnabled() && ChromeFeatureList.isInitialized() 181 && IncognitoUtils.isIncognitoModeEnabled() 182 && ChromeFeatureList 183 .getFieldTrialParamByFeature(ChromeFeatureList.TAB_GRID_LAYOUT_ANDROID, 184 "tab_grid_layout_android_new_tab") 185 .equals("NewTabVariation"); 186 } 187 188 /** 189 * @param highlight If the new tab button should be highlighted. 190 */ setNewTabButtonHighlight(boolean highlight)191 void setNewTabButtonHighlight(boolean highlight) { 192 assert mTabSwitcherModeToolbar != null; 193 mTabSwitcherModeToolbar.setNewTabButtonHighlight(highlight); 194 } 195 196 /** 197 * Initialize {@link IncognitoTabModelObserver}, if the new tab variation is enabled. This 198 * function will initialize observer, if it is not initialized before. 199 */ maybeInitializeIncognitoTabModelObserver()200 private void maybeInitializeIncognitoTabModelObserver() { 201 if (mTabModelSelector == null || mTabSwitcherModeToolbar == null 202 || !isNewTabVariationEnabled() || mIncognitoTabModelObserver != null) { 203 return; 204 } 205 206 mIncognitoTabModelObserver = new IncognitoTabModelObserver() { 207 @Override 208 public void wasFirstTabCreated() { 209 if (mTabSwitcherModeToolbar != null) { 210 mTabSwitcherModeToolbar.onIncognitoTabsExistenceChanged(true); 211 } 212 } 213 214 @Override 215 public void didBecomeEmpty() { 216 if (mTabSwitcherModeToolbar != null) { 217 mTabSwitcherModeToolbar.onIncognitoTabsExistenceChanged(false); 218 } 219 } 220 }; 221 mTabModelSelector.addIncognitoTabModelObserver(mIncognitoTabModelObserver); 222 } 223 224 /** 225 * Update incognito logo visibility on toolbar, if the new tab variation is enabled. 226 */ maybeNotifyOnIncognitoTabsExistenceChanged()227 private void maybeNotifyOnIncognitoTabsExistenceChanged() { 228 if (mTabModelSelector == null || mTabSwitcherModeToolbar == null 229 || !isNewTabVariationEnabled()) { 230 return; 231 } 232 233 boolean doesExist = mTabModelSelector.getModel(true).getCount() != 0; 234 mTabSwitcherModeToolbar.onIncognitoTabsExistenceChanged(doesExist); 235 } 236 } 237