Index: chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..28f9b9fcd34ad3e792a0d8360fc870174620ef12 |
--- /dev/null |
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java |
@@ -0,0 +1,861 @@ |
+// 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.Context; |
+import android.os.Handler; |
+import android.os.Looper; |
+import android.os.Message; |
+import android.text.TextUtils; |
+import android.view.View; |
+import android.view.View.OnAttachStateChangeListener; |
+ |
+import com.google.android.apps.chrome.R; |
+ |
+import org.chromium.base.metrics.RecordUserAction; |
+import org.chromium.chrome.browser.BookmarksBridge; |
+import org.chromium.chrome.browser.ChromeBrowserProviderClient; |
+import org.chromium.chrome.browser.CustomSelectionActionModeCallback; |
+import org.chromium.chrome.browser.EmptyTabObserver; |
+import org.chromium.chrome.browser.Tab; |
+import org.chromium.chrome.browser.TabLoadStatus; |
+import org.chromium.chrome.browser.TabObserver; |
+import org.chromium.chrome.browser.UrlConstants; |
+import org.chromium.chrome.browser.appmenu.AppMenuButtonHelper; |
+import org.chromium.chrome.browser.appmenu.AppMenuHandler; |
+import org.chromium.chrome.browser.appmenu.AppMenuObserver; |
+import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver; |
+import org.chromium.chrome.browser.compositor.layouts.Layout; |
+import org.chromium.chrome.browser.compositor.layouts.LayoutManager; |
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior; |
+import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver; |
+import org.chromium.chrome.browser.compositor.layouts.SceneChangeObserver; |
+import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; |
+import org.chromium.chrome.browser.fullscreen.FullscreenManager; |
+import org.chromium.chrome.browser.ntp.NativePageFactory; |
+import org.chromium.chrome.browser.ntp.NewTabPage; |
+import org.chromium.chrome.browser.omnibox.LocationBar; |
+import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener; |
+import org.chromium.chrome.browser.partnercustomizations.HomepageManager; |
+import org.chromium.chrome.browser.partnercustomizations.HomepageManager.HomepageStateListener; |
+import org.chromium.chrome.browser.profiles.Profile; |
+import org.chromium.chrome.browser.search_engines.TemplateUrlService; |
+import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrl; |
+import org.chromium.chrome.browser.search_engines.TemplateUrlService.TemplateUrlServiceObserver; |
+import org.chromium.chrome.browser.tab.ChromeTab; |
+import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; |
+import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; |
+import org.chromium.chrome.browser.tabmodel.TabModel; |
+import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType; |
+import org.chromium.chrome.browser.tabmodel.TabModel.TabSelectionType; |
+import org.chromium.chrome.browser.tabmodel.TabModelObserver; |
+import org.chromium.chrome.browser.tabmodel.TabModelSelector; |
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; |
+import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager; |
+import org.chromium.chrome.browser.widget.findinpage.FindToolbarObserver; |
+import org.chromium.content_public.browser.LoadUrlParams; |
+import org.chromium.content_public.browser.NavigationController; |
+import org.chromium.content_public.browser.WebContents; |
+import org.chromium.ui.base.PageTransition; |
+ |
+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. |
+ */ |
+class ToolbarManager implements ToolbarTabController, UrlFocusChangeListener { |
+ |
+ /** |
+ * Handle UI updates of menu icons. Only applicable for phones. |
+ */ |
+ public interface MenuDelegatePhone { |
+ |
+ /** |
+ * Called when current tab's loading status changes. |
+ * |
+ * @param isLoading Whether the current tab is loading. |
+ */ |
+ public void updateReloadButtonState(boolean isLoading); |
+ } |
+ |
+ /** |
+ * The minimum load progress that can be shown when a page is loading. This is not 0 so that |
+ * it's obvious to the user that something is attempting to load. |
+ */ |
+ public static final int MINIMUM_LOAD_PROGRESS = 5; |
+ |
+ private final ToolbarLayout mToolbar; |
+ private final ToolbarControlContainer mControlContainer; |
+ |
+ private TabModelSelector mTabModelSelector; |
+ private TabModelSelectorObserver mTabModelSelectorObserver; |
+ private TabModelObserver mTabModelObserver; |
+ private MenuDelegatePhone mMenuDelegatePhone; |
+ private final ToolbarModelImpl mToolbarModel; |
+ private Profile mCurrentProfile; |
+ private BookmarksBridge mBookmarksBridge; |
+ private TemplateUrlServiceObserver mTemplateUrlObserver; |
+ private final LocationBar mLocationBar; |
+ private FindToolbarManager mFindToolbarManager; |
+ |
+ private final TabObserver mTabObserver; |
+ private final BookmarksBridge.BookmarkModelObserver mBookmarksObserver; |
+ private final FindToolbarObserver mFindToolbarObserver; |
+ private final OverviewModeObserver mOverviewModeObserver; |
+ private final SceneChangeObserver mSceneChangeObserver; |
+ |
+ private final LoadProgressSimulator mLoadProgressSimulator; |
+ |
+ private ChromeFullscreenManager mFullscreenManager; |
+ private int mFullscreenFocusToken = FullscreenManager.INVALID_TOKEN; |
+ private int mFullscreenFindInPageToken = FullscreenManager.INVALID_TOKEN; |
+ private int mFullscreenMenuToken = FullscreenManager.INVALID_TOKEN; |
+ |
+ private int mPreselectedTabId = Tab.INVALID_TAB_ID; |
+ |
+ private boolean mNativeLibraryReady; |
+ private boolean mTabRestoreCompleted; |
+ |
+ private AppMenuButtonHelper mAppMenuButtonHelper; |
+ |
+ private HomepageStateListener mHomepageStateListener; |
+ |
+ /** |
+ * Creates a ToolbarManager object. |
+ * @param controlContainer The container of the toolbar. |
+ * @param menuHandler The handler for interacting with the menu. |
+ */ |
+ ToolbarManager(ToolbarControlContainer controlContainer, AppMenuHandler menuHandler) { |
+ mToolbarModel = new ToolbarModelImpl(); |
+ mControlContainer = controlContainer; |
+ assert mControlContainer != null; |
+ |
+ mToolbar = (ToolbarLayout) controlContainer.findViewById(R.id.toolbar); |
+ mLocationBar = mToolbar.getLocationBar(); |
+ mLocationBar.setToolbarDataProvider(mToolbarModel); |
+ mLocationBar.setUrlFocusChangeListener(this); |
+ |
+ setMenuHandler(menuHandler); |
+ mToolbar.initialize(mToolbarModel, this, mAppMenuButtonHelper); |
+ |
+ mHomepageStateListener = new HomepageStateListener() { |
+ @Override |
+ public void onHomepageStateUpdated() { |
+ mToolbar.onHomeButtonUpdate( |
+ HomepageManager.isHomepageEnabled(mToolbar.getContext())); |
+ } |
+ }; |
+ HomepageManager.getInstance(mToolbar.getContext()).addListener(mHomepageStateListener); |
+ |
+ mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() { |
+ @Override |
+ public void onTabModelSelected(TabModel newModel, TabModel oldModel) { |
+ refreshSelectedTab(); |
+ updateTabCount(); |
+ mControlContainer.invalidateBitmap(); |
+ } |
+ |
+ @Override |
+ public void onTabStateInitialized() { |
+ mTabRestoreCompleted = true; |
+ handleTabRestoreCompleted(); |
+ } |
+ }; |
+ |
+ mTabModelObserver = new EmptyTabModelObserver() { |
+ @Override |
+ public void didAddTab(Tab tab, TabLaunchType type) { |
+ updateTabCount(); |
+ } |
+ |
+ @Override |
+ public void didSelectTab(Tab tab, TabSelectionType type, int lastId) { |
+ mPreselectedTabId = Tab.INVALID_TAB_ID; |
+ refreshSelectedTab(); |
+ } |
+ |
+ @Override |
+ public void tabClosureUndone(Tab tab) { |
+ updateTabCount(); |
+ refreshSelectedTab(); |
+ } |
+ |
+ @Override |
+ public void didCloseTab(Tab tab) { |
+ updateTabCount(); |
+ refreshSelectedTab(); |
+ } |
+ |
+ @Override |
+ public void tabPendingClosure(Tab tab) { |
+ updateTabCount(); |
+ refreshSelectedTab(); |
+ } |
+ |
+ @Override |
+ public void allTabsPendingClosure(List<Integer> tabIds) { |
+ updateTabCount(); |
+ refreshSelectedTab(); |
+ } |
+ }; |
+ |
+ mTabObserver = new EmptyTabObserver() { |
+ @Override |
+ public void onSSLStateUpdated(Tab tab) { |
+ super.onSSLStateUpdated(tab); |
+ assert tab == mToolbarModel.getTab(); |
+ mLocationBar.updateSecurityIcon(tab.getSecurityLevel()); |
+ } |
+ |
+ @Override |
+ public void onWebContentsInstantSupportDisabled() { |
+ mLocationBar.setUrlToPageUrl(); |
+ } |
+ |
+ @Override |
+ public void onDidNavigateMainFrame(Tab tab, String url, String baseUrl, |
+ boolean isNavigationToDifferentPage, boolean isFragmentNavigation, |
+ int statusCode) { |
+ if (isNavigationToDifferentPage) { |
+ mToolbar.onNavigatedToDifferentPage(); |
+ } |
+ } |
+ |
+ @Override |
+ public void onPageLoadStarted(Tab tab) { |
+ updateButtonStatus(); |
+ updateTabLoadingState(true, true); |
+ } |
+ |
+ @Override |
+ public void onPageLoadFinished(Tab tab) { |
+ ToolbarManager.this.onPageLoadFinished(); |
+ } |
+ |
+ @Override |
+ public void onPageLoadFailed(Tab tab, int errorCode) { |
+ ToolbarManager.this.onPageLoadFailed(); |
+ } |
+ |
+ @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(false, 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 onCrash(Tab tab, boolean sadTabShown) { |
+ onTabCrash(); |
+ } |
+ |
+ @Override |
+ public void onLoadProgressChanged(Tab tab, int progress) { |
+ updateLoadProgress(progress); |
+ } |
+ |
+ @Override |
+ public void onContentChanged(Tab tab) { |
+ mToolbar.onTabContentViewChanged(); |
+ } |
+ |
+ @Override |
+ public void onWebContentsSwapped(Tab tab, boolean didStartLoad, boolean didFinishLoad) { |
+ if (!didStartLoad) return; |
+ |
+ ChromeTab chromeTab = ChromeTab.fromTab(tab); |
+ if (!chromeTab.getBackgroundContentViewHelper().isPageSwappingInProgress() |
+ && didFinishLoad) { |
+ mLoadProgressSimulator.start(); |
+ } |
+ } |
+ |
+ @Override |
+ public void onDidStartNavigationToPendingEntry(Tab tab, String url) { |
+ // 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. |
+ WebContents webContents = tab.getWebContents(); |
+ if (webContents == null) return; |
+ NavigationController navigationController = webContents.getNavigationController(); |
+ if (navigationController == null) return; |
+ if (navigationController.isInitialNavigation()) { |
+ mLocationBar.setUrlToPageUrl(); |
+ } |
+ } |
+ |
+ @Override |
+ public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) { |
+ NewTabPage ntp = mToolbarModel.getNewTabPageForCurrentTab(); |
+ if (ntp == null) return; |
+ if (!NewTabPage.isNTPUrl(params.getUrl()) |
+ && loadType != TabLoadStatus.PAGE_LOAD_FAILED) { |
+ ntp.setUrlFocusAnimationsDisabled(true); |
+ mToolbar.onTabOrModelChanged(); |
+ } |
+ } |
+ |
+ @Override |
+ public void onDidFailLoad(Tab tab, boolean isProvisionalLoad, boolean isMainFrame, |
+ int errorCode, String description, String failingUrl) { |
+ NewTabPage ntp = mToolbarModel.getNewTabPageForCurrentTab(); |
+ if (ntp == null) return; |
+ if (isProvisionalLoad && isMainFrame) { |
+ ntp.setUrlFocusAnimationsDisabled(false); |
+ mToolbar.onTabOrModelChanged(); |
+ } |
+ } |
+ }; |
+ |
+ mBookmarksObserver = new BookmarksBridge.BookmarkModelObserver() { |
+ @Override |
+ public void bookmarkModelChanged() { |
+ updateBookmarkButtonStatus(); |
+ } |
+ }; |
+ |
+ mFindToolbarObserver = new FindToolbarObserver() { |
+ @Override |
+ public void onFindToolbarShown() { |
+ mToolbar.handleFindToolbarStateChange(true); |
+ if (mFullscreenManager != null) { |
+ mFullscreenFindInPageToken = |
+ mFullscreenManager.showControlsPersistentAndClearOldToken( |
+ mFullscreenFindInPageToken); |
+ } |
+ } |
+ |
+ @Override |
+ public void onFindToolbarHidden() { |
+ mToolbar.handleFindToolbarStateChange(false); |
+ if (mFullscreenManager != null) { |
+ mFullscreenManager.hideControlsPersistent(mFullscreenFindInPageToken); |
+ mFullscreenFindInPageToken = FullscreenManager.INVALID_TOKEN; |
+ } |
+ } |
+ }; |
+ |
+ mOverviewModeObserver = new EmptyOverviewModeObserver() { |
+ @Override |
+ public void onOverviewModeStartedShowing(boolean showToolbar) { |
+ mToolbar.setTabSwitcherMode(true, showToolbar, false); |
+ updateButtonStatus(); |
+ } |
+ |
+ @Override |
+ public void onOverviewModeStartedHiding(boolean showToolbar, boolean delayAnimation) { |
+ mToolbar.setTabSwitcherMode(false, showToolbar, delayAnimation); |
+ updateButtonStatus(); |
+ } |
+ |
+ @Override |
+ public void onOverviewModeFinishedHiding() { |
+ mToolbar.onTabSwitcherTransitionFinished(); |
+ } |
+ }; |
+ |
+ mSceneChangeObserver = new SceneChangeObserver() { |
+ @Override |
+ public void onTabSelectionHinted(int tabId) { |
+ mPreselectedTabId = tabId; |
+ refreshSelectedTab(); |
+ } |
+ |
+ @Override |
+ public void onSceneChange(Layout layout) { |
+ mToolbar.setContentAttached(layout.shouldDisplayContentOverlay()); |
+ } |
+ }; |
+ |
+ mLoadProgressSimulator = new LoadProgressSimulator(this); |
+ } |
+ |
+ /** |
+ * Initialize the manager with the components that had native initialization dependencies. |
+ * <p> |
+ * Calling this must occur after the native library have completely loaded. |
+ * |
+ * @param tabModelSelector The selector that handles tab management. |
+ * @param fullscreenManager The manager in charge of interacting with the fullscreen feature. |
+ * @param findToolbarManager The manager for find in page. |
+ * @param overviewModeBehavior The overview mode manager. |
+ * @param layoutDriver A {@link LayoutManager} instance used to watch for scene changes. |
+ */ |
+ public void initializeWithNative(TabModelSelector tabModelSelector, |
+ ChromeFullscreenManager fullscreenManager, |
+ final FindToolbarManager findToolbarManager, |
+ final OverviewModeBehavior overviewModeBehavior, |
+ final LayoutManager layoutDriver) { |
+ mTabModelSelector = tabModelSelector; |
+ mToolbarModel.initializeWithNative(); |
+ mToolbar.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { |
+ @Override |
+ public void onViewDetachedFromWindow(View v) { |
+ Context context = mToolbar.getContext(); |
+ HomepageManager.getInstance(context).removeListener(mHomepageStateListener); |
+ mTabModelSelector.removeObserver(mTabModelSelectorObserver); |
+ for (TabModel model : mTabModelSelector.getModels()) { |
+ model.removeObserver(mTabModelObserver); |
+ } |
+ if (mBookmarksBridge != null) { |
+ mBookmarksBridge.destroy(); |
+ mBookmarksBridge = null; |
+ } |
+ if (mTemplateUrlObserver != null) { |
+ TemplateUrlService.getInstance().removeObserver(mTemplateUrlObserver); |
+ mTemplateUrlObserver = null; |
+ } |
+ |
+ findToolbarManager.removeObserver(mFindToolbarObserver); |
+ if (overviewModeBehavior != null) { |
+ overviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver); |
+ } |
+ if (layoutDriver != null) { |
+ layoutDriver.removeSceneChangeObserver(mSceneChangeObserver); |
+ } |
+ } |
+ |
+ @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(); |
+ } |
+ }); |
+ |
+ mFindToolbarManager = findToolbarManager; |
+ |
+ assert fullscreenManager != null; |
+ mFullscreenManager = fullscreenManager; |
+ |
+ mNativeLibraryReady = false; |
+ |
+ findToolbarManager.addObserver(mFindToolbarObserver); |
+ if (overviewModeBehavior != null) { |
+ overviewModeBehavior.addOverviewModeObserver(mOverviewModeObserver); |
+ } |
+ if (layoutDriver != null) layoutDriver.addSceneChangeObserver(mSceneChangeObserver); |
+ |
+ onNativeLibraryReady(); |
+ } |
+ |
+ /** |
+ * @return The toolbar interface that this manager handles. |
+ */ |
+ public Toolbar getToolbar() { |
+ return mToolbar; |
+ } |
+ |
+ /** |
+ * Called when the accessibility enabled state changes. |
+ * @param enabled Whether accessibility is enabled. |
+ */ |
+ public void onAccessibilityStatusChanged(boolean enabled) { |
+ mToolbar.onAccessibilityStatusChanged(enabled); |
+ } |
+ |
+ private void registerTemplateUrlObserver() { |
+ final TemplateUrlService templateUrlService = TemplateUrlService.getInstance(); |
+ 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 onNativeLibraryReady() { |
+ mNativeLibraryReady = true; |
+ mToolbar.onNativeLibraryReady(); |
+ |
+ final TemplateUrlService templateUrlService = TemplateUrlService.getInstance(); |
+ TemplateUrlService.LoadListener mTemplateServiceLoadListener = |
+ new TemplateUrlService.LoadListener() { |
+ @Override |
+ public void onTemplateUrlServiceLoaded() { |
+ registerTemplateUrlObserver(); |
+ templateUrlService.unregisterLoadListener(this); |
+ } |
+ }; |
+ templateUrlService.registerLoadListener(mTemplateServiceLoadListener); |
+ if (templateUrlService.isLoaded()) { |
+ mTemplateServiceLoadListener.onTemplateUrlServiceLoaded(); |
+ } else { |
+ templateUrlService.load(); |
+ } |
+ |
+ mTabModelSelector.addObserver(mTabModelSelectorObserver); |
+ for (TabModel model : mTabModelSelector.getModels()) model.addObserver(mTabModelObserver); |
+ |
+ refreshSelectedTab(); |
+ if (mTabModelSelector.isTabStateInitialized()) mTabRestoreCompleted = true; |
+ handleTabRestoreCompleted(); |
+ } |
+ |
+ private void handleTabRestoreCompleted() { |
+ if (!mTabRestoreCompleted || !mNativeLibraryReady) return; |
+ mToolbar.onStateRestored(); |
+ updateTabCount(); |
+ } |
+ |
+ /** |
+ * Sets the handler for any special case handling related with the menu button. |
+ * @param menuHandler The handler to be used. |
+ */ |
+ private void setMenuHandler(AppMenuHandler menuHandler) { |
+ menuHandler.addObserver(new AppMenuObserver() { |
+ @Override |
+ public void onMenuVisibilityChanged(boolean isVisible) { |
+ if (mFullscreenManager == null) return; |
+ if (isVisible) { |
+ mFullscreenMenuToken = |
+ mFullscreenManager.showControlsPersistentAndClearOldToken( |
+ mFullscreenMenuToken); |
+ } else { |
+ mFullscreenManager.hideControlsPersistent(mFullscreenMenuToken); |
+ mFullscreenMenuToken = FullscreenManager.INVALID_TOKEN; |
+ } |
+ } |
+ }); |
+ mAppMenuButtonHelper = new AppMenuButtonHelper(menuHandler); |
+ mAppMenuButtonHelper.setOnAppMenuShownListener(new Runnable() { |
+ @Override |
+ public void run() { |
+ RecordUserAction.record("MobileToolbarShowMenu"); |
+ } |
+ }); |
+ mLocationBar.setMenuButtonHelper(mAppMenuButtonHelper); |
+ } |
+ |
+ /** |
+ * Set the delegate that will handle updates from toolbar driven state changes. |
+ * @param menuDelegatePhone The menu delegate to be updated (only applicable to phones). |
+ */ |
+ public void setMenuDelegatePhone(MenuDelegatePhone menuDelegatePhone) { |
+ mMenuDelegatePhone = menuDelegatePhone; |
+ } |
+ |
+ /** |
+ * Sets a custom ActionMode.Callback instance to the LocationBar's UrlBar. This lets us |
+ * get notified when the user tries to do copy, paste, etc. on the UrlBar. |
+ * @param callback The ActionMode.Callback instance to be notified when selection ActionMode |
+ * is triggered. |
+ */ |
+ public void setDefaultActionModeCallbackForTextEdit( |
+ CustomSelectionActionModeCallback callback) { |
+ mLocationBar.setDefaultTextEditActionModeCallback(callback); |
+ } |
+ |
+ @Override |
+ public boolean back() { |
+ Tab tab = mToolbarModel.getTab(); |
+ if (tab != null && tab.canGoBack()) { |
+ tab.goBack(); |
+ updateButtonStatus(); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ @Override |
+ public boolean forward() { |
+ Tab tab = mToolbarModel.getTab(); |
+ if (tab != null && tab.canGoForward()) { |
+ tab.goForward(); |
+ updateButtonStatus(); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ @Override |
+ public void stopOrReloadCurrentTab() { |
+ Tab currentTab = mToolbarModel.getTab(); |
+ if (currentTab != null) { |
+ if (currentTab.isLoading()) { |
+ currentTab.stopLoading(); |
+ } else { |
+ currentTab.reload(); |
+ RecordUserAction.record("MobileToolbarReload"); |
+ } |
+ } |
+ updateButtonStatus(); |
+ } |
+ |
+ @Override |
+ public void openHomepage() { |
+ Tab currentTab = mToolbarModel.getTab(); |
+ assert currentTab != null; |
+ Context context = mToolbar.getContext(); |
+ String homePageUrl = HomepageManager.getHomepageUri(context); |
+ if (TextUtils.isEmpty(homePageUrl)) { |
+ homePageUrl = UrlConstants.NTP_URL; |
+ } |
+ currentTab.loadUrl(new LoadUrlParams(homePageUrl, PageTransition.HOME_PAGE)); |
+ } |
+ |
+ /** |
+ * 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 (mFullscreenManager == null) return; |
+ if (hasFocus) { |
+ mFullscreenFocusToken = mFullscreenManager.showControlsPersistentAndClearOldToken( |
+ mFullscreenFocusToken); |
+ } else { |
+ mFullscreenManager.hideControlsPersistent(mFullscreenFocusToken); |
+ mFullscreenFocusToken = FullscreenManager.INVALID_TOKEN; |
+ } |
+ } |
+ |
+ /** |
+ * Update the primary color used by the model to the given color. |
+ * @param color The primary color for the current tab. |
+ */ |
+ public void updatePrimaryColor(int color) { |
+ boolean colorChanged = mToolbarModel.getPrimaryColor() != color; |
+ if (!colorChanged) return; |
+ |
+ mToolbarModel.setPrimaryColor(color); |
+ mToolbar.onPrimaryColorChanged(); |
+ } |
+ |
+ /** |
+ * Updates the current number of Tabs based on the TabModel this Toolbar contains. |
+ */ |
+ private void updateTabCount() { |
+ if (!mTabRestoreCompleted) return; |
+ mToolbar.updateTabCountVisuals(mTabModelSelector.getCurrentModel().getCount()); |
+ } |
+ |
+ /** |
+ * 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 = mToolbarModel.getTab(); |
+ boolean tabCrashed = currentTab != null && currentTab.isShowingSadTab(); |
+ |
+ mToolbar.updateBackButtonVisibility(currentTab != null && currentTab.canGoBack()); |
+ mToolbar.updateForwardButtonVisibility(currentTab != null && currentTab.canGoForward()); |
+ updateReloadState(tabCrashed); |
+ updateBookmarkButtonStatus(); |
+ |
+ mToolbar.getMenuButton().setVisibility( |
+ mToolbar.shouldShowMenuButton() ? View.VISIBLE : View.GONE); |
+ } |
+ |
+ private void updateBookmarkButtonStatus() { |
+ Tab currentTab = mToolbarModel.getTab(); |
+ boolean isBookmarked = currentTab != null |
+ && currentTab.getBookmarkId() != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID; |
+ mToolbar.updateBookmarkButtonVisibility(isBookmarked); |
+ } |
+ |
+ private void updateReloadState(boolean tabCrashed) { |
+ Tab currentTab = mToolbarModel.getTab(); |
+ boolean isLoading = false; |
+ if (!tabCrashed) { |
+ isLoading = (currentTab != null && currentTab.isLoading()) || !mNativeLibraryReady; |
+ } |
+ mToolbar.updateReloadButtonVisibility(isLoading); |
+ if (mMenuDelegatePhone != null) mMenuDelegatePhone.updateReloadButtonState(isLoading); |
+ } |
+ |
+ /** |
+ * Triggered when the selected tab has changed. |
+ */ |
+ private void refreshSelectedTab() { |
+ ChromeTab tab = null; |
+ if (mPreselectedTabId != Tab.INVALID_TAB_ID) { |
+ tab = ChromeTab.fromTab(mTabModelSelector.getTabById(mPreselectedTabId)); |
+ } |
+ if (tab == null) tab = ChromeTab.fromTab(mTabModelSelector.getCurrentTab()); |
+ |
+ boolean wasIncognito = mToolbarModel.isIncognito(); |
+ ChromeTab previousTab = ChromeTab.fromTab(mToolbarModel.getTab()); |
+ |
+ boolean isIncognito = |
+ tab != null ? tab.isIncognito() : mTabModelSelector.isIncognitoSelected(); |
+ mToolbarModel.setTab(tab, isIncognito); |
+ |
+ updateCurrentTabDisplayStatus(); |
+ if (previousTab != tab || wasIncognito != isIncognito) { |
+ if (previousTab != tab) { |
+ if (previousTab != null) previousTab.removeObserver(mTabObserver); |
+ if (tab != null) tab.addObserver(mTabObserver); |
+ } |
+ int defaultPrimaryColor = isIncognito |
+ ? mToolbar.getResources().getColor(R.color.incognito_primary_color) |
+ : mToolbar.getResources().getColor(R.color.default_primary_color); |
+ int primaryColor = (tab != null && tab.getWebContents() != null) |
+ ? tab.getWebContents().getThemeColor(defaultPrimaryColor) : defaultPrimaryColor; |
+ updatePrimaryColor(primaryColor); |
+ |
+ mToolbar.onTabOrModelChanged(); |
+ |
+ if (tab != null && tab.getWebContents() != null |
+ && tab.getWebContents().isLoadingToDifferentDocument()) { |
+ mToolbar.onNavigatedToDifferentPage(); |
+ } |
+ } |
+ |
+ Profile profile = mTabModelSelector.getModel(isIncognito).getProfile(); |
+ if (mCurrentProfile != profile) { |
+ if (mBookmarksBridge != null) mBookmarksBridge.destroy(); |
+ mBookmarksBridge = new BookmarksBridge(profile); |
+ mBookmarksBridge.addObserver(mBookmarksObserver); |
+ mLocationBar.setAutocompleteProfile(profile); |
+ mCurrentProfile = profile; |
+ } |
+ } |
+ |
+ private void updateCurrentTabDisplayStatus() { |
+ Tab currentTab = mToolbarModel.getTab(); |
+ mLocationBar.setUrlToPageUrl(); |
+ if (currentTab == null) { |
+ updateLoadProgressInternal(0); |
+ updateButtonStatus(); |
+ return; |
+ } |
+ boolean isLoading = currentTab.isLoading(); |
+ updateTabLoadingState(isLoading, true); |
+ |
+ if (currentTab.getProgress() == 100 || currentTab.isShowingInterstitialPage()) { |
+ // We are switching to a tab that is fully loaded. Don't set the load progress to 1.0, |
+ // that would cause the load progress bar to show briefly. |
+ updateLoadProgressInternal(0); |
+ } else { |
+ updateLoadProgress(currentTab.getProgress()); |
+ } |
+ updateButtonStatus(); |
+ } |
+ |
+ private void onTabCrash() { |
+ updateTabLoadingState(false, false); |
+ updateLoadProgressInternal(0); |
+ updateButtonStatus(); |
+ } |
+ |
+ private void onPageLoadFinished() { |
+ Tab currentTab = mToolbarModel.getTab(); |
+ updateTabLoadingState(false, true); |
+ int currentProgress = currentTab.getProgress(); |
+ if (currentProgress != 100) { |
+ // If we made some progress, fast-forward to complete, otherwise just dismiss any |
+ // MINIMUM_LOAD_PROGRESS that had been set. |
+ if (currentProgress > MINIMUM_LOAD_PROGRESS) { |
+ updateLoadProgress(100); |
+ } else { |
+ updateLoadProgressInternal(0); |
+ } |
+ } |
+ updateButtonStatus(); |
+ } |
+ |
+ private void onPageLoadFailed() { |
+ updateTabLoadingState(false, true); |
+ updateButtonStatus(); |
+ updateLoadProgressInternal(0); |
+ } |
+ |
+ private void updateTabLoadingState(boolean isLoading, boolean updateUrl) { |
+ Tab currentTab = mToolbarModel.getTab(); |
+ mLocationBar.updateLoadingState(updateUrl); |
+ if (isLoading) updateLoadProgress(currentTab.getProgress()); |
+ if (updateUrl) updateButtonStatus(); |
+ } |
+ |
+ private void updateLoadProgressInternal(int progress) { |
+ if (progress == mToolbarModel.getLoadProgress()) return; |
+ mToolbarModel.setLoadProgress(progress); |
+ mToolbar.setLoadProgress(progress); |
+ if (progress == 0) mLoadProgressSimulator.cancel(); |
+ } |
+ |
+ private void updateLoadProgress(int progress) { |
+ mLoadProgressSimulator.cancel(); |
+ progress = Math.max(progress, MINIMUM_LOAD_PROGRESS); |
+ Tab tab = mToolbarModel.getTab(); |
+ if (tab != null |
+ && NativePageFactory.isNativePageUrl(tab.getUrl(), tab.isIncognito())) { |
+ progress = 0; |
+ } |
+ updateLoadProgressInternal(progress); |
+ if (progress == 100 || progress == 0) { |
+ updateButtonStatus(); |
+ } else { |
+ // Update the reload state regardless or whether or not the progress is 100. |
+ updateReloadState(false); |
+ } |
+ } |
+ |
+ private static class LoadProgressSimulator { |
+ private static final int MSG_ID_UPDATE_PROGRESS = 1; |
+ |
+ private static final int PROGRESS_INCREMENT = 10; |
+ private static final int PROGRESS_INCREMENT_DELAY_MS = 10; |
+ |
+ private final ToolbarManager mToolbar; |
+ private final Handler mHandler; |
+ |
+ private int mProgress; |
+ |
+ public LoadProgressSimulator(ToolbarManager toolbar) { |
+ mToolbar = toolbar; |
+ mHandler = new Handler(Looper.getMainLooper()) { |
+ @Override |
+ public void handleMessage(Message msg) { |
+ assert msg.what == MSG_ID_UPDATE_PROGRESS; |
+ mProgress = Math.min(100, mProgress += PROGRESS_INCREMENT); |
+ mToolbar.updateLoadProgressInternal(mProgress); |
+ |
+ if (mProgress >= 100) return; |
+ sendEmptyMessageDelayed(MSG_ID_UPDATE_PROGRESS, PROGRESS_INCREMENT_DELAY_MS); |
+ } |
+ }; |
+ } |
+ |
+ /** |
+ * Start simulating load progress from a baseline of 0. |
+ */ |
+ public void start() { |
+ mProgress = 0; |
+ mHandler.sendEmptyMessage(MSG_ID_UPDATE_PROGRESS); |
+ } |
+ |
+ /** |
+ * Cancels simulating load progress. |
+ */ |
+ public void cancel() { |
+ mHandler.removeMessages(MSG_ID_UPDATE_PROGRESS); |
+ } |
+ } |
+} |