Index: chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6874e55a869bd686a4eb2c55f33db1858c5a6fa6 |
--- /dev/null |
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java |
@@ -0,0 +1,747 @@ |
+// 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.compositor.layouts; |
+ |
+import android.content.Context; |
+import android.graphics.Bitmap; |
+import android.text.TextUtils; |
+import android.view.ViewGroup; |
+ |
+import com.google.android.apps.chrome.R; |
+ |
+import org.chromium.base.ObserverList; |
+import org.chromium.base.VisibleForTesting; |
+import org.chromium.chrome.browser.Tab; |
+import org.chromium.chrome.browser.compositor.TitleCache; |
+import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab; |
+import org.chromium.chrome.browser.compositor.layouts.components.VirtualView; |
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
+import org.chromium.chrome.browser.compositor.layouts.content.TitleBitmapFactory; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.BlackHoleEventFilter; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeEventFilter.ScrollDirection; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeHandler; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.GestureEventFilter; |
+import org.chromium.chrome.browser.compositor.overlays.SceneOverlay; |
+import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager; |
+import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate; |
+import org.chromium.chrome.browser.device.DeviceClassManager; |
+import org.chromium.chrome.browser.fullscreen.FullscreenManager; |
+import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; |
+import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver; |
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager; |
+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.TabModelSelector.CloseAllTabsDelegate; |
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver; |
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver; |
+import org.chromium.chrome.browser.tabmodel.TabModelUtils; |
+import org.chromium.chrome.browser.util.FeatureUtilities; |
+import org.chromium.chrome.browser.widget.OverviewListLayout; |
+import org.chromium.ui.base.LocalizationUtils; |
+import org.chromium.ui.resources.dynamics.DynamicResourceLoader; |
+ |
+import java.util.List; |
+ |
+/** |
+ * A {@link Layout} controller for the more complicated Chrome browser. This is currently a |
+ * superset of {@link LayoutManagerDocument}. |
+ */ |
+public class LayoutManagerChrome |
+ extends LayoutManagerDocument implements OverviewModeBehavior, CloseAllTabsDelegate { |
+ // Layouts |
+ /** An {@link Layout} that should be used as the accessibility tab switcher. */ |
+ protected OverviewListLayout mOverviewListLayout; |
+ /** A {@link Layout} that should be used when the user is swiping sideways on the toolbar. */ |
+ protected ToolbarSwipeLayout mToolbarSwipeLayout; |
+ /** A {@link Layout} that should be used when the user is in the tab switcher. */ |
+ protected Layout mOverviewLayout; |
+ |
+ // Event Filters |
+ /** A {@link EventFilter} that consumes all touch events. */ |
+ protected EventFilter mBlackHoleEventFilter; |
+ private final GestureEventFilter mGestureEventFilter; |
+ |
+ // Event Filter Handlers |
+ private final EdgeSwipeHandler mToolbarSwipeHandler; |
+ |
+ // Internal State |
+ /** A {@link TitleCache} instance that stores all title/favicon bitmaps as CC resources. */ |
+ protected TitleCache mTitleCache; |
+ /** Responsible for building non-incognito titles. */ |
+ protected TitleBitmapFactory mStandardTitleBitmapFactory; |
+ /** Responsible for building all incognito titles. */ |
+ protected TitleBitmapFactory mIncognitoTitleBitmapFactory; |
+ /** Whether or not animations are enabled. This can disable certain layouts or effects. */ |
+ protected boolean mEnableAnimations = true; |
+ private boolean mCreatingNtp; |
+ private final ObserverList<OverviewModeObserver> mOverviewModeObservers; |
+ private TabModelSelectorObserver mTabModelSelectorObserver; |
+ private TabModelObserver mTabModelObserver; |
+ private TabModelSelectorTabObserver mTabSelectorTabObserver; |
+ |
+ /** |
+ * Protected class to handle {@link TabModelObserver} related tasks. Extending classes will |
+ * need to override any related calls to add new functionality */ |
+ protected class LayoutManagerTabModelObserver extends EmptyTabModelObserver { |
+ @Override |
+ public void didSelectTab(Tab tab, TabSelectionType type, int lastId) { |
+ if (tab.getId() != lastId) tabSelected(tab.getId(), lastId, tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void willAddTab(Tab tab, TabLaunchType type) { |
+ // Open the new tab |
+ if (type == TabLaunchType.FROM_INSTANT || type == TabLaunchType.FROM_RESTORE) return; |
+ |
+ tabCreating(getTabModelSelector().getCurrentTabId(), tab.getUrl(), tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void didAddTab(Tab tab, TabLaunchType launchType) { |
+ int tabId = tab.getId(); |
+ if (launchType != TabLaunchType.FROM_INSTANT |
+ && launchType != TabLaunchType.FROM_RESTORE) { |
+ boolean incognito = tab.isIncognito(); |
+ boolean willBeSelected = launchType != TabLaunchType.FROM_LONGPRESS_BACKGROUND |
+ || (!getTabModelSelector().isIncognitoSelected() && incognito); |
+ float lastTapX = LocalizationUtils.isLayoutRtl() ? mLastContentWidthDp : 0.f; |
+ float lastTapY = 0.f; |
+ if (launchType != TabLaunchType.FROM_MENU_OR_OVERVIEW) { |
+ float heightDelta = |
+ mLastFullscreenViewportDp.height() - mLastVisibleViewportDp.height(); |
+ lastTapX = mPxToDp * mLastTapX; |
+ lastTapY = mPxToDp * mLastTapY - heightDelta; |
+ } |
+ |
+ tabCreated(tabId, getTabModelSelector().getCurrentTabId(), launchType, incognito, |
+ willBeSelected, lastTapX, lastTapY); |
+ } |
+ } |
+ |
+ @Override |
+ public void didCloseTab(Tab tab) { |
+ tabClosed(tab); |
+ } |
+ |
+ @Override |
+ public void tabPendingClosure(Tab tab) { |
+ tabClosed(tab); |
+ } |
+ |
+ @Override |
+ public void tabClosureUndone(Tab tab) { |
+ tabClosureCancelled(tab.getId(), tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void tabClosureCommitted(Tab tab) { |
+ LayoutManagerChrome.this.tabClosureCommitted(tab.getId(), tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void didMoveTab(Tab tab, int newIndex, int curIndex) { |
+ tabMoved(tab.getId(), curIndex, newIndex, tab.isIncognito()); |
+ } |
+ } |
+ |
+ /** |
+ * Delegate of a factory to create an overview layout. |
+ */ |
+ public interface OverviewLayoutFactoryDelegate { |
+ /** |
+ * @param context The current Android's context. |
+ * @param updateHost The {@link LayoutUpdateHost} view for this layout. |
+ * @param renderHost The {@link LayoutRenderHost} view for this layout. |
+ * @param eventFilter The {@link EventFilter} that is needed for this view. |
+ */ |
+ Layout createOverviewLayout(Context context, LayoutUpdateHost updateHost, |
+ LayoutRenderHost renderHost, EventFilter eventFilter); |
+ } |
+ |
+ /** |
+ * Creates the {@link LayoutManagerChrome} instance. |
+ * @param host A {@link LayoutManagerHost} instance. |
+ * @param overviewLayoutFactoryDelegate A {@link OverviewLayoutFactoryDelegate} instance. |
+ */ |
+ public LayoutManagerChrome( |
+ LayoutManagerHost host, OverviewLayoutFactoryDelegate overviewLayoutFactoryDelegate) { |
+ super(host); |
+ Context context = host.getContext(); |
+ LayoutRenderHost renderHost = host.getLayoutRenderHost(); |
+ |
+ // Set up state |
+ mStandardTitleBitmapFactory = |
+ new TitleBitmapFactory(context, false, R.drawable.default_favicon); |
+ mIncognitoTitleBitmapFactory = |
+ new TitleBitmapFactory(context, true, R.drawable.default_favicon_white); |
+ mOverviewModeObservers = new ObserverList<OverviewModeObserver>(); |
+ |
+ // Build Event Filter Handlers |
+ mToolbarSwipeHandler = new ToolbarSwipeHandler(this); |
+ |
+ // Build Event Filters |
+ mBlackHoleEventFilter = new BlackHoleEventFilter(context, this); |
+ mGestureEventFilter = new GestureEventFilter(context, this, mGestureHandler); |
+ |
+ // Build Layouts |
+ mOverviewListLayout = |
+ new OverviewListLayout(context, this, renderHost, mBlackHoleEventFilter); |
+ mToolbarSwipeLayout = |
+ new ToolbarSwipeLayout(context, this, renderHost, mBlackHoleEventFilter); |
+ if (overviewLayoutFactoryDelegate != null) { |
+ mOverviewLayout = overviewLayoutFactoryDelegate.createOverviewLayout( |
+ context, this, renderHost, mGestureEventFilter); |
+ } |
+ } |
+ |
+ /** |
+ * @return The {@link TabModelObserver} instance this class should be using. |
+ */ |
+ protected LayoutManagerTabModelObserver createTabModelObserver() { |
+ return new LayoutManagerTabModelObserver(); |
+ } |
+ |
+ /** |
+ * @return A list of virtual views representing compositor rendered views. |
+ */ |
+ @Override |
+ public void getVirtualViews(List<VirtualView> views) { |
+ if (getActiveLayout() != null) { |
+ getActiveLayout().getVirtualViews(views); |
+ } |
+ } |
+ |
+ /** |
+ * @return The {@link EdgeSwipeHandler} responsible for processing swipe events for the toolbar. |
+ */ |
+ @Override |
+ public EdgeSwipeHandler getTopSwipeHandler() { |
+ return mToolbarSwipeHandler; |
+ } |
+ |
+ @Override |
+ public void init(TabModelSelector selector, TabCreatorManager creator, |
+ TabContentManager content, ViewGroup androidContentContainer, |
+ ContextualSearchManagementDelegate contextualSearchDelegate, |
+ DynamicResourceLoader dynamicResourceLoader) { |
+ // TODO: TitleCache should be a part of the ResourceManager. |
+ mTitleCache = mHost.getTitleCache(); |
+ |
+ // Initialize Layouts |
+ mToolbarSwipeLayout.setTabModelSelector(selector, content); |
+ mOverviewListLayout.setTabModelSelector(selector, content); |
+ if (mOverviewLayout != null) mOverviewLayout.setTabModelSelector(selector, content); |
+ |
+ super.init(selector, creator, content, androidContentContainer, contextualSearchDelegate, |
+ dynamicResourceLoader); |
+ |
+ mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() { |
+ @Override |
+ public void onTabModelSelected(TabModel newModel, TabModel oldModel) { |
+ tabModelSwitched(newModel.isIncognito()); |
+ } |
+ }; |
+ selector.addObserver(mTabModelSelectorObserver); |
+ selector.setCloseAllTabsDelegate(this); |
+ |
+ mTabModelObserver = createTabModelObserver(); |
+ for (TabModel model : selector.getModels()) model.addObserver(mTabModelObserver); |
+ |
+ mTabSelectorTabObserver = new TabModelSelectorTabObserver(selector) { |
+ @Override |
+ public void onLoadStarted(Tab tab) { |
+ tabLoadStarted(tab.getId(), tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void onLoadStopped(Tab tab) { |
+ tabLoadFinished(tab.getId(), tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void onPageLoadStarted(Tab tab) { |
+ tabPageLoadStarted(tab.getId(), tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void onPageLoadFinished(Tab tab) { |
+ tabPageLoadFinished(tab.getId(), tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void onPageLoadFailed(Tab tab, int errorCode) { |
+ tabPageLoadFinished(tab.getId(), tab.isIncognito()); |
+ } |
+ |
+ @Override |
+ public void onCrash(Tab tab, boolean sadTabShown) { |
+ tabPageLoadFinished(tab.getId(), tab.isIncognito()); |
+ } |
+ }; |
+ } |
+ |
+ @Override |
+ public void destroy() { |
+ super.destroy(); |
+ if (mTabModelSelectorObserver != null) { |
+ getTabModelSelector().removeObserver(mTabModelSelectorObserver); |
+ } |
+ if (mTabModelObserver != null) { |
+ for (TabModel model : getTabModelSelector().getModels()) { |
+ model.removeObserver(mTabModelObserver); |
+ } |
+ } |
+ if (mTabSelectorTabObserver != null) mTabSelectorTabObserver.destroy(); |
+ mOverviewModeObservers.clear(); |
+ |
+ if (mOverviewLayout != null) { |
+ mOverviewLayout.destroy(); |
+ mOverviewLayout = null; |
+ } |
+ mOverviewListLayout.destroy(); |
+ mToolbarSwipeLayout.destroy(); |
+ } |
+ |
+ @Override |
+ protected void addGlobalSceneOverlay(SceneOverlay helper) { |
+ super.addGlobalSceneOverlay(helper); |
+ mOverviewListLayout.addSceneOverlay(helper); |
+ mToolbarSwipeLayout.addSceneOverlay(helper); |
+ if (mOverviewLayout != null) mOverviewLayout.addSceneOverlay(helper); |
+ } |
+ |
+ /** |
+ * Meant to be overridden by child classes for when they need to extend the toolbar side swipe |
+ * functionality. |
+ * @param provider A {@link LayoutProvider} instance. |
+ * @return A {@link ToolbarSwipeHandler} instance that will be used by internal layouts. |
+ */ |
+ protected ToolbarSwipeHandler createToolbarSwipeHandler(LayoutProvider provider) { |
+ return new ToolbarSwipeHandler(provider); |
+ } |
+ |
+ /** |
+ * Simulates a click on the view at the specified pixel offset |
+ * from the top left of the view. |
+ * This is used by UI tests. |
+ * @param x Coordinate of the click in dp. |
+ * @param y Coordinate of the click in dp. |
+ */ |
+ @VisibleForTesting |
+ public void simulateClick(float x, float y) { |
+ if (getActiveLayout() != null) getActiveLayout().click(time(), x, y); |
+ } |
+ |
+ /** |
+ * Simulates a drag and issues Up-event to commit the drag. |
+ * @param x Coordinate to start the Drag from in dp. |
+ * @param y Coordinate to start the Drag from in dp. |
+ * @param dX Amount of drag in X direction in dp. |
+ * @param dY Amount of drag in Y direction in dp. |
+ */ |
+ @VisibleForTesting |
+ public void simulateDrag(float x, float y, float dX, float dY) { |
+ if (getActiveLayout() != null) { |
+ getActiveLayout().onDown(0, x, y); |
+ getActiveLayout().drag(0, x, y, dX, dY); |
+ getActiveLayout().onUpOrCancel(time()); |
+ } |
+ } |
+ |
+ private boolean isOverviewLayout(Layout layout) { |
+ return layout != null && (layout == mOverviewLayout || layout == mOverviewListLayout); |
+ } |
+ |
+ @Override |
+ protected void startShowing(Layout layout, boolean animate) { |
+ mCreatingNtp = false; |
+ super.startShowing(layout, animate); |
+ |
+ Layout layoutBeingShown = getActiveLayout(); |
+ |
+ // Check if a layout is showing that should hide the contextual search bar. |
+ if (mContextualSearchDelegate != null |
+ && (isOverviewLayout(layoutBeingShown) |
+ || layoutBeingShown == mToolbarSwipeLayout)) { |
+ mContextualSearchDelegate.dismissContextualSearchBar(); |
+ } |
+ |
+ // Check if we should notify OverviewModeObservers. |
+ if (isOverviewLayout(layoutBeingShown)) { |
+ boolean showToolbar = |
+ !mEnableAnimations || getTabModelSelector().getCurrentModel().getCount() <= 0; |
+ for (OverviewModeObserver observer : mOverviewModeObservers) { |
+ observer.onOverviewModeStartedShowing(showToolbar); |
+ } |
+ } |
+ } |
+ |
+ @Override |
+ public void startHiding(int nextTabId, boolean hintAtTabSelection) { |
+ super.startHiding(nextTabId, hintAtTabSelection); |
+ |
+ Layout layoutBeingHidden = getActiveLayout(); |
+ if (isOverviewLayout(layoutBeingHidden)) { |
+ boolean showToolbar = true; |
+ if (mEnableAnimations && layoutBeingHidden == mOverviewLayout) { |
+ final LayoutTab tab = layoutBeingHidden.getLayoutTab(nextTabId); |
+ showToolbar = tab != null ? !tab.showToolbar() : true; |
+ } |
+ |
+ boolean creatingNtp = layoutBeingHidden == mOverviewLayout && mCreatingNtp; |
+ |
+ for (OverviewModeObserver observer : mOverviewModeObservers) { |
+ observer.onOverviewModeStartedHiding(showToolbar, creatingNtp); |
+ } |
+ } |
+ } |
+ |
+ @Override |
+ public void doneShowing() { |
+ super.doneShowing(); |
+ |
+ if (isOverviewLayout(getActiveLayout())) { |
+ for (OverviewModeObserver observer : mOverviewModeObservers) { |
+ observer.onOverviewModeFinishedShowing(); |
+ } |
+ } |
+ } |
+ |
+ @Override |
+ public void doneHiding() { |
+ Layout layoutBeingHidden = getActiveLayout(); |
+ |
+ if (getNextLayout() == getDefaultLayout()) { |
+ Tab tab = getTabModelSelector() != null ? getTabModelSelector().getCurrentTab() : null; |
+ emptyCachesExcept(tab != null ? tab.getId() : Tab.INVALID_TAB_ID); |
+ } |
+ |
+ super.doneHiding(); |
+ |
+ if (isOverviewLayout(layoutBeingHidden)) { |
+ for (OverviewModeObserver observer : mOverviewModeObservers) { |
+ observer.onOverviewModeFinishedHiding(); |
+ } |
+ } |
+ } |
+ |
+ @VisibleForTesting |
+ public void tabSelected(int tabId, int prevId, boolean incognito) { |
+ // Update the model here so we properly set the right selected TabModel. |
+ if (getActiveLayout() != null) { |
+ getActiveLayout().onTabSelected(time(), tabId, prevId, incognito); |
+ } |
+ } |
+ |
+ /** |
+ * Should be called when a tab created event is triggered. |
+ * @param id The id of the tab that was created. |
+ * @param sourceId The id of the creating tab if any. |
+ * @param launchType How the tab was launched. |
+ * @param incognito Whether or not the created tab is incognito. |
+ * @param willBeSelected Whether or not the created tab will be selected. |
+ * @param originX The x coordinate of the action that created this tab in dp. |
+ * @param originY The y coordinate of the action that created this tab in dp. |
+ */ |
+ protected void tabCreated(int id, int sourceId, TabLaunchType launchType, boolean incognito, |
+ boolean willBeSelected, float originX, float originY) { |
+ Tab newTab = TabModelUtils.getTabById(getTabModelSelector().getModel(incognito), id); |
+ mCreatingNtp = newTab != null && newTab.isNativePage(); |
+ |
+ int newIndex = TabModelUtils.getTabIndexById(getTabModelSelector().getModel(incognito), id); |
+ getActiveLayout().onTabCreated( |
+ time(), id, newIndex, sourceId, incognito, !willBeSelected, originX, originY); |
+ } |
+ |
+ /** |
+ * Should be called when a tab creating event is triggered (called before the tab is done being |
+ * created). |
+ * @param sourceId The id of the creating tab if any. |
+ * @param url The url of the created tab. |
+ * @param isIncognito Whether or not created tab will be incognito. |
+ */ |
+ protected void tabCreating(int sourceId, String url, boolean isIncognito) { |
+ if (getActiveLayout() != null) getActiveLayout().onTabCreating(sourceId); |
+ } |
+ |
+ /** |
+ * Should be called when a tab closed event is triggered. |
+ * @param id The id of the closed tab. |
+ * @param nextId The id of the next tab that will be visible, if any. |
+ * @param incognito Whether or not the closed tab is incognito. |
+ */ |
+ protected void tabClosed(int id, int nextId, boolean incognito) { |
+ if (getActiveLayout() != null) getActiveLayout().onTabClosed(time(), id, nextId, incognito); |
+ } |
+ |
+ private void tabClosed(Tab tab) { |
+ Tab currentTab = |
+ getTabModelSelector() != null ? getTabModelSelector().getCurrentTab() : null; |
+ int nextTabId = currentTab != null ? currentTab.getId() : Tab.INVALID_TAB_ID; |
+ tabClosed(tab.getId(), nextTabId, tab.isIncognito()); |
+ } |
+ |
+ /** |
+ * Called when a tab closure has been committed and all tab cleanup should happen. |
+ * @param id The id of the closed tab. |
+ * @param incognito Whether or not the closed tab is incognito. |
+ */ |
+ protected void tabClosureCommitted(int id, boolean incognito) { |
+ if (getActiveLayout() != null) { |
+ getActiveLayout().onTabClosureCommitted(time(), id, incognito); |
+ } |
+ } |
+ |
+ @Override |
+ public boolean closeAllTabsRequest(boolean incognito) { |
+ if (!isOverviewLayout(getActiveLayout()) || !getActiveLayout().handlesCloseAll()) { |
+ return false; |
+ } |
+ getActiveLayout().onTabsAllClosing(time(), incognito); |
+ return true; |
+ } |
+ |
+ /** |
+ * Called when the selected tab model has switched. |
+ * @param incognito Whether or not the new current tab model is incognito. |
+ */ |
+ protected void tabModelSwitched(boolean incognito) { |
+ if (getActiveLayout() != null) getActiveLayout().onTabModelSwitched(incognito); |
+ } |
+ |
+ private void tabMoved(int id, int oldIndex, int newIndex, boolean incognito) { |
+ if (getActiveLayout() != null) { |
+ getActiveLayout().onTabMoved(time(), id, oldIndex, newIndex, incognito); |
+ } |
+ } |
+ |
+ private void tabPageLoadStarted(int id, boolean incognito) { |
+ if (getActiveLayout() != null) getActiveLayout().onTabPageLoadStarted(id, incognito); |
+ } |
+ |
+ private void tabPageLoadFinished(int id, boolean incognito) { |
+ if (getActiveLayout() != null) getActiveLayout().onTabPageLoadFinished(id, incognito); |
+ } |
+ |
+ private void tabLoadStarted(int id, boolean incognito) { |
+ if (getActiveLayout() != null) getActiveLayout().onTabLoadStarted(id, incognito); |
+ } |
+ |
+ private void tabLoadFinished(int id, boolean incognito) { |
+ if (getActiveLayout() != null) getActiveLayout().onTabLoadFinished(id, incognito); |
+ } |
+ |
+ private void tabClosureCancelled(int id, boolean incognito) { |
+ if (getActiveLayout() != null) { |
+ getActiveLayout().onTabClosureCancelled(time(), id, incognito); |
+ } |
+ } |
+ |
+ @Override |
+ public void initLayoutTabFromHost(int tabId) { |
+ super.initLayoutTabFromHost(tabId); |
+ |
+ if (getTabModelSelector() == null || getActiveLayout() == null) return; |
+ |
+ TabModelSelector selector = getTabModelSelector(); |
+ Tab tab = selector.getTabById(tabId); |
+ if (tab == null) return; |
+ |
+ LayoutTab layoutTab = getExistingLayoutTab(tabId); |
+ if (layoutTab == null) return; |
+ |
+ if (mTitleCache != null && layoutTab.isTitleNeeded()) { |
+ mTitleCache.put(tabId, getTitleBitmap(tab), getFaviconBitmap(tab), tab.isIncognito(), |
+ tab.isTitleDirectionRtl()); |
+ } |
+ } |
+ |
+ /** |
+ * Builds a title bitmap for a {@link Tab}. This function does not do anything in the |
+ * general case because only the phone need to bake special resource. |
+ * |
+ * @param tab The tab to build the title bitmap for. |
+ * @return The Title bitmap |
+ */ |
+ protected Bitmap getTitleBitmap(Tab tab) { |
+ TitleBitmapFactory titleBitmapFactory = |
+ tab.isIncognito() ? mIncognitoTitleBitmapFactory : mStandardTitleBitmapFactory; |
+ |
+ return titleBitmapFactory.getTitleBitmap(mHost.getContext(), getTitleForTab(tab)); |
+ } |
+ |
+ /** |
+ * Comes up with a valid title to return for a tab. |
+ * @param tab The {@link Tab} to build a title for. |
+ * @return The title to use. |
+ */ |
+ protected String getTitleForTab(Tab tab) { |
+ String title = tab.getTitle(); |
+ if (TextUtils.isEmpty(title)) title = tab.getUrl(); |
+ return title; |
+ } |
+ |
+ /** |
+ * Builds a favicon bitmap for a {@link Tab}. This function does not do anything in the |
+ * general case because only the phone need to bake special texture. |
+ * |
+ * @param tab The tab to build the title bitmap for. |
+ * @return The Favicon bitmap |
+ */ |
+ protected Bitmap getFaviconBitmap(Tab tab) { |
+ TitleBitmapFactory titleBitmapFactory = |
+ tab.isIncognito() ? mIncognitoTitleBitmapFactory : mStandardTitleBitmapFactory; |
+ return titleBitmapFactory.getFaviconBitmap(mHost.getContext(), tab.getFavicon()); |
+ } |
+ |
+ /** |
+ * @return The {@link OverviewListLayout} managed by this class. |
+ */ |
+ @VisibleForTesting |
+ public Layout getOverviewListLayout() { |
+ return mOverviewListLayout; |
+ } |
+ |
+ /** |
+ * @return The overview layout {@link Layout} managed by this class. |
+ */ |
+ @VisibleForTesting |
+ public Layout getOverviewLayout() { |
+ return mOverviewLayout; |
+ } |
+ |
+ /** |
+ * @return The {@link StripLayoutHelperManager} managed by this class. |
+ */ |
+ @VisibleForTesting |
+ public StripLayoutHelperManager getStripLayoutHelperManager() { |
+ return null; |
+ } |
+ |
+ /** |
+ * @return Whether or not to use the accessibility layout. |
+ */ |
+ protected boolean useAccessibilityLayout() { |
+ return DeviceClassManager.isAccessibilityModeEnabled(mHost.getContext()) |
+ || DeviceClassManager.enableAccessibilityLayout(); |
+ } |
+ |
+ /** |
+ * Show the overview {@link Layout}. This is generally a {@link Layout} that visibly represents |
+ * all of the {@link Tab}s opened by the user. |
+ * @param animate Whether or not to animate the transition to overview mode. |
+ */ |
+ public void showOverview(boolean animate) { |
+ boolean useAccessibility = useAccessibilityLayout(); |
+ |
+ boolean accessibilityIsVisible = |
+ useAccessibility && getActiveLayout() == mOverviewListLayout; |
+ boolean normalIsVisible = getActiveLayout() == mOverviewLayout && mOverviewLayout != null; |
+ |
+ // We only want to use the AccessibilityOverviewLayout if the following are all valid: |
+ // 1. We're already showing the AccessibilityOverviewLayout OR we're using accessibility. |
+ // 2. We're not already showing the normal OverviewLayout (or we are on a tablet, in which |
+ // case the normal layout is always visible). |
+ if ((accessibilityIsVisible || useAccessibility) && !normalIsVisible) { |
+ startShowing(mOverviewListLayout, animate); |
+ } else if (mOverviewLayout != null) { |
+ startShowing(mOverviewLayout, animate); |
+ } |
+ } |
+ |
+ /** |
+ * Hides the current {@link Layout}, returning to the default {@link Layout}. |
+ * @param animate Whether or not to animate the transition to the default {@link Layout}. |
+ */ |
+ public void hideOverview(boolean animate) { |
+ Layout activeLayout = getActiveLayout(); |
+ if (activeLayout != null && !activeLayout.isHiding()) { |
+ if (animate) { |
+ activeLayout.onTabSelecting(time(), Tab.INVALID_TAB_ID); |
+ } else { |
+ startHiding(Tab.INVALID_TAB_ID, false); |
+ doneHiding(); |
+ } |
+ } |
+ } |
+ |
+ /** |
+ * @param enabled Whether or not to allow model-reactive animations (tab creation, closing, |
+ * etc.). |
+ */ |
+ public void setEnableAnimations(boolean enabled) { |
+ mEnableAnimations = enabled; |
+ } |
+ |
+ @Override |
+ public boolean overviewVisible() { |
+ Layout activeLayout = getActiveLayout(); |
+ return isOverviewLayout(activeLayout) && !activeLayout.isHiding(); |
+ } |
+ |
+ @Override |
+ public void addOverviewModeObserver(OverviewModeObserver listener) { |
+ mOverviewModeObservers.addObserver(listener); |
+ } |
+ |
+ @Override |
+ public void removeOverviewModeObserver(OverviewModeObserver listener) { |
+ mOverviewModeObservers.removeObserver(listener); |
+ } |
+ |
+ /** |
+ * A {@link EdgeSwipeHandler} meant to respond to edge events for the toolbar. |
+ */ |
+ protected class ToolbarSwipeHandler extends EdgeSwipeHandlerLayoutDelegate { |
+ /** |
+ * Creates an instance of the {@link ToolbarSwipeHandler}. |
+ * @param provider A {@link LayoutProvider} instance. |
+ */ |
+ public ToolbarSwipeHandler(LayoutProvider provider) { |
+ super(provider); |
+ } |
+ |
+ @Override |
+ public void swipeStarted(ScrollDirection direction, float x, float y) { |
+ if (direction == ScrollDirection.DOWN) { |
+ startShowing(mOverviewLayout, true); |
+ super.swipeStarted(direction, x, y); |
+ } else if (direction == ScrollDirection.LEFT || direction == ScrollDirection.RIGHT) { |
+ startShowing(mToolbarSwipeLayout, true); |
+ super.swipeStarted(direction, x, y); |
+ } |
+ } |
+ |
+ @Override |
+ public boolean isSwipeEnabled(ScrollDirection direction) { |
+ FullscreenManager manager = mHost.getFullscreenManager(); |
+ if (getActiveLayout() != mStaticLayout |
+ || !DeviceClassManager.enableToolbarSwipe( |
+ FeatureUtilities.isDocumentMode(mHost.getContext())) |
+ || (manager != null && manager.getPersistentFullscreenMode())) { |
+ return false; |
+ } |
+ |
+ boolean isAccessibility = |
+ DeviceClassManager.isAccessibilityModeEnabled(mHost.getContext()); |
+ return direction == ScrollDirection.LEFT || direction == ScrollDirection.RIGHT |
+ || (direction == ScrollDirection.DOWN && mOverviewLayout != null |
+ && !isAccessibility); |
+ } |
+ } |
+ |
+ /** |
+ * @param id The id of the {@link Tab} to search for. |
+ * @return A {@link Tab} instance or {@code null} if it could be found. |
+ */ |
+ protected Tab getTabById(int id) { |
+ TabModelSelector selector = getTabModelSelector(); |
+ return selector == null ? null : selector.getTabById(id); |
+ } |
+} |