OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 package org.chromium.chrome.browser.compositor.layouts; |
| 6 |
| 7 import android.content.Context; |
| 8 import android.graphics.Rect; |
| 9 import android.os.Handler; |
| 10 |
| 11 import com.google.android.apps.chrome.R; |
| 12 |
| 13 import org.chromium.chrome.browser.Tab; |
| 14 import org.chromium.chrome.browser.compositor.LayerTitleCache; |
| 15 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.Context
ualSearchPanel; |
| 16 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab; |
| 17 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; |
| 18 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter; |
| 19 import org.chromium.chrome.browser.compositor.scene_layer.ReaderModeSceneLayer; |
| 20 import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer; |
| 21 import org.chromium.chrome.browser.compositor.scene_layer.StaticTabSceneLayer; |
| 22 import org.chromium.chrome.browser.dom_distiller.ReaderModePanel; |
| 23 import org.chromium.chrome.browser.dom_distiller.ReaderModePanel.ReaderModePanel
LayoutDelegate; |
| 24 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; |
| 25 import org.chromium.chrome.browser.tab.ChromeTab; |
| 26 import org.chromium.chrome.browser.tabmodel.TabModel; |
| 27 import org.chromium.chrome.browser.tabmodel.TabModelBase; |
| 28 import org.chromium.ui.resources.ResourceManager; |
| 29 |
| 30 import java.util.Arrays; |
| 31 import java.util.LinkedList; |
| 32 |
| 33 /** |
| 34 * A {@link Layout} that shows a single tab at full screen. This tab is chosen b
ased on the |
| 35 * {@link #tabSelecting(long, int)} call, and is used to show a thumbnail of a {
@link ChromeTab} |
| 36 * until that {@link ChromeTab} is ready to be shown. |
| 37 */ |
| 38 public class StaticLayout extends ContextualSearchSupportedLayout { |
| 39 public static final String TAG = "StaticLayout"; |
| 40 |
| 41 private static final int HIDE_TIMEOUT_MS = 2000; |
| 42 private static final int HIDE_DURATION_MS = 500; |
| 43 |
| 44 private boolean mHandlesTabLifecycles; |
| 45 |
| 46 private class UnstallRunnable implements Runnable { |
| 47 @Override |
| 48 public void run() { |
| 49 mUnstalling = false; |
| 50 if (mLayoutTabs == null || mLayoutTabs.length == 0) return; |
| 51 addToAnimation(mLayoutTabs[0], LayoutTab.Property.SATURATION, |
| 52 mLayoutTabs[0].getSaturation(), 1.0f, HIDE_DURATION_MS, 0); |
| 53 addToAnimation(mLayoutTabs[0], LayoutTab.Property.STATIC_TO_VIEW_BLE
ND, |
| 54 mLayoutTabs[0].getStaticToViewBlend(), 0.0f, HIDE_DURATION_M
S, 0); |
| 55 mLayoutTabs[0].setShouldStall(false); |
| 56 } |
| 57 } |
| 58 |
| 59 private final UnstallRunnable mUnstallRunnable; |
| 60 private final Handler mHandler; |
| 61 private boolean mUnstalling; |
| 62 private StaticTabSceneLayer mSceneLayer; |
| 63 |
| 64 // TODO(aruslan): look into moving this to an overlay/it's own layout. |
| 65 private ReaderModeSceneLayer mReaderModeSceneLayer; |
| 66 private ReaderModePanel mReaderModePanel; |
| 67 |
| 68 /** |
| 69 * Creates an instance of the {@link StaticLayout}. |
| 70 * @param context The current Android's context. |
| 71 * @param updateHost The {@link LayoutUpdateHost} view for this lay
out. |
| 72 * @param renderHost The {@link LayoutRenderHost} view for this lay
out. |
| 73 * @param eventFilter The {@link EventFilter} that is needed for thi
s view. |
| 74 */ |
| 75 public StaticLayout(Context context, LayoutUpdateHost updateHost, LayoutRend
erHost renderHost, |
| 76 EventFilter eventFilter, ContextualSearchPanel panel) { |
| 77 super(context, updateHost, renderHost, eventFilter, panel); |
| 78 |
| 79 mHandler = new Handler(); |
| 80 mUnstallRunnable = new UnstallRunnable(); |
| 81 mUnstalling = false; |
| 82 mSceneLayer = new StaticTabSceneLayer(R.id.control_container); |
| 83 |
| 84 float dpToPx = context.getResources().getDisplayMetrics().density; |
| 85 mReaderModeSceneLayer = new ReaderModeSceneLayer(dpToPx); |
| 86 } |
| 87 |
| 88 /** |
| 89 * @param handlesTabLifecycles Whether or not this {@link Layout} should han
dle tab closing and |
| 90 * creating events. |
| 91 */ |
| 92 public void setLayoutHandlesTabLifecycles(boolean handlesTabLifecycles) { |
| 93 mHandlesTabLifecycles = handlesTabLifecycles; |
| 94 } |
| 95 |
| 96 @Override |
| 97 public int getSizingFlags() { |
| 98 return SizingFlags.HELPER_SUPPORTS_FULLSCREEN; |
| 99 } |
| 100 |
| 101 @Override |
| 102 public float getTopControlsOffset(float currentOffsetDp) { |
| 103 if (mReaderModePanel == null) return super.getTopControlsOffset(currentO
ffsetDp); |
| 104 return mReaderModePanel.getTopControlsOffset(currentOffsetDp); |
| 105 } |
| 106 |
| 107 /** |
| 108 * Initialize the layout to be shown. |
| 109 * @param time The current time of the app in ms. |
| 110 * @param animate Whether to play an entry animation. |
| 111 */ |
| 112 @Override |
| 113 public void show(long time, boolean animate) { |
| 114 super.show(time, animate); |
| 115 |
| 116 mLayoutTabs = null; |
| 117 setStaticTab(mTabModelSelector.getCurrentTabId()); |
| 118 } |
| 119 |
| 120 @Override |
| 121 protected void updateLayout(long time, long dt) { |
| 122 super.updateLayout(time, dt); |
| 123 if (mLayoutTabs != null && mLayoutTabs.length > 0) mLayoutTabs[0].update
Snap(dt); |
| 124 } |
| 125 |
| 126 @Override |
| 127 public void onTabSelected(long time, int id, int prevId, boolean incognito)
{ |
| 128 setStaticTab(id); |
| 129 super.onTabSelected(time, id, prevId, incognito); |
| 130 } |
| 131 |
| 132 @Override |
| 133 public void onTabSelecting(long time, int id) { |
| 134 setStaticTab(id); |
| 135 super.onTabSelecting(time, id); |
| 136 } |
| 137 |
| 138 @Override |
| 139 public void onTabCreated(long time, int tabId, int tabIndex, int sourceTabId
, |
| 140 boolean newIsIncognito, boolean background, float originX, float ori
ginY) { |
| 141 super.onTabCreated( |
| 142 time, tabId, tabIndex, sourceTabId, newIsIncognito, background,
originX, originY); |
| 143 if (!background) setStaticTab(tabId); |
| 144 } |
| 145 |
| 146 @Override |
| 147 public void onTabModelSwitched(boolean incognito) { |
| 148 super.onTabModelSwitched(incognito); |
| 149 setStaticTab(mTabModelSelector.getCurrentTabId()); |
| 150 } |
| 151 |
| 152 @Override |
| 153 public void onTabPageLoadFinished(int id, boolean incognito) { |
| 154 super.onTabPageLoadFinished(id, incognito); |
| 155 unstallImmediately(id); |
| 156 } |
| 157 |
| 158 private void setPreHideState() { |
| 159 mHandler.removeCallbacks(mUnstallRunnable); |
| 160 mLayoutTabs[0].setStaticToViewBlend(1.0f); |
| 161 mLayoutTabs[0].setSaturation(0.0f); |
| 162 mUnstalling = true; |
| 163 } |
| 164 |
| 165 private void setPostHideState() { |
| 166 mHandler.removeCallbacks(mUnstallRunnable); |
| 167 mLayoutTabs[0].setStaticToViewBlend(0.0f); |
| 168 mLayoutTabs[0].setSaturation(1.0f); |
| 169 mUnstalling = false; |
| 170 } |
| 171 |
| 172 private void setStaticTab(final int id) { |
| 173 if (mLayoutTabs != null && mLayoutTabs.length > 0 && mLayoutTabs[0].getI
d() == id) { |
| 174 if (!mLayoutTabs[0].shouldStall()) setPostHideState(); |
| 175 return; |
| 176 } |
| 177 TabModel model = mTabModelSelector.getModelForTabId(id); |
| 178 if (model == null) return; |
| 179 updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(id))); |
| 180 if (mLayoutTabs == null || mLayoutTabs.length != 1) mLayoutTabs = new La
youtTab[1]; |
| 181 mLayoutTabs[0] = createLayoutTab(id, model.isIncognito(), NO_CLOSE_BUTTO
N, NO_TITLE); |
| 182 mLayoutTabs[0].setDrawDecoration(false); |
| 183 if (mLayoutTabs[0].shouldStall()) { |
| 184 setPreHideState(); |
| 185 mHandler.postDelayed(mUnstallRunnable, HIDE_TIMEOUT_MS); |
| 186 } else { |
| 187 setPostHideState(); |
| 188 } |
| 189 mReaderModePanel = ReaderModePanel.getReaderModePanel(mTabModelSelector.
getTabById(id)); |
| 190 if (mReaderModePanel != null) { |
| 191 mReaderModePanel.setLayoutDelegate(new ReaderModePanelLayoutDelegate
() { |
| 192 @Override |
| 193 public void requestUpdate() { |
| 194 StaticLayout.this.requestUpdate(); |
| 195 } |
| 196 |
| 197 @Override |
| 198 public void setLayoutTabBrightness(float v) { |
| 199 if (mLayoutTabs != null && mLayoutTabs.length > 0 |
| 200 && mLayoutTabs[0].getId() == id) { |
| 201 mLayoutTabs[0].setBrightness(v); |
| 202 } |
| 203 } |
| 204 |
| 205 @Override |
| 206 public void setLayoutTabY(float v) { |
| 207 if (mLayoutTabs != null && mLayoutTabs.length > 0 |
| 208 && mLayoutTabs[0].getId() == id) { |
| 209 mLayoutTabs[0].setY(v); |
| 210 } |
| 211 } |
| 212 }); |
| 213 final boolean isToolbarVisible = getHeight() == getHeightMinusTopCon
trols(); |
| 214 final float dpToPx = getContext().getResources().getDisplayMetrics()
.density; |
| 215 mReaderModePanel.onSizeChanged(getWidth(), getHeight(), isToolbarVis
ible, dpToPx); |
| 216 } |
| 217 requestRender(); |
| 218 } |
| 219 |
| 220 /** |
| 221 * @return Currently active reader mode panel, or null. |
| 222 */ |
| 223 public ReaderModePanel getReaderModePanel() { |
| 224 return mReaderModePanel; |
| 225 } |
| 226 |
| 227 @Override |
| 228 public void unstallImmediately(int tabId) { |
| 229 if (mLayoutTabs != null && mLayoutTabs.length > 0 && mLayoutTabs[0].getI
d() == tabId) { |
| 230 unstallImmediately(); |
| 231 } |
| 232 } |
| 233 |
| 234 @Override |
| 235 public void unstallImmediately() { |
| 236 if (mLayoutTabs != null && mLayoutTabs.length > 0 && mLayoutTabs[0].shou
ldStall() |
| 237 && mUnstalling) { |
| 238 mHandler.removeCallbacks(mUnstallRunnable); |
| 239 mUnstallRunnable.run(); |
| 240 } |
| 241 } |
| 242 |
| 243 @Override |
| 244 public boolean handlesTabCreating() { |
| 245 return mHandlesTabLifecycles; |
| 246 } |
| 247 |
| 248 @Override |
| 249 public boolean handlesTabClosing() { |
| 250 return mHandlesTabLifecycles; |
| 251 } |
| 252 |
| 253 @Override |
| 254 public boolean handlesCloseAll() { |
| 255 return mHandlesTabLifecycles; |
| 256 } |
| 257 |
| 258 @Override |
| 259 public boolean shouldDisplayContentOverlay() { |
| 260 return true; |
| 261 } |
| 262 |
| 263 @Override |
| 264 public boolean isTabInteractive() { |
| 265 return mLayoutTabs != null && mLayoutTabs.length > 0; |
| 266 } |
| 267 |
| 268 @Override |
| 269 protected SceneLayer getSceneLayer() { |
| 270 return mSceneLayer; |
| 271 } |
| 272 |
| 273 @Override |
| 274 protected void notifySizeChanged(float width, float height, int orientation)
{ |
| 275 super.notifySizeChanged(width, height, orientation); |
| 276 if (mReaderModePanel == null) return; |
| 277 |
| 278 final boolean isToolbarVisible = getHeight() == getHeightMinusTopControl
s(); |
| 279 final float dpToPx = getContext().getResources().getDisplayMetrics().den
sity; |
| 280 mReaderModePanel.onSizeChanged(width, height, isToolbarVisible, dpToPx); |
| 281 } |
| 282 |
| 283 @Override |
| 284 protected boolean onUpdateAnimation(long time, boolean jumpToEnd) { |
| 285 boolean parentAnimating = super.onUpdateAnimation(time, jumpToEnd); |
| 286 boolean panelAnimating = mReaderModePanel != null |
| 287 ? mReaderModePanel.onUpdateAnimation(time, jumpToEnd) |
| 288 : false; |
| 289 return panelAnimating || parentAnimating; |
| 290 } |
| 291 |
| 292 @Override |
| 293 protected void updateSceneLayer(Rect viewport, Rect contentViewport, |
| 294 LayerTitleCache layerTitleCache, TabContentManager tabContentManager
, |
| 295 ResourceManager resourceManager, ChromeFullscreenManager fullscreenM
anager) { |
| 296 super.updateSceneLayer(viewport, contentViewport, layerTitleCache, tabCo
ntentManager, |
| 297 resourceManager, fullscreenManager); |
| 298 assert mSceneLayer != null; |
| 299 |
| 300 final LayoutTab[] tabs = getLayoutTabsToRender(); |
| 301 if (tabs == null || tabs.length != 1 || tabs[0].getId() == Tab.INVALID_T
AB_ID) { |
| 302 return; |
| 303 } |
| 304 LayoutTab layoutTab = tabs[0]; |
| 305 final float dpToPx = getContext().getResources().getDisplayMetrics().den
sity; |
| 306 |
| 307 mReaderModeSceneLayer.update(mReaderModePanel, resourceManager); |
| 308 |
| 309 mSceneLayer.update(dpToPx, contentViewport, layerTitleCache, tabContentM
anager, |
| 310 fullscreenManager, layoutTab); |
| 311 |
| 312 // TODO(pedrosimonetti): Coordinate w/ dtrainor@ to improve integration
with TreeProvider. |
| 313 SceneLayer overlayLayer = null; |
| 314 if (mSearchPanel.isShowing()) { |
| 315 overlayLayer = super.getSceneLayer(); |
| 316 } else if (mReaderModePanel != null && mReaderModePanel.isShowing()) { |
| 317 overlayLayer = mReaderModeSceneLayer; |
| 318 } |
| 319 mSceneLayer.setContentSceneLayer(overlayLayer); |
| 320 |
| 321 // TODO(dtrainor): Find the best way to properly track this metric for c
old starts. |
| 322 // We should probably erase the thumbnail when we select a tab that we n
eed to restore. |
| 323 if (tabContentManager != null |
| 324 && tabContentManager.hasFullCachedThumbnail(layoutTab.getId()))
{ |
| 325 TabModelBase.logPerceivedTabSwitchLatencyMetric(); |
| 326 } |
| 327 } |
| 328 |
| 329 @Override |
| 330 public void destroy() { |
| 331 if (mSceneLayer != null) { |
| 332 mSceneLayer.destroy(); |
| 333 mSceneLayer = null; |
| 334 } |
| 335 } |
| 336 } |
OLD | NEW |