| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.chrome.browser.toolbar; |
| |
| import android.content.ComponentCallbacks; |
| import android.content.res.ColorStateList; |
| import android.content.res.Configuration; |
| import android.graphics.Point; |
| import android.graphics.Rect; |
| import android.graphics.drawable.Drawable; |
| import android.os.Handler; |
| import android.text.TextUtils; |
| import android.view.MotionEvent; |
| import android.view.View; |
| import android.view.View.OnAttachStateChangeListener; |
| import android.view.View.OnClickListener; |
| import android.view.View.OnLongClickListener; |
| import android.view.ViewGroup; |
| |
| import androidx.annotation.NonNull; |
| import androidx.annotation.Nullable; |
| import androidx.annotation.VisibleForTesting; |
| import androidx.appcompat.app.ActionBar; |
| import androidx.appcompat.app.AppCompatActivity; |
| |
| import com.google.android.material.appbar.AppBarLayout; |
| |
| import org.chromium.base.Callback; |
| import org.chromium.base.CallbackController; |
| import org.chromium.base.TraceEvent; |
| import org.chromium.base.supplier.ObservableSupplier; |
| import org.chromium.base.supplier.ObservableSupplierImpl; |
| import org.chromium.base.supplier.OneshotSupplier; |
| import org.chromium.base.supplier.Supplier; |
| import org.chromium.chrome.R; |
| import org.chromium.chrome.browser.ActivityTabProvider; |
| import org.chromium.chrome.browser.TabLoadStatus; |
| import org.chromium.chrome.browser.WindowDelegate; |
| import org.chromium.chrome.browser.bookmarks.BookmarkBridge; |
| import org.chromium.chrome.browser.browser_controls.BrowserControlsSizer; |
| import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider; |
| import org.chromium.chrome.browser.browser_controls.BrowserStateBrowserControlsVisibilityDelegate; |
| import org.chromium.chrome.browser.compositor.CompositorViewHolder; |
| import org.chromium.chrome.browser.compositor.Invalidator; |
| import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager.OverlayPanelManagerObserver; |
| import org.chromium.chrome.browser.compositor.layouts.Layout; |
| import org.chromium.chrome.browser.compositor.layouts.LayoutManagerImpl; |
| import org.chromium.chrome.browser.compositor.layouts.SceneChangeObserver; |
| import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbar; |
| import org.chromium.chrome.browser.dom_distiller.DomDistillerTabUtils; |
| import org.chromium.chrome.browser.feature_engagement.TrackerFactory; |
| import org.chromium.chrome.browser.findinpage.FindToolbarManager; |
| import org.chromium.chrome.browser.findinpage.FindToolbarObserver; |
| import org.chromium.chrome.browser.flags.ChromeFeatureList; |
| import org.chromium.chrome.browser.fullscreen.FullscreenManager; |
| import org.chromium.chrome.browser.fullscreen.FullscreenOptions; |
| import org.chromium.chrome.browser.homepage.HomepageManager; |
| import org.chromium.chrome.browser.homepage.HomepagePolicyManager; |
| import org.chromium.chrome.browser.identity_disc.IdentityDiscController; |
| import org.chromium.chrome.browser.incognito.IncognitoUtils; |
| import org.chromium.chrome.browser.intent.IntentMetadata; |
| import org.chromium.chrome.browser.layouts.LayoutStateProvider; |
| import org.chromium.chrome.browser.layouts.LayoutType; |
| import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; |
| import org.chromium.chrome.browser.ntp.FakeboxDelegate; |
| import org.chromium.chrome.browser.ntp.IncognitoNewTabPage; |
| import org.chromium.chrome.browser.ntp.NewTabPage; |
| import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; |
| import org.chromium.chrome.browser.omnibox.LocationBar; |
| import org.chromium.chrome.browser.omnibox.LocationBarCoordinator; |
| import org.chromium.chrome.browser.omnibox.OmniboxFocusReason; |
| import org.chromium.chrome.browser.omnibox.OverrideUrlLoadingDelegate; |
| import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener; |
| import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler; |
| import org.chromium.chrome.browser.previews.Previews; |
| import org.chromium.chrome.browser.previews.PreviewsAndroidBridge; |
| import org.chromium.chrome.browser.previews.PreviewsUma; |
| import org.chromium.chrome.browser.profiles.Profile; |
| import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory; |
| import org.chromium.chrome.browser.share.ShareDelegate; |
| import org.chromium.chrome.browser.tab.SadTab; |
| import org.chromium.chrome.browser.tab.Tab; |
| import org.chromium.chrome.browser.tab.TabObserver; |
| import org.chromium.chrome.browser.tab.TabSelectionType; |
| import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; |
| import org.chromium.chrome.browser.tabmodel.IncognitoStateProvider; |
| import org.chromium.chrome.browser.tabmodel.TabModel; |
| import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
| import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; |
| import org.chromium.chrome.browser.tasks.ReturnToChromeExperimentsUtil; |
| import org.chromium.chrome.browser.theme.ThemeColorProvider; |
| import org.chromium.chrome.browser.theme.ThemeColorProvider.ThemeColorObserver; |
| import org.chromium.chrome.browser.theme.ThemeColorProvider.TintObserver; |
| import org.chromium.chrome.browser.theme.TopUiThemeColorProvider; |
| import org.chromium.chrome.browser.toolbar.bottom.BottomControlsCoordinator; |
| import org.chromium.chrome.browser.toolbar.load_progress.LoadProgressCoordinator; |
| import org.chromium.chrome.browser.toolbar.menu_button.MenuButtonCoordinator; |
| import org.chromium.chrome.browser.toolbar.top.ActionModeController; |
| import org.chromium.chrome.browser.toolbar.top.ActionModeController.ActionBarDelegate; |
| import org.chromium.chrome.browser.toolbar.top.HomeButtonCoordinator; |
| import org.chromium.chrome.browser.toolbar.top.TabSwitcherActionMenuCoordinator; |
| import org.chromium.chrome.browser.toolbar.top.ToggleTabStackButton; |
| import org.chromium.chrome.browser.toolbar.top.ToggleTabStackButtonCoordinator; |
| import org.chromium.chrome.browser.toolbar.top.Toolbar; |
| import org.chromium.chrome.browser.toolbar.top.ToolbarActionModeCallback; |
| import org.chromium.chrome.browser.toolbar.top.ToolbarControlContainer; |
| import org.chromium.chrome.browser.toolbar.top.ToolbarLayout; |
| import org.chromium.chrome.browser.toolbar.top.ToolbarPhone; |
| import org.chromium.chrome.browser.toolbar.top.ToolbarTablet; |
| import org.chromium.chrome.browser.toolbar.top.TopToolbarCoordinator; |
| import org.chromium.chrome.browser.toolbar.top.ViewShiftingActionBarDelegate; |
| import org.chromium.chrome.browser.ui.TabObscuringHandler; |
| import org.chromium.chrome.browser.ui.appmenu.AppMenuCoordinator; |
| import org.chromium.chrome.browser.ui.appmenu.AppMenuDelegate; |
| import org.chromium.chrome.browser.ui.appmenu.MenuButtonDelegate; |
| import org.chromium.chrome.browser.ui.native_page.NativePage; |
| import org.chromium.chrome.browser.ui.system.StatusBarColorController; |
| import org.chromium.chrome.browser.user_education.UserEducationHelper; |
| import org.chromium.chrome.browser.util.ChromeAccessibilityUtil; |
| import org.chromium.chrome.features.start_surface.StartSurface; |
| import org.chromium.chrome.features.start_surface.StartSurfaceConfiguration; |
| import org.chromium.chrome.features.start_surface.StartSurfaceState; |
| import org.chromium.components.browser_ui.styles.ChromeColors; |
| import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator; |
| import org.chromium.components.embedder_support.util.UrlConstants; |
| import org.chromium.components.embedder_support.util.UrlUtilities; |
| import org.chromium.components.feature_engagement.Tracker; |
| import org.chromium.components.search_engines.TemplateUrl; |
| import org.chromium.components.search_engines.TemplateUrlService; |
| import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver; |
| import org.chromium.content_public.browser.LoadUrlParams; |
| import org.chromium.content_public.browser.NavigationController; |
| import org.chromium.content_public.browser.NavigationEntry; |
| import org.chromium.content_public.browser.NavigationHandle; |
| import org.chromium.content_public.browser.WebContents; |
| import org.chromium.net.NetError; |
| import org.chromium.ui.base.DeviceFormFactor; |
| import org.chromium.ui.base.WindowAndroid; |
| import org.chromium.ui.modaldialog.ModalDialogManager; |
| import org.chromium.ui.util.TokenHolder; |
| |
| import java.util.List; |
| |
| /** |
| * Contains logic for managing the toolbar visual component. This class manages the interactions |
| * with the rest of the application to ensure the toolbar is always visually up to date. |
| */ |
| public class ToolbarManager implements UrlFocusChangeListener, ThemeColorObserver, TintObserver, |
| MenuButtonDelegate, ChromeAccessibilityUtil.Observer { |
| private final IncognitoStateProvider mIncognitoStateProvider; |
| private final TabCountProvider mTabCountProvider; |
| private final TopUiThemeColorProvider mTopUiThemeColorProvider; |
| private AppThemeColorProvider mAppThemeColorProvider; |
| private SettableThemeColorProvider mCustomTabThemeColorProvider; |
| private final TopToolbarCoordinator mToolbar; |
| private final ToolbarControlContainer mControlContainer; |
| private final BrowserControlsStateProvider.Observer mBrowserControlsObserver; |
| private final FullscreenManager.Observer mFullscreenObserver; |
| private final ObservableSupplierImpl<Boolean> mHomeButtonVisibilitySupplier = |
| new ObservableSupplierImpl<>(); |
| private final ObservableSupplierImpl<Boolean> mHomepageManagedByPolicySupplier = |
| new ObservableSupplierImpl<>(); |
| private final ObservableSupplierImpl<Boolean> mIdentityDiscStateSupplier = |
| new ObservableSupplierImpl<>(); |
| private final ObservableSupplier<Boolean> mOmniboxFocusStateSupplier; |
| |
| private ObservableSupplierImpl<BottomControlsCoordinator> mBottomControlsCoordinatorSupplier = |
| new ObservableSupplierImpl<>(); |
| private final ObservableSupplierImpl<Tab> mActivityTabSupplier = new ObservableSupplierImpl<>(); |
| private TabModelSelector mTabModelSelector; |
| private TabModelSelectorObserver mTabModelSelectorObserver; |
| private ObservableSupplier<TabModelSelector> mTabModelSelectorSupplier; |
| private ActivityTabProvider.ActivityTabTabObserver mActivityTabTabObserver; |
| private final ActivityTabProvider mActivityTabProvider; |
| private final LocationBarModel mLocationBarModel; |
| private ObservableSupplier<BookmarkBridge> mBookmarkBridgeSupplier; |
| private final Callback<BookmarkBridge> mBookmarkBridgeSupplierObserver; |
| private TemplateUrlServiceObserver mTemplateUrlObserver; |
| private LocationBar mLocationBar; |
| private FindToolbarManager mFindToolbarManager; |
| |
| private LayoutManagerImpl mLayoutManager; |
| private final ObservableSupplier<ShareDelegate> mShareDelegateSupplier; |
| |
| private TabObserver mTabObserver; |
| private BookmarkBridge.BookmarkModelObserver mBookmarksObserver; |
| private FindToolbarObserver mFindToolbarObserver; |
| |
| private @StartSurfaceState int mStartSurfaceState = StartSurfaceState.NOT_SHOWN; |
| |
| private LayoutStateProvider mLayoutStateProvider; |
| private LayoutStateProvider.LayoutStateObserver mLayoutStateObserver; |
| private OneshotSupplier<LayoutStateProvider> mLayoutStateProviderSupplier; |
| private CallbackController mCallbackController = new CallbackController(); |
| |
| private SceneChangeObserver mSceneChangeObserver; |
| private final ActionBarDelegate mActionBarDelegate; |
| private ActionModeController mActionModeController; |
| private final Callback<Boolean> mUrlFocusChangedCallback; |
| private final Handler mHandler = new Handler(); |
| private final AppCompatActivity mActivity; |
| private final WindowAndroid mWindowAndroid; |
| private final AppMenuDelegate mAppMenuDelegate; |
| private final CompositorViewHolder mCompositorViewHolder; |
| private final BrowserControlsSizer mBrowserControlsSizer; |
| private final FullscreenManager mFullscreenManager; |
| private LocationBarFocusScrimHandler mLocationBarFocusHandler; |
| private ComponentCallbacks mComponentCallbacks; |
| private final LoadProgressCoordinator mProgressBarCoordinator; |
| private final ToolbarTabControllerImpl mToolbarTabController; |
| private MenuButtonCoordinator mMenuButtonCoordinator; |
| private HomepageManager.HomepageStateListener mHomepageStateListener; |
| private StatusBarColorController mStatusBarColorController; |
| |
| private HomeButtonCoordinator mHomeButtonCoordinator; |
| private ToggleTabStackButtonCoordinator mToggleTabStackButtonCoordinator; |
| |
| private BrowserStateBrowserControlsVisibilityDelegate mControlsVisibilityDelegate; |
| private int mFullscreenFocusToken = TokenHolder.INVALID_TOKEN; |
| private int mFullscreenFindInPageToken = TokenHolder.INVALID_TOKEN; |
| private int mFullscreenMenuToken = TokenHolder.INVALID_TOKEN; |
| private int mFullscreenHighlightToken = TokenHolder.INVALID_TOKEN; |
| |
| private boolean mTabRestoreCompleted; |
| |
| |
| private boolean mInitializedWithNative; |
| private Runnable mOnInitializedRunnable; |
| |
| private boolean mShouldUpdateToolbarPrimaryColor = true; |
| private int mCurrentThemeColor; |
| |
| private int mCurrentOrientation; |
| |
| private final Supplier<Boolean> mCanAnimateNativeBrowserControls; |
| |
| /** |
| * Runnable for the home and search accelerator button when Start Surface home page is enabled. |
| */ |
| private Supplier<Boolean> mShowStartSurfaceSupplier; |
| private final ScrimCoordinator mScrimCoordinator; |
| |
| private StartSurface mStartSurface; |
| private StartSurface.StateObserver mStartSurfaceStateObserver; |
| private AppBarLayout.OnOffsetChangedListener mStartSurfaceHeaderOffsetChangeListener; |
| |
| private OneshotSupplier<IntentMetadata> mIntentMetadataOneshotSupplier; |
| private OneshotSupplier<Boolean> mPromoShownOneshotSupplier; |
| private OverlayPanelManagerObserver mOverlayPanelManagerObserver; |
| private ObservableSupplierImpl<Boolean> mOverlayPanelVisibilitySupplier = |
| new ObservableSupplierImpl<>(); |
| |
| private static class TabObscuringCallback implements Callback<Boolean> { |
| private final TabObscuringHandler mTabObscuringHandler; |
| /** A token held while the toolbar/omnibox is obscuring all visible tabs. */ |
| private int mTabObscuringToken = TokenHolder.INVALID_TOKEN; |
| public TabObscuringCallback(TabObscuringHandler handler) { |
| mTabObscuringHandler = handler; |
| } |
| |
| @Override |
| public void onResult(Boolean visible) { |
| if (visible) { |
| // It's possible for the scrim to unfocus and refocus without the |
| // visibility actually changing. In this case we have to make sure we |
| // unregister the previous token before acquiring a new one. |
| int oldToken = mTabObscuringToken; |
| mTabObscuringToken = mTabObscuringHandler.obscureAllTabs(); |
| if (oldToken != TokenHolder.INVALID_TOKEN) { |
| mTabObscuringHandler.unobscureAllTabs(oldToken); |
| } |
| } else { |
| mTabObscuringHandler.unobscureAllTabs(mTabObscuringToken); |
| mTabObscuringToken = TokenHolder.INVALID_TOKEN; |
| } |
| } |
| }; |
| |
| /** |
| * Creates a ToolbarManager object. |
| * |
| * @param activity The Android activity. |
| * @param controlsSizer The {@link BrowserControlsSizer} for the activity. |
| * @param fullscreenManager The {@link FullscreenManager} for the activity. |
| * @param controlContainer The container of the toolbar. |
| * @param compositorViewHolder Class that holds a {@link CompositorView}. |
| * @param urlFocusChangedCallback The callback to be notified when the URL focus changes. |
| * @param topUiThemeColorProvider The ThemeColorProvider object for top UI. |
| * @param tabObscuringHandler Delegate object handling obscuring views. |
| * @param shareDelegateSupplier Supplier for ShareDelegate. |
| * @param identityDiscController The controller that coordinates the state of the identity disc |
| * @param buttonDataProviders The list of button data providers for the optional toolbar button |
| * in the browsing mode toolbar, given in precedence order. |
| * @param tabProvider The {@link ActivityTabProvider} for accessing current activity tab. |
| * @param scrimCoordinator A means of showing the scrim. |
| * @param toolbarActionModeCallback Callback that communicates changes in the conceptual mode |
| * of toolbar interaction. |
| * @param findToolbarManager The manager for the find in page function. |
| * @param profileSupplier Supplier of the currently applicable profile. |
| * @param bookmarkBridgeSupplier Supplier of the bookmark bridge for the current profile. |
| * TODO(https://crbug.com/1084528): Use OneShotSupplier once it is ready. |
| * @param layoutStateProviderSupplier Supplier of the {@link LayoutStateProvider}. |
| * @param tabModelSelectorSupplier Supplier of the {@link TabModelSelector}. |
| * @param startSurfaceSupplier Supplier of the StartSurface. |
| * @param omniboxFocusStateSupplier Supplier to access the focus state of the omnibox. |
| * @param intentMetadataOneshotSupplier Supplier with info about the launching intent. |
| * @param promoShownOneshotSupplier Supplier for whether a promo was shown on startup. Will only |
| * be fulfilled when feature TOOLBAR_IPH_ANDROID is enabled. |
| * @param windowAndroid The {@link WindowAndroid} associated with the ToolbarManager. |
| * @param isInOverviewModeSupplier Supplies whether the app is currently in overview mode. |
| * @param isCustomTab Whether the toolbar is for a custom tab. |
| * @param modalDialogManagerSupplier Supplies the {@link ModalDialogManager}. |
| * @param statusBarColorController The {@link StatusBarColorController} for the app. |
| * @param appMenuDelegate Allows interacting with the app menu. |
| * @param activityLifecycleDispatcher Allows monitoring the activity lifecycle, |
| */ |
| public ToolbarManager(AppCompatActivity activity, BrowserControlsSizer controlsSizer, |
| FullscreenManager fullscreenManager, ToolbarControlContainer controlContainer, |
| CompositorViewHolder compositorViewHolder, Callback<Boolean> urlFocusChangedCallback, |
| TopUiThemeColorProvider topUiThemeColorProvider, |
| TabObscuringHandler tabObscuringHandler, |
| ObservableSupplier<ShareDelegate> shareDelegateSupplier, |
| IdentityDiscController identityDiscController, |
| List<ButtonDataProvider> buttonDataProviders, ActivityTabProvider tabProvider, |
| ScrimCoordinator scrimCoordinator, ToolbarActionModeCallback toolbarActionModeCallback, |
| FindToolbarManager findToolbarManager, ObservableSupplier<Profile> profileSupplier, |
| ObservableSupplier<BookmarkBridge> bookmarkBridgeSupplier, |
| @Nullable Supplier<Boolean> canAnimateNativeBrowserControls, |
| OneshotSupplier<LayoutStateProvider> layoutStateProviderSupplier, |
| OneshotSupplier<AppMenuCoordinator> appMenuCoordinatorSupplier, |
| boolean shouldShowUpdateBadge, |
| ObservableSupplier<TabModelSelector> tabModelSelectorSupplier, |
| OneshotSupplier<StartSurface> startSurfaceSupplier, |
| ObservableSupplier<Boolean> omniboxFocusStateSupplier, |
| OneshotSupplier<IntentMetadata> intentMetadataOneshotSupplier, |
| OneshotSupplier<Boolean> promoShownOneshotSupplier, WindowAndroid windowAndroid, |
| Supplier<Boolean> isInOverviewModeSupplier, boolean isCustomTab, |
| Supplier<ModalDialogManager> modalDialogManagerSupplier, |
| StatusBarColorController statusBarColorController, AppMenuDelegate appMenuDelegate, |
| ActivityLifecycleDispatcher activityLifecycleDispatcher, |
| @NonNull Supplier<Tab> startSurfaceParentTabSupplier) { |
| TraceEvent.begin("ToolbarManager.ToolbarManager"); |
| mActivity = activity; |
| mWindowAndroid = windowAndroid; |
| mCompositorViewHolder = compositorViewHolder; |
| mBrowserControlsSizer = controlsSizer; |
| mFullscreenManager = fullscreenManager; |
| mActionBarDelegate = new ViewShiftingActionBarDelegate(activity.getSupportActionBar(), |
| controlContainer, activity.findViewById(R.id.action_bar_black_background)); |
| mShareDelegateSupplier = shareDelegateSupplier; |
| mCanAnimateNativeBrowserControls = canAnimateNativeBrowserControls; |
| mScrimCoordinator = scrimCoordinator; |
| mTabModelSelectorSupplier = tabModelSelectorSupplier; |
| mOmniboxFocusStateSupplier = omniboxFocusStateSupplier; |
| mIntentMetadataOneshotSupplier = intentMetadataOneshotSupplier; |
| mPromoShownOneshotSupplier = promoShownOneshotSupplier; |
| mAppMenuDelegate = appMenuDelegate; |
| mStatusBarColorController = statusBarColorController; |
| mUrlFocusChangedCallback = urlFocusChangedCallback; |
| |
| ToolbarLayout toolbarLayout = mActivity.findViewById(R.id.toolbar); |
| NewTabPageDelegate ntpDelegate = createNewTabPageDelegate(toolbarLayout); |
| mLocationBarModel = new LocationBarModel(activity, ntpDelegate, |
| DomDistillerTabUtils::getFormattedUrlFromOriginalDistillerUrl, |
| IncognitoUtils::getNonPrimaryOTRProfileFromWindowAndroid, |
| new LocationBarModel.OfflineStatus() { |
| @Override |
| public boolean isShowingTrustedOfflinePage(WebContents webContents) { |
| return OfflinePageUtils.isShowingTrustedOfflinePage(webContents); |
| } |
| |
| @Override |
| public boolean isOfflinePage(Tab tab) { |
| return OfflinePageUtils.isOfflinePage(tab); |
| } |
| }); |
| mControlContainer = controlContainer; |
| assert mControlContainer != null; |
| |
| mBookmarkBridgeSupplier = bookmarkBridgeSupplier; |
| // We need to capture a reference to setBookmarkBridge/setCurrentProfile in order to remove |
| // them later; there is no guarantee in the JLS that referencing the same method later will |
| // reference the same object. |
| mBookmarkBridgeSupplierObserver = this::setBookmarkBridge; |
| mBookmarkBridgeSupplier.addObserver(mBookmarkBridgeSupplierObserver); |
| |
| mLayoutStateProviderSupplier = layoutStateProviderSupplier; |
| mLayoutStateProviderSupplier.onAvailable( |
| mCallbackController.makeCancelable(this::setLayoutStateProvider)); |
| |
| mComponentCallbacks = new ComponentCallbacks() { |
| @Override |
| public void onConfigurationChanged(Configuration configuration) { |
| int newOrientation = configuration.orientation; |
| if (newOrientation == mCurrentOrientation) { |
| return; |
| } |
| mCurrentOrientation = newOrientation; |
| onOrientationChange(newOrientation); |
| } |
| @Override |
| public void onLowMemory() {} |
| }; |
| mActivity.registerComponentCallbacks(mComponentCallbacks); |
| |
| mIncognitoStateProvider = new IncognitoStateProvider(); |
| mTabCountProvider = new TabCountProvider(); |
| mTopUiThemeColorProvider = topUiThemeColorProvider; |
| mTopUiThemeColorProvider.addThemeColorObserver(this); |
| |
| mAppThemeColorProvider = new AppThemeColorProvider(/* context= */ mActivity); |
| // Observe tint changes to update sub-components that rely on the tint (crbug.com/1077684). |
| mAppThemeColorProvider.addTintObserver(this); |
| mCustomTabThemeColorProvider = new SettableThemeColorProvider(/* context= */ mActivity); |
| |
| mActivityTabProvider = tabProvider; |
| mToolbarTabController = new ToolbarTabControllerImpl(mLocationBarModel::getTab, |
| () -> mShowStartSurfaceSupplier != null && mShowStartSurfaceSupplier.get(), |
| profileSupplier, mBottomControlsCoordinatorSupplier, ToolbarManager::homepageUrl, |
| this::updateButtonStatus); |
| |
| BrowserStateBrowserControlsVisibilityDelegate controlsVisibilityDelegate = |
| mBrowserControlsSizer.getBrowserVisibilityDelegate(); |
| assert controlsVisibilityDelegate != null; |
| mControlsVisibilityDelegate = controlsVisibilityDelegate; |
| ThemeColorProvider browsingModeThemeColorProvider = |
| DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity) |
| ? mAppThemeColorProvider |
| : mTopUiThemeColorProvider; |
| ThemeColorProvider overviewModeThemeColorProvider = mAppThemeColorProvider; |
| |
| Runnable requestFocusRunnable = compositorViewHolder::requestFocus; |
| mMenuButtonCoordinator = new MenuButtonCoordinator(appMenuCoordinatorSupplier, |
| mControlsVisibilityDelegate, mActivity, |
| (focus, type) |
| -> setUrlBarFocus(focus, type), |
| requestFocusRunnable, shouldShowUpdateBadge, isInOverviewModeSupplier, |
| isCustomTab ? mCustomTabThemeColorProvider : browsingModeThemeColorProvider, |
| R.id.menu_button_wrapper); |
| MenuButtonCoordinator startSurfaceMenuButtonCoordinator = new MenuButtonCoordinator( |
| appMenuCoordinatorSupplier, mControlsVisibilityDelegate, mActivity, |
| (focus, type) |
| -> setUrlBarFocus(focus, type), |
| requestFocusRunnable, shouldShowUpdateBadge, isInOverviewModeSupplier, |
| overviewModeThemeColorProvider, R.id.none); |
| |
| mToolbar = createTopToolbarCoordinator(controlContainer, toolbarLayout, buttonDataProviders, |
| browsingModeThemeColorProvider, startSurfaceMenuButtonCoordinator, |
| mCompositorViewHolder.getInvalidator(), identityDiscController, |
| startSurfaceSupplier); |
| mActionModeController = |
| new ActionModeController(mActivity, mActionBarDelegate, toolbarActionModeCallback); |
| |
| mActionModeController.setTabStripHeight(mToolbar.getTabStripHeight()); |
| |
| if (toolbarLayout instanceof CustomTabToolbar) { |
| CustomTabToolbar customTabToolbar = ((CustomTabToolbar) toolbarLayout); |
| mLocationBar = customTabToolbar.createLocationBar( |
| mLocationBarModel, mActionModeController.getActionModeCallback()); |
| } else { |
| OverrideUrlLoadingDelegate overrideUrlLoadingDelegate = |
| (url, transition, postDataType, postData, incognito) |
| -> ReturnToChromeExperimentsUtil.willHandleLoadUrlWithPostDataFromStartSurface( |
| url, transition, postDataType, postData, incognito, |
| startSurfaceParentTabSupplier.get()); |
| LocationBarCoordinator locationBarCoordinator = new LocationBarCoordinator( |
| mActivity.findViewById(R.id.location_bar), toolbarLayout, profileSupplier, |
| mLocationBarModel, mActionModeController.getActionModeCallback(), |
| new WindowDelegate(mActivity.getWindow()), windowAndroid, mActivityTabProvider, |
| modalDialogManagerSupplier, shareDelegateSupplier, mIncognitoStateProvider, |
| activityLifecycleDispatcher, overrideUrlLoadingDelegate); |
| toolbarLayout.setLocationBarCoordinator(locationBarCoordinator); |
| mLocationBar = locationBarCoordinator; |
| } |
| |
| if (mLocationBar.getFakeboxDelegate() != null) { |
| mLocationBar.getFakeboxDelegate().addUrlFocusChangeListener(this); |
| } |
| Runnable clickDelegate = |
| () -> setUrlBarFocus(false, OmniboxFocusReason.UNFOCUS); |
| View scrimTarget = mCompositorViewHolder; |
| mLocationBarFocusHandler = new LocationBarFocusScrimHandler(scrimCoordinator, |
| new TabObscuringCallback(tabObscuringHandler), /* context= */ activity, |
| mLocationBarModel, clickDelegate, scrimTarget); |
| if (mLocationBar.getFakeboxDelegate() != null) { |
| mLocationBar.getFakeboxDelegate().addUrlFocusChangeListener(mLocationBarFocusHandler); |
| } |
| |
| mProgressBarCoordinator = |
| new LoadProgressCoordinator(mActivityTabSupplier, mToolbar.getProgressBar()); |
| mToolbar.addUrlExpansionObserver(statusBarColorController); |
| |
| mActivityTabTabObserver = new ActivityTabProvider.ActivityTabTabObserver( |
| mActivityTabProvider) { |
| @Override |
| public void onObservingDifferentTab(Tab tab, boolean hint) { |
| mActivityTabSupplier.set(tab); |
| |
| // ActivityTabProvider will null out the tab passed to onObservingDifferentTab when |
| // the tab is non-interactive (e.g. when entering the TabSwitcher), but in those |
| // cases we actually still want to use the most recently selected tab. |
| if (tab == null) return; |
| |
| refreshSelectedTab(tab); |
| onTabOrModelChanged(); |
| } |
| |
| @Override |
| public void onSSLStateUpdated(Tab tab) { |
| if (mLocationBarModel.getTab() == null) return; |
| |
| assert tab == mLocationBarModel.getTab(); |
| mLocationBarModel.notifySecurityStateChanged(); |
| mLocationBarModel.notifyUrlChanged(); |
| } |
| |
| @Override |
| public void onTitleUpdated(Tab tab) { |
| mLocationBarModel.notifyTitleChanged(); |
| } |
| |
| @Override |
| public void onUrlUpdated(Tab tab) { |
| // Update the SSL security state as a result of this notification as it will |
| // sometimes be the only update we receive. |
| updateTabLoadingState(true); |
| |
| // A URL update is a decent enough indicator that the toolbar widget is in |
| // a stable state to capture its bitmap for use in fullscreen. |
| mControlContainer.setReadyForBitmapCapture(true); |
| } |
| |
| @Override |
| public void onShown(Tab tab, @TabSelectionType int type) { |
| if (TextUtils.isEmpty(tab.getUrlString())) return; |
| mControlContainer.setReadyForBitmapCapture(true); |
| } |
| |
| @Override |
| public void onCrash(Tab tab) { |
| updateTabLoadingState(false); |
| updateButtonStatus(); |
| } |
| |
| @Override |
| public void onLoadStarted(Tab tab, boolean toDifferentDocument) { |
| if (!toDifferentDocument) return; |
| updateButtonStatus(); |
| updateTabLoadingState(true); |
| } |
| |
| @Override |
| public void onLoadStopped(Tab tab, boolean toDifferentDocument) { |
| if (!toDifferentDocument) return; |
| updateTabLoadingState(true); |
| } |
| |
| @Override |
| public void onContentChanged(Tab tab) { |
| checkIfNtpLoaded(); |
| mToolbar.onTabContentViewChanged(); |
| if (shouldShowCursorInLocationBar()) { |
| mLocationBar.showUrlBarCursorWithoutFocusAnimations(); |
| } |
| // Paint preview status might have been changed. Update the omnibox chip. |
| mLocationBarModel.notifySecurityStateChanged(); |
| } |
| |
| @Override |
| public void onWebContentsSwapped(Tab tab, boolean didStartLoad, boolean didFinishLoad) { |
| if (!didStartLoad) return; |
| mLocationBarModel.notifyUrlChanged(); |
| mLocationBarModel.notifySecurityStateChanged(); |
| } |
| |
| @Override |
| public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) { |
| NewTabPage ntp = getNewTabPageForCurrentTab(); |
| if (ntp == null) return; |
| if (!UrlUtilities.isNTPUrl(params.getUrl()) |
| && loadType != TabLoadStatus.PAGE_LOAD_FAILED) { |
| ntp.setUrlFocusAnimationsDisabled(true); |
| onTabOrModelChanged(); |
| } |
| } |
| |
| private boolean hasPendingNonNtpNavigation(Tab tab) { |
| WebContents webContents = tab.getWebContents(); |
| if (webContents == null) return false; |
| |
| NavigationController navigationController = webContents.getNavigationController(); |
| if (navigationController == null) return false; |
| |
| NavigationEntry pendingEntry = navigationController.getPendingEntry(); |
| if (pendingEntry == null) return false; |
| |
| return !UrlUtilities.isNTPUrl(pendingEntry.getUrl()); |
| } |
| |
| @Override |
| public void onDidStartNavigation(Tab tab, NavigationHandle navigation) { |
| if (!navigation.isInMainFrame()) return; |
| // Update URL as soon as it becomes available when it's a new tab. |
| // But we want to update only when it's a new tab. So we check whether the current |
| // navigation entry is initial, meaning whether it has the same target URL as the |
| // initial URL of the tab. |
| if (tab.getWebContents() != null |
| && tab.getWebContents().getNavigationController() != null |
| && tab.getWebContents().getNavigationController().isInitialNavigation()) { |
| mLocationBarModel.notifyUrlChanged(); |
| } |
| } |
| |
| @Override |
| public void onDidFinishNavigation(Tab tab, NavigationHandle navigation) { |
| if (navigation.hasCommitted() && navigation.isInMainFrame() |
| && !navigation.isSameDocument()) { |
| mToolbar.onNavigatedToDifferentPage(); |
| } |
| |
| if (navigation.hasCommitted() && Previews.isPreview(tab)) { |
| // Some previews are not fully decided until the page commits. If this |
| // is a preview, update the security icon which will also update the verbose |
| // status view to make sure the "Lite" badge is displayed. |
| mLocationBarModel.notifySecurityStateChanged(); |
| PreviewsUma.recordLitePageAtCommit( |
| PreviewsAndroidBridge.getInstance().getPreviewsType( |
| tab.getWebContents()), |
| navigation.isInMainFrame()); |
| } |
| |
| // If the load failed due to a different navigation, there is no need to reset the |
| // location bar animations. |
| if (navigation.errorCode() != NetError.OK && navigation.isInMainFrame() |
| && !hasPendingNonNtpNavigation(tab)) { |
| NewTabPage ntp = getNewTabPageForCurrentTab(); |
| if (ntp == null) return; |
| |
| ntp.setUrlFocusAnimationsDisabled(false); |
| onTabOrModelChanged(); |
| } |
| } |
| |
| @Override |
| public void onNavigationEntriesDeleted(Tab tab) { |
| if (tab == mLocationBarModel.getTab()) { |
| updateButtonStatus(); |
| } |
| } |
| }; |
| |
| mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() { |
| @Override |
| public void onTabStateInitialized() { |
| mTabRestoreCompleted = true; |
| handleTabRestoreCompleted(); |
| } |
| |
| @Override |
| public void onTabModelSelected(TabModel newModel, TabModel oldModel) { |
| if (mTabModelSelector != null) { |
| refreshSelectedTab(mTabModelSelector.getCurrentTab()); |
| } |
| } |
| }; |
| |
| mBookmarksObserver = new BookmarkBridge.BookmarkModelObserver() { |
| @Override |
| public void bookmarkModelChanged() { |
| updateBookmarkButtonStatus(); |
| } |
| }; |
| |
| mBrowserControlsObserver = new BrowserControlsStateProvider.Observer() { |
| @Override |
| public void onControlsOffsetChanged(int topOffset, int topControlsMinHeightOffset, |
| int bottomOffset, int bottomControlsMinHeightOffset, boolean needsAnimate) { |
| // Controls need to be offset to match the composited layer, which is |
| // anchored at the bottom of the controls container. |
| setControlContainerTopMargin(getToolbarExtraYOffset()); |
| } |
| }; |
| mBrowserControlsSizer.addObserver(mBrowserControlsObserver); |
| |
| mFullscreenObserver = new FullscreenManager.Observer() { |
| @Override |
| public void onEnterFullscreen(Tab tab, FullscreenOptions options) { |
| if (mFindToolbarManager != null) mFindToolbarManager.hideToolbar(); |
| } |
| }; |
| mFullscreenManager.addObserver(mFullscreenObserver); |
| |
| mFindToolbarObserver = new FindToolbarObserver() { |
| @Override |
| public void onFindToolbarShown() { |
| mToolbar.handleFindLocationBarStateChange(true); |
| if (mControlsVisibilityDelegate != null) { |
| mFullscreenFindInPageToken = |
| mControlsVisibilityDelegate.showControlsPersistentAndClearOldToken( |
| mFullscreenFindInPageToken); |
| } |
| } |
| |
| @Override |
| public void onFindToolbarHidden() { |
| mToolbar.handleFindLocationBarStateChange(false); |
| if (mControlsVisibilityDelegate != null) { |
| mControlsVisibilityDelegate.releasePersistentShowingToken( |
| mFullscreenFindInPageToken); |
| } |
| } |
| }; |
| |
| mLayoutStateObserver = new LayoutStateProvider.LayoutStateObserver() { |
| @Override |
| public void onStartedShowing(@LayoutType int layoutType, boolean showToolbar) { |
| if (layoutType == LayoutType.TAB_SWITCHER) { |
| mToolbar.setTabSwitcherMode(true, showToolbar, false); |
| updateButtonStatus(); |
| if (mLocationBarModel.shouldShowLocationBarInOverviewMode()) { |
| assert mLocationBar instanceof LocationBarCoordinator; |
| ((LocationBarCoordinator) mLocationBar).startAutocompletePrefetch(); |
| } |
| } |
| } |
| |
| @Override |
| public void onStartedHiding( |
| @LayoutType int layoutType, boolean showToolbar, boolean delayAnimation) { |
| if (layoutType == LayoutType.TAB_SWITCHER) { |
| mToolbar.setTabSwitcherMode(false, showToolbar, delayAnimation); |
| updateButtonStatus(); |
| } |
| } |
| |
| @Override |
| public void onFinishedHiding(@LayoutType int layoutType) { |
| if (layoutType == LayoutType.TAB_SWITCHER) { |
| mToolbar.onTabSwitcherTransitionFinished(); |
| updateButtonStatus(); |
| } |
| } |
| }; |
| |
| mSceneChangeObserver = new SceneChangeObserver() { |
| @Override |
| public void onTabSelectionHinted(int tabId) { |
| Tab tab = mTabModelSelector != null ? mTabModelSelector.getTabById(tabId) : null; |
| refreshSelectedTab(tab); |
| |
| if (mToolbar.setForceTextureCapture(true)) { |
| mControlContainer.invalidateBitmap(); |
| } |
| } |
| |
| @Override |
| public void onSceneChange(Layout layout) { |
| mToolbar.setContentAttached(layout.shouldDisplayContentOverlay()); |
| } |
| }; |
| |
| mOverlayPanelManagerObserver = new OverlayPanelManagerObserver() { |
| @Override |
| public void onOverlayPanelShown() { |
| mOverlayPanelVisibilitySupplier.set(true); |
| } |
| |
| @Override |
| public void onOverlayPanelHidden() { |
| mOverlayPanelVisibilitySupplier.set(false); |
| } |
| }; |
| |
| mToolbar.setTabCountProvider(mTabCountProvider); |
| mToolbar.setIncognitoStateProvider(mIncognitoStateProvider); |
| |
| ChromeAccessibilityUtil.get().addObserver(this); |
| mLocationBarModel.setShouldShowOmniboxInOverviewMode( |
| StartSurfaceConfiguration.isStartSurfaceEnabled()); |
| |
| mFindToolbarManager = findToolbarManager; |
| mFindToolbarManager.addObserver(mFindToolbarObserver); |
| |
| startSurfaceSupplier.onAvailable(mCallbackController.makeCancelable((startSurface) -> { |
| mStartSurface = startSurface; |
| mStartSurfaceStateObserver = (newState, shouldShowToolbar) -> { |
| assert StartSurfaceConfiguration.isStartSurfaceEnabled(); |
| mStartSurfaceState = newState; |
| mToolbar.updateStartSurfaceToolbarState(newState, shouldShowToolbar); |
| }; |
| mStartSurface.addStateChangeObserver(mStartSurfaceStateObserver); |
| |
| mStartSurfaceHeaderOffsetChangeListener = (appbarLayout, verticalOffset) -> { |
| assert StartSurfaceConfiguration.isStartSurfaceEnabled(); |
| mToolbar.onStartSurfaceHeaderOffsetChanged(verticalOffset); |
| }; |
| mStartSurface.addHeaderOffsetChangeListener(mStartSurfaceHeaderOffsetChangeListener); |
| })); |
| |
| TraceEvent.end("ToolbarManager.ToolbarManager"); |
| } |
| |
| private TopToolbarCoordinator createTopToolbarCoordinator( |
| ToolbarControlContainer controlContainer, ToolbarLayout toolbarLayout, |
| List<ButtonDataProvider> buttonDataProviders, |
| ThemeColorProvider browsingModeThemeColorProvider, |
| MenuButtonCoordinator startSurfaceMenuButtonCoordinator, Invalidator invalidator, |
| IdentityDiscController identityDiscController, |
| OneshotSupplier<StartSurface> startSurfaceSupplier) { |
| // clang-format off |
| TopToolbarCoordinator toolbar = new TopToolbarCoordinator(controlContainer, toolbarLayout, |
| mLocationBarModel, mToolbarTabController, |
| new UserEducationHelper(mActivity, mHandler, TrackerFactory::getTrackerForProfile), |
| buttonDataProviders, mLayoutStateProviderSupplier, browsingModeThemeColorProvider, |
| mAppThemeColorProvider, mMenuButtonCoordinator, startSurfaceMenuButtonCoordinator, |
| mMenuButtonCoordinator.getMenuButtonHelperSupplier(), mTabModelSelectorSupplier, |
| mHomeButtonVisibilitySupplier, mIdentityDiscStateSupplier, (client) -> { |
| if (invalidator != null) { |
| invalidator.invalidate(client); |
| } else { |
| client.run(); |
| } |
| }, () -> identityDiscController.getForStartSurface(mStartSurfaceState), |
| startSurfaceSupplier, mCompositorViewHolder::getResourceManager); |
| // clang-format on |
| mHomepageStateListener = () -> { |
| mHomeButtonVisibilitySupplier.set(HomepageManager.isHomepageEnabled()); |
| mHomepageManagedByPolicySupplier.set(HomepagePolicyManager.isHomepageManagedByPolicy()); |
| }; |
| HomepageManager.getInstance().addListener(mHomepageStateListener); |
| mHomepageStateListener.onHomepageStateUpdated(); |
| |
| if (toolbarLayout instanceof ToolbarPhone |
| && StartSurfaceConfiguration.isStartSurfaceEnabled()) { |
| identityDiscController.addObserver( |
| (canShowHint) -> mIdentityDiscStateSupplier.set(canShowHint)); |
| } |
| HomeButton homeButton = toolbarLayout.getHomeButton(); |
| if (homeButton != null) { |
| homeButton.init(mHomeButtonVisibilitySupplier, |
| HomepageManager.getInstance()::onMenuClick, mHomepageManagedByPolicySupplier); |
| } |
| return toolbar; |
| } |
| |
| // Base abstract implementation of NewTabPageDelegate for phone/table toolbar layout. |
| private abstract class ToolbarNtpDelegate implements NewTabPageDelegate { |
| protected NewTabPage mVisibleNtp; |
| |
| @Override |
| public boolean wasShowingNtp() { |
| return mVisibleNtp != null; |
| } |
| |
| @Override |
| public boolean isCurrentlyVisible() { |
| return getNewTabPageForCurrentTab() != null; |
| } |
| |
| @Override |
| public boolean dispatchTouchEvent(MotionEvent ev) { |
| assert mVisibleNtp != null; |
| // No null check -- the toolbar should not be moved if we are not on an NTP. |
| return mVisibleNtp.getView().dispatchTouchEvent(ev); |
| } |
| |
| @Override |
| public boolean isLocationBarShown() { |
| // Without this check, ToolbarPhone#computeVisualState may return |
| // VisualState.NEW_TAB_NORMAL even if it's in start surface homepage, which leads |
| // ToolbarPhone#getToolbarColorForVisualState to return transparent color. |
| if (StartSurfaceConfiguration.isStartSurfaceEnabled() |
| && mStartSurfaceState == StartSurfaceState.SHOWN_HOMEPAGE) { |
| return false; |
| } |
| NewTabPage ntp = getNewTabPageForCurrentTab(); |
| return ntp != null && ntp.isLocationBarShownInNTP(); |
| } |
| |
| @Override |
| public boolean transitioningAwayFromLocationBar() { |
| return mVisibleNtp != null && mVisibleNtp.isLocationBarShownInNTP() |
| && !isLocationBarShown(); |
| } |
| |
| @Override |
| public void setSearchBoxScrollListener(Callback<Float> scrollCallback) { |
| NewTabPage newVisibleNtp = getNewTabPageForCurrentTab(); |
| if (mVisibleNtp != null) mVisibleNtp.setSearchBoxScrollListener(null); |
| mVisibleNtp = newVisibleNtp; |
| if (mVisibleNtp != null && shouldUpdateListener()) { |
| mVisibleNtp.setSearchBoxScrollListener( |
| (fraction) -> scrollCallback.onResult(fraction)); |
| } |
| } |
| |
| // Boolean predicate that tells if the NewTabPage.OnSearchBoxScrollListener |
| // should be updated or not |
| protected abstract boolean shouldUpdateListener(); |
| |
| @Override |
| public void getSearchBoxBounds(Rect bounds, Point translation) { |
| assert getNewTabPageForCurrentTab() != null; |
| getNewTabPageForCurrentTab().getSearchBoxBounds(bounds, translation); |
| } |
| |
| @Override |
| public void setSearchBoxBackground(Drawable drawable) { |
| assert getNewTabPageForCurrentTab() != null; |
| getNewTabPageForCurrentTab().setSearchBoxBackground(drawable); |
| } |
| |
| @Override |
| public void setSearchBoxAlpha(float alpha) { |
| assert getNewTabPageForCurrentTab() != null; |
| getNewTabPageForCurrentTab().setSearchBoxAlpha(alpha); |
| } |
| |
| @Override |
| public void setSearchProviderLogoAlpha(float alpha) { |
| assert getNewTabPageForCurrentTab() != null; |
| getNewTabPageForCurrentTab().setSearchProviderLogoAlpha(alpha); |
| } |
| |
| @Override |
| public void setUrlFocusChangeAnimationPercent(float fraction) { |
| NewTabPage ntp = getNewTabPageForCurrentTab(); |
| if (ntp != null) ntp.setUrlFocusChangeAnimationPercent(fraction); |
| } |
| } |
| |
| private NewTabPageDelegate createNewTabPageDelegate(ToolbarLayout toolbarLayout) { |
| if (toolbarLayout instanceof ToolbarPhone) { |
| return new ToolbarNtpDelegate() { |
| @Override |
| protected boolean shouldUpdateListener() { |
| return mVisibleNtp.isLocationBarShownInNTP(); |
| } |
| }; |
| } else if (toolbarLayout instanceof ToolbarTablet) { |
| return new ToolbarNtpDelegate() { |
| @Override |
| public void setSearchBoxScrollListener(Callback<Float> scrollCallback) { |
| if (mVisibleNtp == getNewTabPageForCurrentTab()) return; |
| super.setSearchBoxScrollListener(scrollCallback); |
| } |
| |
| @Override |
| protected boolean shouldUpdateListener() { |
| return true; |
| } |
| }; |
| } |
| return NewTabPageDelegate.EMPTY; |
| } |
| |
| private NewTabPage getNewTabPageForCurrentTab() { |
| if (mLocationBarModel.hasTab()) { |
| NativePage nativePage = mLocationBarModel.getTab().getNativePage(); |
| if (nativePage instanceof NewTabPage) return (NewTabPage) nativePage; |
| } |
| return null; |
| } |
| |
| /** |
| * Called when the contextual action bar's visibility has changed (i.e. the widget shown |
| * when you can copy/paste text after long press). |
| * @param visible Whether the contextual action bar is now visible. |
| */ |
| public void onActionBarVisibilityChanged(boolean visible) { |
| ActionBar actionBar = mActionBarDelegate.getSupportActionBar(); |
| if (!visible && actionBar != null) actionBar.hide(); |
| if (DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity)) { |
| if (visible) { |
| mActionModeController.startShowAnimation(); |
| } else { |
| mActionModeController.startHideAnimation(); |
| } |
| } |
| } |
| |
| /** |
| * @return Whether the UrlBar currently has focus. |
| */ |
| public boolean isUrlBarFocused() { |
| if (mLocationBar.getFakeboxDelegate() == null) { |
| return false; |
| } |
| return mLocationBar.getFakeboxDelegate().isUrlBarFocused(); |
| } |
| |
| /** |
| * Enable the bottom controls. |
| */ |
| public void enableBottomControls() { |
| mBottomControlsCoordinatorSupplier.set( |
| new BottomControlsCoordinator(mActivity, mWindowAndroid, mLayoutManager, |
| mCompositorViewHolder.getResourceManager(), mBrowserControlsSizer, |
| mFullscreenManager, mActivity.findViewById(R.id.bottom_controls_stub), |
| mAppThemeColorProvider, mShareDelegateSupplier, mScrimCoordinator, |
| mOmniboxFocusStateSupplier, mOverlayPanelVisibilitySupplier)); |
| } |
| |
| /** |
| * @return The coordinator for the bottom controls if it exists. |
| */ |
| public BottomControlsCoordinator getBottomControlsCoordinator() { |
| return mBottomControlsCoordinatorSupplier.get(); |
| } |
| |
| /** |
| * Initialize the manager with the components that had native initialization dependencies. |
| * <p> |
| * Calling this must occur after the native library have completely loaded. |
| * |
| * @param layoutManager A {@link LayoutManagerImpl} instance used to watch for scene |
| * changes. |
| * @param tabSwitcherClickHandler The {@link OnClickListener} for the tab switcher button. |
| * @param newTabClickHandler The {@link OnClickListener} for the new tab button. |
| * @param bookmarkClickHandler The {@link OnClickListener} for the bookmark button. |
| * @param customTabsBackClickHandler The {@link OnClickListener} for the custom tabs back |
| * button. |
| * @param showStartSurfaceSupplier Supplies if we should show the start surface. |
| */ |
| public void initializeWithNative(LayoutManagerImpl layoutManager, |
| OnClickListener tabSwitcherClickHandler, OnClickListener newTabClickHandler, |
| OnClickListener bookmarkClickHandler, OnClickListener customTabsBackClickHandler, |
| Supplier<Boolean> showStartSurfaceSupplier) { |
| TraceEvent.begin("ToolbarManager.initializeWithNative"); |
| assert !mInitializedWithNative; |
| assert mTabModelSelectorSupplier.get() != null; |
| |
| mTabModelSelector = mTabModelSelectorSupplier.get(); |
| mShowStartSurfaceSupplier = showStartSurfaceSupplier; |
| |
| OnLongClickListener tabSwitcherLongClickHandler = |
| TabSwitcherActionMenuCoordinator.createOnLongClickListener( |
| (id) -> mAppMenuDelegate.onOptionsItemSelected(id, null)); |
| |
| mToolbar.initializeWithNative(layoutManager::requestUpdate, tabSwitcherClickHandler, |
| tabSwitcherLongClickHandler, newTabClickHandler, bookmarkClickHandler, |
| customTabsBackClickHandler, layoutManager, mActivityTabSupplier, |
| mBrowserControlsSizer, mTopUiThemeColorProvider); |
| |
| mToolbar.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { |
| @Override |
| public void onViewDetachedFromWindow(View v) {} |
| |
| @Override |
| public void onViewAttachedToWindow(View v) { |
| // As we have only just registered for notifications, any that were sent prior |
| // to this may have been missed. Calling refreshSelectedTab in case we missed |
| // the initial selection notification. |
| refreshSelectedTab(mActivityTabProvider.get()); |
| } |
| }); |
| |
| mLocationBarModel.initializeWithNative(); |
| |
| if (layoutManager != null) { |
| mLayoutManager = layoutManager; |
| mLayoutManager.addSceneChangeObserver(mSceneChangeObserver); |
| mLayoutManager.getOverlayPanelManager().addObserver(mOverlayPanelManagerObserver); |
| } |
| |
| // TODO(https://crbug.com/1086676, pnoland): Remove this by having MBC listen for native |
| // init directly. |
| mMenuButtonCoordinator.onNativeInitialized(); |
| |
| TemplateUrlServiceFactory.get().runWhenLoaded(this::registerTemplateUrlObserver); |
| mInitializedWithNative = true; |
| mTabModelSelector.addObserver(mTabModelSelectorObserver); |
| refreshSelectedTab(mActivityTabProvider.get()); |
| if (mTabModelSelector.isTabStateInitialized()) mTabRestoreCompleted = true; |
| handleTabRestoreCompleted(); |
| mTabCountProvider.setTabModelSelector(mTabModelSelector); |
| mIncognitoStateProvider.setTabModelSelector(mTabModelSelector); |
| mAppThemeColorProvider.setIncognitoStateProvider(mIncognitoStateProvider); |
| |
| if (mOnInitializedRunnable != null) { |
| mOnInitializedRunnable.run(); |
| mOnInitializedRunnable = null; |
| } |
| |
| // Allow bitmap capturing once everything has been initialized. |
| Tab currentTab = mTabModelSelector.getCurrentTab(); |
| if (currentTab != null && currentTab.getWebContents() != null |
| && !TextUtils.isEmpty(currentTab.getUrlString())) { |
| mControlContainer.setReadyForBitmapCapture(true); |
| } |
| |
| if (ChromeFeatureList.isEnabled(ChromeFeatureList.TOOLBAR_IPH_ANDROID)) { |
| UserEducationHelper userEducationHelper = new UserEducationHelper( |
| mActivity, mHandler, TrackerFactory::getTrackerForProfile); |
| Tracker tracker = |
| TrackerFactory.getTrackerForProfile(Profile.getLastUsedRegularProfile()); |
| View homeButton = mControlContainer.findViewById(R.id.home_button); |
| mHomeButtonCoordinator = new HomeButtonCoordinator(mActivity, homeButton, |
| userEducationHelper, mIncognitoStateProvider::isIncognitoSelected, |
| mIntentMetadataOneshotSupplier, mPromoShownOneshotSupplier, |
| HomepageManager::isHomepageNonNtp, mActivityTabSupplier, tracker); |
| ToggleTabStackButton toggleTabStackButton = |
| mControlContainer.findViewById(R.id.tab_switcher_button); |
| mToggleTabStackButtonCoordinator = new ToggleTabStackButtonCoordinator(mActivity, |
| toggleTabStackButton, userEducationHelper, |
| mIncognitoStateProvider::isIncognitoSelected, mIntentMetadataOneshotSupplier, |
| mPromoShownOneshotSupplier, mLayoutStateProviderSupplier, |
| mToolbar::setNewTabButtonHighlight, mActivityTabSupplier, tracker); |
| } |
| mActivityTabSupplier.set(mActivityTabProvider.get()); |
| TraceEvent.end("ToolbarManager.initializeWithNative"); |
| } |
| |
| /** |
| * @return The toolbar interface that this manager handles. |
| */ |
| public Toolbar getToolbar() { |
| return mToolbar; |
| } |
| |
| @Override |
| public @Nullable View getMenuButtonView() { |
| return mMenuButtonCoordinator.getMenuButton().getImageButton(); |
| } |
| |
| /** |
| * TODO(twellington): Try to remove this method. It's only used to return an in-product help |
| * bubble anchor view... which should be moved out of tab and perhaps into |
| * the status bar icon component. |
| * @return The view containing the security icon. |
| */ |
| public View getSecurityIconView() { |
| return mLocationBar.getSecurityIconView(); |
| } |
| |
| /** |
| * Adds a custom action button to the {@link Toolbar}, if it is supported. |
| * @param drawable The {@link Drawable} to use as the background for the button. |
| * @param description The content description for the custom action button. |
| * @param listener The {@link OnClickListener} to use for clicks to the button. |
| * @see #updateCustomActionButton |
| */ |
| public void addCustomActionButton( |
| Drawable drawable, String description, OnClickListener listener) { |
| mToolbar.addCustomActionButton(drawable, description, listener); |
| } |
| |
| /** |
| * Updates the visual appearance of a custom action button in the {@link Toolbar}, |
| * if it is supported. |
| * @param index The index of the button to update. |
| * @param drawable The {@link Drawable} to use as the background for the button. |
| * @param description The content description for the custom action button. |
| * @see #addCustomActionButton |
| */ |
| public void updateCustomActionButton(int index, Drawable drawable, String description) { |
| mToolbar.updateCustomActionButton(index, drawable, description); |
| } |
| |
| /** |
| * Call to tear down all of the toolbar dependencies. |
| */ |
| public void destroy() { |
| if (mInitializedWithNative) { |
| mFindToolbarManager.removeObserver(mFindToolbarObserver); |
| } |
| if (mTabModelSelectorSupplier != null) { |
| mTabModelSelectorSupplier = null; |
| } |
| if (mTabModelSelector != null) { |
| mTabModelSelector.removeObserver(mTabModelSelectorObserver); |
| } |
| if (mBookmarkBridgeSupplier != null) { |
| BookmarkBridge bridge = mBookmarkBridgeSupplier.get(); |
| if (bridge != null) bridge.removeObserver(mBookmarksObserver); |
| |
| mBookmarkBridgeSupplier.removeObserver(mBookmarkBridgeSupplierObserver); |
| mBookmarkBridgeSupplier = null; |
| } |
| if (mTemplateUrlObserver != null) { |
| TemplateUrlServiceFactory.get().removeObserver(mTemplateUrlObserver); |
| mTemplateUrlObserver = null; |
| } |
| if (mLayoutStateProvider != null) { |
| mLayoutStateProvider.removeObserver(mLayoutStateObserver); |
| mLayoutStateProvider = null; |
| } |
| |
| if (mLayoutStateProviderSupplier != null) { |
| mLayoutStateProviderSupplier = null; |
| } |
| |
| if (mLayoutManager != null) { |
| mLayoutManager.removeSceneChangeObserver(mSceneChangeObserver); |
| mLayoutManager.getOverlayPanelManager().removeObserver(mOverlayPanelManagerObserver); |
| mLayoutManager = null; |
| } |
| |
| HomepageManager.getInstance().removeListener(mHomepageStateListener); |
| |
| if (mBottomControlsCoordinatorSupplier.get() != null) { |
| mBottomControlsCoordinatorSupplier.get().destroy(); |
| mBottomControlsCoordinatorSupplier = null; |
| } |
| |
| mToolbar.removeUrlExpansionObserver(mStatusBarColorController); |
| mToolbar.destroy(); |
| |
| if (mTabObserver != null) { |
| Tab currentTab = mLocationBarModel.getTab(); |
| if (currentTab != null) currentTab.removeObserver(mTabObserver); |
| mTabObserver = null; |
| } |
| |
| mIncognitoStateProvider.destroy(); |
| mTabCountProvider.destroy(); |
| |
| mLocationBarModel.destroy(); |
| mHandler.removeCallbacksAndMessages(null); // Cancel delayed tasks. |
| mBrowserControlsSizer.removeObserver(mBrowserControlsObserver); |
| mFullscreenManager.removeObserver(mFullscreenObserver); |
| |
| if (mTopUiThemeColorProvider != null) { |
| mTopUiThemeColorProvider.removeThemeColorObserver(this); |
| } |
| |
| if (mAppThemeColorProvider != null) { |
| mAppThemeColorProvider.removeTintObserver(this); |
| mAppThemeColorProvider.destroy(); |
| mAppThemeColorProvider = null; |
| } |
| |
| if (mActivityTabTabObserver != null) { |
| mActivityTabTabObserver.destroy(); |
| mActivityTabTabObserver = null; |
| } |
| |
| if (mProgressBarCoordinator != null) mProgressBarCoordinator.destroy(); |
| |
| if (mFindToolbarManager != null) { |
| mFindToolbarManager.removeObserver(mFindToolbarObserver); |
| mFindToolbarManager = null; |
| } |
| |
| if (mMenuButtonCoordinator != null) { |
| mMenuButtonCoordinator.destroy(); |
| mMenuButtonCoordinator = null; |
| } |
| |
| if (mHomeButtonCoordinator != null) { |
| mHomeButtonCoordinator.destroy(); |
| mHomeButtonCoordinator = null; |
| } |
| if (mToggleTabStackButtonCoordinator != null) { |
| mToggleTabStackButtonCoordinator.destroy(); |
| mToggleTabStackButtonCoordinator = null; |
| } |
| |
| if (mCallbackController != null) { |
| mCallbackController.destroy(); |
| mCallbackController = null; |
| } |
| |
| if (mStartSurface != null) { |
| mStartSurface.removeStateChangeObserver(mStartSurfaceStateObserver); |
| mStartSurface.removeHeaderOffsetChangeListener(mStartSurfaceHeaderOffsetChangeListener); |
| mStartSurface = null; |
| mStartSurfaceStateObserver = null; |
| mStartSurfaceHeaderOffsetChangeListener = null; |
| } |
| |
| mActivity.unregisterComponentCallbacks(mComponentCallbacks); |
| mComponentCallbacks = null; |
| ChromeAccessibilityUtil.get().removeObserver(this); |
| } |
| |
| /** |
| * Called when the orientation of the activity has changed. |
| */ |
| private void onOrientationChange(int newOrientation) { |
| if (mActionModeController != null) mActionModeController.showControlsOnOrientationChange(); |
| } |
| |
| @Override |
| public void onAccessibilityModeChanged(boolean enabled) { |
| mToolbar.onAccessibilityStatusChanged(enabled); |
| } |
| |
| @VisibleForTesting |
| static String homepageUrl() { |
| String homePageUrl = HomepageManager.getHomepageUri(); |
| if (TextUtils.isEmpty(homePageUrl)) homePageUrl = UrlConstants.NTP_URL; |
| return homePageUrl; |
| } |
| |
| private void registerTemplateUrlObserver() { |
| final TemplateUrlService templateUrlService = TemplateUrlServiceFactory.get(); |
| assert mTemplateUrlObserver == null; |
| mTemplateUrlObserver = new TemplateUrlServiceObserver() { |
| private TemplateUrl mSearchEngine = |
| templateUrlService.getDefaultSearchEngineTemplateUrl(); |
| |
| @Override |
| public void onTemplateURLServiceChanged() { |
| TemplateUrl searchEngine = templateUrlService.getDefaultSearchEngineTemplateUrl(); |
| if ((mSearchEngine == null && searchEngine == null) |
| || (mSearchEngine != null && mSearchEngine.equals(searchEngine))) { |
| return; |
| } |
| |
| mSearchEngine = searchEngine; |
| mToolbar.onDefaultSearchEngineChanged(); |
| } |
| }; |
| templateUrlService.addObserver(mTemplateUrlObserver); |
| } |
| |
| private void handleTabRestoreCompleted() { |
| if (!mTabRestoreCompleted || !mInitializedWithNative) return; |
| mToolbar.onStateRestored(); |
| } |
| |
| // TODO(https://crbug.com/865801): remove the below two methods if possible. |
| public boolean back() { |
| return mToolbarTabController.back(); |
| } |
| |
| public boolean forward() { |
| return mToolbarTabController.forward(); |
| } |
| |
| /** |
| * Triggered when the URL input field has gained or lost focus. |
| * @param hasFocus Whether the URL field has gained focus. |
| */ |
| @Override |
| public void onUrlFocusChange(boolean hasFocus) { |
| mToolbar.onUrlFocusChange(hasFocus); |
| |
| if (mFindToolbarManager != null && hasFocus) mFindToolbarManager.hideToolbar(); |
| |
| if (mControlsVisibilityDelegate == null) return; |
| if (hasFocus) { |
| mFullscreenFocusToken = |
| mControlsVisibilityDelegate.showControlsPersistentAndClearOldToken( |
| mFullscreenFocusToken); |
| } else { |
| mControlsVisibilityDelegate.releasePersistentShowingToken(mFullscreenFocusToken); |
| } |
| |
| mUrlFocusChangedCallback.onResult(hasFocus); |
| } |
| |
| /** |
| * Updates the primary color used by the model to the given color. |
| * @param color The primary color for the current tab. |
| * @param shouldAnimate Whether the change of color should be animated. |
| */ |
| @Override |
| public void onThemeColorChanged(int color, boolean shouldAnimate) { |
| if (!mShouldUpdateToolbarPrimaryColor) return; |
| |
| boolean colorChanged = mCurrentThemeColor != color; |
| if (!colorChanged) return; |
| |
| mCurrentThemeColor = color; |
| mLocationBarModel.setPrimaryColor(color); |
| mToolbar.onPrimaryColorChanged(shouldAnimate); |
| // TODO(https://crbug.com/865801, pnoland): Rationalize theme color logic |
| // into a set of documented, self-contained providers that we can inject to the appropriate |
| // sub-components. That will let us have every component handle its own coloring, and remove |
| // onThemeColorChanged from ToolbarManager. |
| mCustomTabThemeColorProvider.setPrimaryColor(color, shouldAnimate); |
| } |
| |
| @Override |
| public void onTintChanged(ColorStateList tint, boolean useLight) { |
| updateBookmarkButtonStatus(); |
| } |
| |
| /** |
| * @param shouldUpdate Whether we should be updating the toolbar primary color based on updates |
| * from the Tab. |
| */ |
| public void setShouldUpdateToolbarPrimaryColor(boolean shouldUpdate) { |
| mShouldUpdateToolbarPrimaryColor = shouldUpdate; |
| } |
| |
| /** |
| * @return The primary toolbar color. |
| */ |
| public int getPrimaryColor() { |
| return mLocationBarModel.getPrimaryColor(); |
| } |
| |
| /** |
| * Sets the visibility of the Toolbar shadow. |
| */ |
| public void setToolbarShadowVisibility(int visibility) { |
| View toolbarShadow = mControlContainer.findViewById(R.id.toolbar_shadow); |
| if (toolbarShadow != null) toolbarShadow.setVisibility(visibility); |
| } |
| |
| /** |
| * We use getTopControlOffset to position the top controls. However, the toolbar's height may |
| * be less than the total top controls height. If that's the case, this method will return the |
| * extra offset needed to align the toolbar at the bottom of the top controls. |
| * @return The extra Y offset for the toolbar in pixels. |
| */ |
| private int getToolbarExtraYOffset() { |
| return mBrowserControlsSizer.getTopControlsHeight() |
| - getControlContainerHeightWithoutShadow(); |
| } |
| |
| private int getControlContainerHeightWithoutShadow() { |
| final View toolbarShadow = mControlContainer.findViewById(R.id.toolbar_shadow); |
| final int shadowHeight = toolbarShadow != null ? toolbarShadow.getHeight() : 0; |
| return mControlContainer.getHeight() - shadowHeight; |
| } |
| |
| /** |
| * Sets the drawable that the close button shows, or hides it if {@code drawable} is |
| * {@code null}. |
| */ |
| public void setCloseButtonDrawable(Drawable drawable) { |
| mToolbar.setCloseButtonImageResource(drawable); |
| } |
| |
| /** |
| * Sets whether a title should be shown within the Toolbar. |
| * @param showTitle Whether a title should be shown. |
| */ |
| public void setShowTitle(boolean showTitle) { |
| mToolbar.setShowTitle(showTitle); |
| } |
| |
| /** |
| * @see TopToolbarCoordinator#setUrlBarHidden(boolean) |
| */ |
| public void setUrlBarHidden(boolean hidden) { |
| mToolbar.setUrlBarHidden(hidden); |
| } |
| |
| /** |
| * @see TopToolbarCoordinator#getContentPublisher() |
| */ |
| public String getContentPublisher() { |
| return mToolbar.getContentPublisher(); |
| } |
| |
| /** |
| * Focuses or unfocuses the URL bar. |
| * |
| * If you request focus and the UrlBar was already focused, this will select all of the text. |
| * |
| * @param focused Whether URL bar should be focused. |
| * @param reason The given reason. |
| */ |
| public void setUrlBarFocus(boolean focused, @OmniboxFocusReason int reason) { |
| if (!mInitializedWithNative) return; |
| if (mLocationBar.getFakeboxDelegate() == null) return; |
| boolean wasFocused = mLocationBar.getFakeboxDelegate().isUrlBarFocused(); |
| mLocationBar.getFakeboxDelegate().setUrlBarFocus(focused, null, reason); |
| if (wasFocused && focused) { |
| mLocationBar.selectAll(); |
| } |
| } |
| |
| /** |
| * See {@link #setUrlBarFocus}, but if native is not loaded it will queue the request instead |
| * of dropping it. |
| */ |
| public void setUrlBarFocusOnceNativeInitialized( |
| boolean focused, @OmniboxFocusReason int reason) { |
| if (mInitializedWithNative) { |
| setUrlBarFocus(focused, reason); |
| return; |
| } |
| |
| if (focused) { |
| // Remember requests to focus the Url bar and replay them once native has been |
| // initialized. This is important for the Launch to Incognito Tab flow (see |
| // IncognitoTabLauncher. |
| mOnInitializedRunnable = () -> { |
| setUrlBarFocus(focused, reason); |
| }; |
| } else { |
| mOnInitializedRunnable = null; |
| } |
| } |
| |
| /** |
| * Reverts any pending edits of the location bar and reset to the page state. This does not |
| * change the focus state of the location bar. |
| */ |
| public void revertLocationBarChanges() { |
| mLocationBar.revertChanges(); |
| } |
| |
| /** |
| * Handle all necessary tasks that can be delayed until initialization completes. |
| * @param activityCreationTimeMs The time of creation for the activity this toolbar belongs to. |
| * @param activityName Simple class name for the activity this toolbar belongs to. |
| */ |
| public void onDeferredStartup(final long activityCreationTimeMs, final String activityName) { |
| mLocationBar.onDeferredStartup(); |
| } |
| |
| /** |
| * Finish any toolbar animations. |
| */ |
| public void finishAnimations() { |
| if (mInitializedWithNative) mToolbar.finishAnimations(); |
| } |
| |
| /** |
| * @return The current {@link LoadProgressCoordinator}. |
| */ |
| public LoadProgressCoordinator getProgressBarCoordinator() { |
| return mProgressBarCoordinator; |
| } |
| |
| /** |
| * Updates the current button states and calls appropriate abstract visibility methods, giving |
| * inheriting classes the chance to update the button visuals as well. |
| */ |
| private void updateButtonStatus() { |
| Tab currentTab = mLocationBarModel.getTab(); |
| boolean tabCrashed = currentTab != null && SadTab.isShowing(currentTab); |
| |
| mToolbar.updateButtonVisibility(); |
| mToolbar.updateBackButtonVisibility(currentTab != null && currentTab.canGoBack()); |
| mToolbar.updateForwardButtonVisibility(currentTab != null && currentTab.canGoForward()); |
| updateReloadState(tabCrashed); |
| updateBookmarkButtonStatus(); |
| if (mToolbar.getMenuButtonWrapper() != null) { |
| mToolbar.getMenuButtonWrapper().setVisibility(View.VISIBLE); |
| } |
| } |
| |
| private void updateBookmarkButtonStatus() { |
| Tab currentTab = mLocationBarModel.getTab(); |
| BookmarkBridge bridge = mBookmarkBridgeSupplier.get(); |
| boolean isBookmarked = |
| currentTab != null && bridge != null && bridge.hasBookmarkIdForTab(currentTab); |
| boolean editingAllowed = |
| currentTab == null || bridge == null || bridge.isEditBookmarksEnabled(); |
| mToolbar.updateBookmarkButton(isBookmarked, editingAllowed); |
| } |
| |
| private void updateReloadState(boolean tabCrashed) { |
| Tab currentTab = mLocationBarModel.getTab(); |
| boolean isLoading = false; |
| if (!tabCrashed) { |
| isLoading = (currentTab != null && currentTab.isLoading()) || !mInitializedWithNative; |
| } |
| mToolbar.updateReloadButtonVisibility(isLoading); |
| mMenuButtonCoordinator.updateReloadingState(isLoading); |
| } |
| |
| /** |
| * Triggered when the selected tab has changed. |
| */ |
| private void refreshSelectedTab(Tab tab) { |
| boolean wasIncognito = mLocationBarModel.isIncognito(); |
| Tab previousTab = mLocationBarModel.getTab(); |
| |
| boolean isIncognito = |
| tab != null ? tab.isIncognito() : mTabModelSelector.isIncognitoSelected(); |
| mLocationBarModel.setTab(tab, isIncognito); |
| |
| updateCurrentTabDisplayStatus(); |
| |
| // This method is called prior to action mode destroy callback for incognito <-> normal |
| // tab switch. Makes sure the action mode toolbar is hidden before selecting the new tab. |
| if (previousTab != null && wasIncognito != isIncognito |
| && DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity)) { |
| mActionModeController.startHideAnimation(); |
| } |
| if (previousTab != tab || wasIncognito != isIncognito) { |
| int defaultPrimaryColor = |
| ChromeColors.getDefaultThemeColor(mActivity.getResources(), isIncognito); |
| int primaryColor = tab != null |
| ? mTopUiThemeColorProvider.calculateColor(tab, tab.getThemeColor()) |
| : defaultPrimaryColor; |
| // TODO(jinsukkim): Let TopUiThemeColorProvider handle this by updating the theme color. |
| onThemeColorChanged(primaryColor, false); |
| |
| onTabOrModelChanged(); |
| |
| if (tab != null) { |
| mToolbar.onNavigatedToDifferentPage(); |
| } |
| |
| // Ensure the URL bar loses focus if the tab it was interacting with is changed from |
| // underneath it. |
| setUrlBarFocus(false, OmniboxFocusReason.UNFOCUS); |
| |
| // Place the cursor in the Omnibox if applicable. We always clear the focus above to |
| // ensure the shield placed over the content is dismissed when switching tabs. But if |
| // needed, we will refocus the omnibox and make the cursor visible here. |
| if (shouldShowCursorInLocationBar()) { |
| mLocationBar.showUrlBarCursorWithoutFocusAnimations(); |
| } |
| } |
| |
| updateButtonStatus(); |
| } |
| |
| private void onTabOrModelChanged() { |
| mToolbar.onTabOrModelChanged(); |
| checkIfNtpLoaded(); |
| } |
| |
| private void checkIfNtpLoaded() { |
| NewTabPage ntp = getNewTabPageForCurrentTab(); |
| if (ntp != null) { |
| ntp.setFakeboxDelegate(mLocationBar.getFakeboxDelegate()); |
| mLocationBarModel.notifyNtpStartedLoading(); |
| } |
| } |
| |
| private void setBookmarkBridge(BookmarkBridge bookmarkBridge) { |
| if (bookmarkBridge == null) return; |
| bookmarkBridge.addObserver(mBookmarksObserver); |
| } |
| |
| private void setLayoutStateProvider(LayoutStateProvider layoutStateProvider) { |
| assert mLayoutStateProvider == null : "the mLayoutStateProvider should set at most once."; |
| |
| mLayoutStateProvider = layoutStateProvider; |
| mLayoutStateProvider.addObserver(mLayoutStateObserver); |
| mAppThemeColorProvider.setLayoutStateProvider(mLayoutStateProvider); |
| mLocationBarModel.setLayoutStateProvider(mLayoutStateProvider); |
| if (mBottomControlsCoordinatorSupplier.get() != null) { |
| mBottomControlsCoordinatorSupplier.get().setLayoutStateProvider(mLayoutStateProvider); |
| } |
| } |
| |
| private void updateCurrentTabDisplayStatus() { |
| mLocationBarModel.notifyUrlChanged(); |
| updateTabLoadingState(true); |
| } |
| |
| private void updateTabLoadingState(boolean updateUrl) { |
| mLocationBarModel.notifySecurityStateChanged(); |
| if (updateUrl) { |
| mLocationBarModel.notifyUrlChanged(); |
| updateButtonStatus(); |
| } |
| } |
| |
| /** |
| * @param enabled Whether the progress bar is enabled. |
| */ |
| public void setProgressBarEnabled(boolean enabled) { |
| mToolbar.setProgressBarEnabled(enabled); |
| } |
| |
| /** |
| * @return The {@link FakeboxDelegate}. |
| */ |
| @Nullable |
| public FakeboxDelegate getFakeboxDelegate() { |
| // TODO(crbug.com/1000295): Split fakebox component out of ntp package. |
| return mLocationBar.getFakeboxDelegate(); |
| } |
| |
| @Nullable |
| public VoiceRecognitionHandler getVoiceRecognitionHandler() { |
| return mLocationBar.getVoiceRecognitionHandler(); |
| } |
| |
| private boolean shouldShowCursorInLocationBar() { |
| Tab tab = mLocationBarModel.getTab(); |
| if (tab == null) return false; |
| NativePage nativePage = tab.getNativePage(); |
| if (!(nativePage instanceof NewTabPage) && !(nativePage instanceof IncognitoNewTabPage)) { |
| return false; |
| } |
| |
| return DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity) |
| && mActivity.getResources().getConfiguration().keyboard |
| == Configuration.KEYBOARD_QWERTY; |
| } |
| |
| /** |
| * Sets the top margin for the control container. |
| * @param margin The margin in pixels. |
| */ |
| private void setControlContainerTopMargin(int margin) { |
| final ViewGroup.MarginLayoutParams layoutParams = |
| ((ViewGroup.MarginLayoutParams) mControlContainer.getLayoutParams()); |
| if (layoutParams.topMargin == margin) { |
| return; |
| } |
| |
| layoutParams.topMargin = margin; |
| mControlContainer.setLayoutParams(layoutParams); |
| } |
| |
| /** Returns {@link LocationBar} for access in tests. */ |
| @VisibleForTesting |
| public LocationBar getLocationBarForTesting() { |
| return mLocationBar; |
| } |
| |
| /** Returns {@link LocationBarModel} for access in tests. */ |
| @VisibleForTesting |
| public LocationBarModel getLocationBarModelForTesting() { |
| return mLocationBarModel; |
| } |
| |
| /** |
| * @return The {@link ToolbarLayout} that constitutes the toolbar. |
| */ |
| @VisibleForTesting |
| public ToolbarLayout getToolbarLayoutForTesting() { |
| return mToolbar.getToolbarLayoutForTesting(); |
| } |
| |
| /** |
| * Get the home button on the top toolbar to verify the button status. |
| * Note that this home button is not always the home button that on the UI, and the button is |
| * not always visible. |
| * @return The {@link HomeButton} that lives in the top toolbar. |
| */ |
| @VisibleForTesting |
| public HomeButton getHomeButtonForTesting() { |
| return mToolbar.getToolbarLayoutForTesting().getHomeButton(); |
| } |
| |
| /** |
| * @return View for toolbar container. |
| */ |
| @VisibleForTesting |
| public View getContainerViewForTesting() { |
| return mControlContainer.getView(); |
| } |
| } |