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