Index: chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java |
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e19647598e58e8a8fbf866c3cd6f38e74b6a14dd |
--- /dev/null |
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java |
@@ -0,0 +1,336 @@ |
+// 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.Rect; |
+import android.os.Handler; |
+ |
+import com.google.android.apps.chrome.R; |
+ |
+import org.chromium.chrome.browser.Tab; |
+import org.chromium.chrome.browser.compositor.LayerTitleCache; |
+import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel; |
+import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab; |
+import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
+import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter; |
+import org.chromium.chrome.browser.compositor.scene_layer.ReaderModeSceneLayer; |
+import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer; |
+import org.chromium.chrome.browser.compositor.scene_layer.StaticTabSceneLayer; |
+import org.chromium.chrome.browser.dom_distiller.ReaderModePanel; |
+import org.chromium.chrome.browser.dom_distiller.ReaderModePanel.ReaderModePanelLayoutDelegate; |
+import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; |
+import org.chromium.chrome.browser.tab.ChromeTab; |
+import org.chromium.chrome.browser.tabmodel.TabModel; |
+import org.chromium.chrome.browser.tabmodel.TabModelBase; |
+import org.chromium.ui.resources.ResourceManager; |
+ |
+import java.util.Arrays; |
+import java.util.LinkedList; |
+ |
+/** |
+ * A {@link Layout} that shows a single tab at full screen. This tab is chosen based on the |
+ * {@link #tabSelecting(long, int)} call, and is used to show a thumbnail of a {@link ChromeTab} |
+ * until that {@link ChromeTab} is ready to be shown. |
+ */ |
+public class StaticLayout extends ContextualSearchSupportedLayout { |
+ public static final String TAG = "StaticLayout"; |
+ |
+ private static final int HIDE_TIMEOUT_MS = 2000; |
+ private static final int HIDE_DURATION_MS = 500; |
+ |
+ private boolean mHandlesTabLifecycles; |
+ |
+ private class UnstallRunnable implements Runnable { |
+ @Override |
+ public void run() { |
+ mUnstalling = false; |
+ if (mLayoutTabs == null || mLayoutTabs.length == 0) return; |
+ addToAnimation(mLayoutTabs[0], LayoutTab.Property.SATURATION, |
+ mLayoutTabs[0].getSaturation(), 1.0f, HIDE_DURATION_MS, 0); |
+ addToAnimation(mLayoutTabs[0], LayoutTab.Property.STATIC_TO_VIEW_BLEND, |
+ mLayoutTabs[0].getStaticToViewBlend(), 0.0f, HIDE_DURATION_MS, 0); |
+ mLayoutTabs[0].setShouldStall(false); |
+ } |
+ } |
+ |
+ private final UnstallRunnable mUnstallRunnable; |
+ private final Handler mHandler; |
+ private boolean mUnstalling; |
+ private StaticTabSceneLayer mSceneLayer; |
+ |
+ // TODO(aruslan): look into moving this to an overlay/it's own layout. |
+ private ReaderModeSceneLayer mReaderModeSceneLayer; |
+ private ReaderModePanel mReaderModePanel; |
+ |
+ /** |
+ * Creates an instance of the {@link StaticLayout}. |
+ * @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. |
+ */ |
+ public StaticLayout(Context context, LayoutUpdateHost updateHost, LayoutRenderHost renderHost, |
+ EventFilter eventFilter, ContextualSearchPanel panel) { |
+ super(context, updateHost, renderHost, eventFilter, panel); |
+ |
+ mHandler = new Handler(); |
+ mUnstallRunnable = new UnstallRunnable(); |
+ mUnstalling = false; |
+ mSceneLayer = new StaticTabSceneLayer(R.id.control_container); |
+ |
+ float dpToPx = context.getResources().getDisplayMetrics().density; |
+ mReaderModeSceneLayer = new ReaderModeSceneLayer(dpToPx); |
+ } |
+ |
+ /** |
+ * @param handlesTabLifecycles Whether or not this {@link Layout} should handle tab closing and |
+ * creating events. |
+ */ |
+ public void setLayoutHandlesTabLifecycles(boolean handlesTabLifecycles) { |
+ mHandlesTabLifecycles = handlesTabLifecycles; |
+ } |
+ |
+ @Override |
+ public int getSizingFlags() { |
+ return SizingFlags.HELPER_SUPPORTS_FULLSCREEN; |
+ } |
+ |
+ @Override |
+ public float getTopControlsOffset(float currentOffsetDp) { |
+ if (mReaderModePanel == null) return super.getTopControlsOffset(currentOffsetDp); |
+ return mReaderModePanel.getTopControlsOffset(currentOffsetDp); |
+ } |
+ |
+ /** |
+ * Initialize the layout to be shown. |
+ * @param time The current time of the app in ms. |
+ * @param animate Whether to play an entry animation. |
+ */ |
+ @Override |
+ public void show(long time, boolean animate) { |
+ super.show(time, animate); |
+ |
+ mLayoutTabs = null; |
+ setStaticTab(mTabModelSelector.getCurrentTabId()); |
+ } |
+ |
+ @Override |
+ protected void updateLayout(long time, long dt) { |
+ super.updateLayout(time, dt); |
+ if (mLayoutTabs != null && mLayoutTabs.length > 0) mLayoutTabs[0].updateSnap(dt); |
+ } |
+ |
+ @Override |
+ public void onTabSelected(long time, int id, int prevId, boolean incognito) { |
+ setStaticTab(id); |
+ super.onTabSelected(time, id, prevId, incognito); |
+ } |
+ |
+ @Override |
+ public void onTabSelecting(long time, int id) { |
+ setStaticTab(id); |
+ super.onTabSelecting(time, id); |
+ } |
+ |
+ @Override |
+ public void onTabCreated(long time, int tabId, int tabIndex, int sourceTabId, |
+ boolean newIsIncognito, boolean background, float originX, float originY) { |
+ super.onTabCreated( |
+ time, tabId, tabIndex, sourceTabId, newIsIncognito, background, originX, originY); |
+ if (!background) setStaticTab(tabId); |
+ } |
+ |
+ @Override |
+ public void onTabModelSwitched(boolean incognito) { |
+ super.onTabModelSwitched(incognito); |
+ setStaticTab(mTabModelSelector.getCurrentTabId()); |
+ } |
+ |
+ @Override |
+ public void onTabPageLoadFinished(int id, boolean incognito) { |
+ super.onTabPageLoadFinished(id, incognito); |
+ unstallImmediately(id); |
+ } |
+ |
+ private void setPreHideState() { |
+ mHandler.removeCallbacks(mUnstallRunnable); |
+ mLayoutTabs[0].setStaticToViewBlend(1.0f); |
+ mLayoutTabs[0].setSaturation(0.0f); |
+ mUnstalling = true; |
+ } |
+ |
+ private void setPostHideState() { |
+ mHandler.removeCallbacks(mUnstallRunnable); |
+ mLayoutTabs[0].setStaticToViewBlend(0.0f); |
+ mLayoutTabs[0].setSaturation(1.0f); |
+ mUnstalling = false; |
+ } |
+ |
+ private void setStaticTab(final int id) { |
+ if (mLayoutTabs != null && mLayoutTabs.length > 0 && mLayoutTabs[0].getId() == id) { |
+ if (!mLayoutTabs[0].shouldStall()) setPostHideState(); |
+ return; |
+ } |
+ TabModel model = mTabModelSelector.getModelForTabId(id); |
+ if (model == null) return; |
+ updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(id))); |
+ if (mLayoutTabs == null || mLayoutTabs.length != 1) mLayoutTabs = new LayoutTab[1]; |
+ mLayoutTabs[0] = createLayoutTab(id, model.isIncognito(), NO_CLOSE_BUTTON, NO_TITLE); |
+ mLayoutTabs[0].setDrawDecoration(false); |
+ if (mLayoutTabs[0].shouldStall()) { |
+ setPreHideState(); |
+ mHandler.postDelayed(mUnstallRunnable, HIDE_TIMEOUT_MS); |
+ } else { |
+ setPostHideState(); |
+ } |
+ mReaderModePanel = ReaderModePanel.getReaderModePanel(mTabModelSelector.getTabById(id)); |
+ if (mReaderModePanel != null) { |
+ mReaderModePanel.setLayoutDelegate(new ReaderModePanelLayoutDelegate() { |
+ @Override |
+ public void requestUpdate() { |
+ StaticLayout.this.requestUpdate(); |
+ } |
+ |
+ @Override |
+ public void setLayoutTabBrightness(float v) { |
+ if (mLayoutTabs != null && mLayoutTabs.length > 0 |
+ && mLayoutTabs[0].getId() == id) { |
+ mLayoutTabs[0].setBrightness(v); |
+ } |
+ } |
+ |
+ @Override |
+ public void setLayoutTabY(float v) { |
+ if (mLayoutTabs != null && mLayoutTabs.length > 0 |
+ && mLayoutTabs[0].getId() == id) { |
+ mLayoutTabs[0].setY(v); |
+ } |
+ } |
+ }); |
+ final boolean isToolbarVisible = getHeight() == getHeightMinusTopControls(); |
+ final float dpToPx = getContext().getResources().getDisplayMetrics().density; |
+ mReaderModePanel.onSizeChanged(getWidth(), getHeight(), isToolbarVisible, dpToPx); |
+ } |
+ requestRender(); |
+ } |
+ |
+ /** |
+ * @return Currently active reader mode panel, or null. |
+ */ |
+ public ReaderModePanel getReaderModePanel() { |
+ return mReaderModePanel; |
+ } |
+ |
+ @Override |
+ public void unstallImmediately(int tabId) { |
+ if (mLayoutTabs != null && mLayoutTabs.length > 0 && mLayoutTabs[0].getId() == tabId) { |
+ unstallImmediately(); |
+ } |
+ } |
+ |
+ @Override |
+ public void unstallImmediately() { |
+ if (mLayoutTabs != null && mLayoutTabs.length > 0 && mLayoutTabs[0].shouldStall() |
+ && mUnstalling) { |
+ mHandler.removeCallbacks(mUnstallRunnable); |
+ mUnstallRunnable.run(); |
+ } |
+ } |
+ |
+ @Override |
+ public boolean handlesTabCreating() { |
+ return mHandlesTabLifecycles; |
+ } |
+ |
+ @Override |
+ public boolean handlesTabClosing() { |
+ return mHandlesTabLifecycles; |
+ } |
+ |
+ @Override |
+ public boolean handlesCloseAll() { |
+ return mHandlesTabLifecycles; |
+ } |
+ |
+ @Override |
+ public boolean shouldDisplayContentOverlay() { |
+ return true; |
+ } |
+ |
+ @Override |
+ public boolean isTabInteractive() { |
+ return mLayoutTabs != null && mLayoutTabs.length > 0; |
+ } |
+ |
+ @Override |
+ protected SceneLayer getSceneLayer() { |
+ return mSceneLayer; |
+ } |
+ |
+ @Override |
+ protected void notifySizeChanged(float width, float height, int orientation) { |
+ super.notifySizeChanged(width, height, orientation); |
+ if (mReaderModePanel == null) return; |
+ |
+ final boolean isToolbarVisible = getHeight() == getHeightMinusTopControls(); |
+ final float dpToPx = getContext().getResources().getDisplayMetrics().density; |
+ mReaderModePanel.onSizeChanged(width, height, isToolbarVisible, dpToPx); |
+ } |
+ |
+ @Override |
+ protected boolean onUpdateAnimation(long time, boolean jumpToEnd) { |
+ boolean parentAnimating = super.onUpdateAnimation(time, jumpToEnd); |
+ boolean panelAnimating = mReaderModePanel != null |
+ ? mReaderModePanel.onUpdateAnimation(time, jumpToEnd) |
+ : false; |
+ return panelAnimating || parentAnimating; |
+ } |
+ |
+ @Override |
+ protected void updateSceneLayer(Rect viewport, Rect contentViewport, |
+ LayerTitleCache layerTitleCache, TabContentManager tabContentManager, |
+ ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) { |
+ super.updateSceneLayer(viewport, contentViewport, layerTitleCache, tabContentManager, |
+ resourceManager, fullscreenManager); |
+ assert mSceneLayer != null; |
+ |
+ final LayoutTab[] tabs = getLayoutTabsToRender(); |
+ if (tabs == null || tabs.length != 1 || tabs[0].getId() == Tab.INVALID_TAB_ID) { |
+ return; |
+ } |
+ LayoutTab layoutTab = tabs[0]; |
+ final float dpToPx = getContext().getResources().getDisplayMetrics().density; |
+ |
+ mReaderModeSceneLayer.update(mReaderModePanel, resourceManager); |
+ |
+ mSceneLayer.update(dpToPx, contentViewport, layerTitleCache, tabContentManager, |
+ fullscreenManager, layoutTab); |
+ |
+ // TODO(pedrosimonetti): Coordinate w/ dtrainor@ to improve integration with TreeProvider. |
+ SceneLayer overlayLayer = null; |
+ if (mSearchPanel.isShowing()) { |
+ overlayLayer = super.getSceneLayer(); |
+ } else if (mReaderModePanel != null && mReaderModePanel.isShowing()) { |
+ overlayLayer = mReaderModeSceneLayer; |
+ } |
+ mSceneLayer.setContentSceneLayer(overlayLayer); |
+ |
+ // TODO(dtrainor): Find the best way to properly track this metric for cold starts. |
+ // We should probably erase the thumbnail when we select a tab that we need to restore. |
+ if (tabContentManager != null |
+ && tabContentManager.hasFullCachedThumbnail(layoutTab.getId())) { |
+ TabModelBase.logPerceivedTabSwitchLatencyMetric(); |
+ } |
+ } |
+ |
+ @Override |
+ public void destroy() { |
+ if (mSceneLayer != null) { |
+ mSceneLayer.destroy(); |
+ mSceneLayer = null; |
+ } |
+ } |
+} |