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.PointF;
9 import android.graphics.RectF;
10 import android.view.MotionEvent;
11 import android.view.ViewGroup;
12 
13 import androidx.annotation.IntDef;
14 import androidx.annotation.VisibleForTesting;
15 
16 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
17 import org.chromium.chrome.browser.compositor.LayerTitleCache;
18 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
19 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
20 import org.chromium.chrome.browser.layouts.EventFilter;
21 import org.chromium.chrome.browser.layouts.LayoutType;
22 import org.chromium.chrome.browser.layouts.animation.CompositorAnimationHandler;
23 import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer;
24 import org.chromium.chrome.browser.tab.Tab;
25 import org.chromium.chrome.browser.tabmodel.TabModel;
26 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
27 import org.chromium.chrome.browser.tabmodel.TabModelUtils;
28 import org.chromium.ui.modelutil.PropertyModel;
29 import org.chromium.ui.resources.ResourceManager;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 import java.util.List;
34 
35 /**
36  * Abstract representation of an OpenGL layout tailored to draw tabs. It is a framework used as an
37  * alternative to the Android UI for lower level hardware accelerated rendering.
38  * This layout also pass through all the events that may happen.
39  */
40 
41 public abstract class Layout implements TabContentManager.ThumbnailChangeListener {
42 
43     /**
44      * The orientation of the device.
45      */
46     @IntDef({Orientation.UNSET, Orientation.PORTRAIT, Orientation.LANDSCAPE})
47     @Retention(RetentionPolicy.SOURCE)
48     public @interface Orientation {
49         int UNSET = 0;
50         int PORTRAIT = 1;
51         int LANDSCAPE = 2;
52     }
53 
54     /** The possible variations of the visible viewport that different layouts may need. */
55     @IntDef({ViewportMode.ALWAYS_FULLSCREEN, ViewportMode.ALWAYS_SHOWING_BROWSER_CONTROLS,
56             ViewportMode.DYNAMIC_BROWSER_CONTROLS,
57             ViewportMode.USE_PREVIOUS_BROWSER_CONTROLS_STATE})
58     @Retention(RetentionPolicy.SOURCE)
59     public @interface ViewportMode {
60         /** The viewport is assumed to be always fullscreen. */
61         int ALWAYS_FULLSCREEN = 0;
62         /** The viewport is assuming that browser controls are permanently shown. */
63         int ALWAYS_SHOWING_BROWSER_CONTROLS = 1;
64         /** The viewport will account for animating browser controls (both shown and hidden). */
65         int DYNAMIC_BROWSER_CONTROLS = 2;
66         /** Use a viewport that accounts for the browser controls state in the previous layout. */
67         int USE_PREVIOUS_BROWSER_CONTROLS_STATE = 3;
68     }
69 
70     // Defines to make the code easier to read.
71     public static final boolean NEED_TITLE = true;
72     public static final boolean NO_TITLE = false;
73     public static final boolean SHOW_CLOSE_BUTTON = true;
74     public static final boolean NO_CLOSE_BUTTON = false;
75 
76     /** Length of the unstalling animation. **/
77     public static final long UNSTALLED_ANIMATION_DURATION_MS = 500;
78 
79     private static final float SNAP_SPEED = 1.0f; // dp per second
80 
81     // Drawing area properties.
82     private float mWidthDp;
83     private float mHeightDp;
84     private float mTopBrowserControlsHeightDp;
85     private float mBottomBrowserControlsHeightDp;
86 
87     /** A {@link Context} instance. */
88     private Context mContext;
89 
90     /** The current {@link Orientation} of the layout. */
91     private @Orientation int mCurrentOrientation;
92 
93     // Tabs
94     protected TabModelSelector mTabModelSelector;
95     protected TabContentManager mTabContentManager;
96 
97     // Helpers
98     private final LayoutUpdateHost mUpdateHost;
99     protected final LayoutRenderHost mRenderHost;
100 
101     /** The tabs currently being rendered as part of this layout. The tabs are
102      * drawn using the same ordering as this array. */
103     protected LayoutTab[] mLayoutTabs;
104 
105     // True means that the layout is going to hide as soon as the animation finishes.
106     private boolean mIsStartingToHide;
107 
108     // True means that the layout is going to show as soon as the animation finishes.
109     private boolean mIsStartingToShow;
110 
111     // The next id to show when the layout is hidden, or TabBase#INVALID_TAB_ID if no change.
112     protected int mNextTabId = Tab.INVALID_TAB_ID;
113 
114     // The ratio of dp to px.
115     protected final float mDpToPx;
116     protected final float mPxToDp;
117 
118     /**
119      * The {@link Layout} is not usable until sizeChanged is called.
120      * This is convenient this way so we can pre-create the layout before the host is fully defined.
121      * @param context      The current Android's context.
122      * @param updateHost   The parent {@link LayoutUpdateHost}.
123      * @param renderHost   The parent {@link LayoutRenderHost}.
124      */
Layout(Context context, LayoutUpdateHost updateHost, LayoutRenderHost renderHost)125     public Layout(Context context, LayoutUpdateHost updateHost, LayoutRenderHost renderHost) {
126         mContext = context;
127         mUpdateHost = updateHost;
128         mRenderHost = renderHost;
129 
130         // Invalid sizes
131         mWidthDp = -1;
132         mHeightDp = -1;
133         mTopBrowserControlsHeightDp = -1;
134         mBottomBrowserControlsHeightDp = -1;
135 
136         mCurrentOrientation = Orientation.UNSET;
137         mDpToPx = context.getResources().getDisplayMetrics().density;
138         mPxToDp = 1 / mDpToPx;
139     }
140 
141     /**
142      * @return The handler responsible for running compositor animations.
143      */
getAnimationHandler()144     public CompositorAnimationHandler getAnimationHandler() {
145         return mUpdateHost.getAnimationHandler();
146     }
147 
148     /**
149      * Called when native initialization is completed.
150      */
onFinishNativeInitialization()151     public void onFinishNativeInitialization() {}
152 
153     /**
154      * Cleans up any internal state.  This object should not be used after this call.
155      */
destroy()156     public void destroy() {
157     }
158 
159     /**
160      * @return The current {@link Context} instance associated with this {@link Layout}.
161      */
getContext()162     public Context getContext() {
163         return mContext;
164     }
165 
166     /**
167      * @return Whether the {@link Layout} is currently active.
168      */
isActive()169     public boolean isActive() {
170         return mUpdateHost.isActiveLayout(this);
171     }
172 
173     /**
174      * Creates a {@link LayoutTab}.
175      * @param id              The id of the reference {@link Tab} in the {@link TabModel}.
176      * @param isIncognito     Whether the new tab is incognito.
177      * @param showCloseButton True to show and activate a close button on the border.
178      * @param isTitleNeeded   Whether a title will be shown.
179      * @return                The newly created {@link LayoutTab}.
180      */
createLayoutTab( int id, boolean isIncognito, boolean showCloseButton, boolean isTitleNeeded)181     public LayoutTab createLayoutTab(
182             int id, boolean isIncognito, boolean showCloseButton, boolean isTitleNeeded) {
183         return createLayoutTab(id, isIncognito, showCloseButton, isTitleNeeded, -1.f, -1.f);
184     }
185 
186     /**
187      * Creates a {@link LayoutTab}.
188      * @param id               The id of the reference {@link Tab} in the {@link TabModel}.
189      * @param isIncognito      Whether the new tab is incognito.
190      * @param showCloseButton  True to show and activate a close button on the border.
191      * @param isTitleNeeded    Whether a title will be shown.
192      * @param maxContentWidth  The max content width of the tab.  Negative numbers will use the
193      *                         original content width.
194      * @param maxContentHeight The max content height of the tab.  Negative numbers will use the
195      *                         original content height.
196      * @return                 The newly created {@link LayoutTab}.
197      */
createLayoutTab(int id, boolean isIncognito, boolean showCloseButton, boolean isTitleNeeded, float maxContentWidth, float maxContentHeight)198     public LayoutTab createLayoutTab(int id, boolean isIncognito, boolean showCloseButton,
199             boolean isTitleNeeded, float maxContentWidth, float maxContentHeight) {
200         LayoutTab layoutTab = mUpdateHost.createLayoutTab(
201                 id, isIncognito, showCloseButton, isTitleNeeded, maxContentWidth, maxContentHeight);
202         initLayoutTabFromHost(layoutTab);
203         return layoutTab;
204     }
205 
206     /**
207      * Releases the data we keep for that {@link LayoutTab}.
208      * @param layoutTab The {@link LayoutTab} to release.
209      */
releaseTabLayout(LayoutTab layoutTab)210     public void releaseTabLayout(LayoutTab layoutTab) {
211         mUpdateHost.releaseTabLayout(layoutTab.getId());
212     }
213 
214     /**
215      * Releases cached title texture resources for the {@link LayoutTab}.
216      * @param layoutTab The {@link LayoutTab} to release resources for.
217      */
releaseResourcesForTab(LayoutTab layoutTab)218     public void releaseResourcesForTab(LayoutTab layoutTab) {
219         mUpdateHost.releaseResourcesForTab(layoutTab.getId());
220     }
221 
222     /**
223      * Update the animation and give chance to cascade the changes.
224      * @param time The current time of the app in ms.
225      * @param dt   The delta time between update frames in ms.
226      * @return     Whether the layout is done updating.
227      */
onUpdate(long time, long dt)228     public final boolean onUpdate(long time, long dt) {
229         final boolean doneAnimating = onUpdateAnimation(time, false);
230 
231         // Don't update the layout if onUpdateAnimation ended up making a new layout active.
232         if (mUpdateHost.isActiveLayout(this)) updateLayout(time, dt);
233 
234         return doneAnimating;
235     }
236 
237     /**
238      * Layout-specific updates. Cascades the values updated by the animations.
239      * @param time The current time of the app in ms.
240      * @param dt   The delta time between update frames in ms.
241      */
updateLayout(long time, long dt)242     protected void updateLayout(long time, long dt) {}
243 
244     /**
245      * Update snapping to pixel. To be called once every frame.
246      *
247      * TODO(crbug.com/1070281): Temporary placement. This is some Mediator logic and should move to
248      * the appropriate location when doing MVC. Maybe move to {@link LayoutMediator}.
249      *
250      * @param dt The delta time between update frames in ms.
251      * @param layoutTab The {@link LayoutTab} that needs to be updating.
252      * @return   True if the snapping requests to render at least one more frame.
253      */
updateSnap(long dt, PropertyModel layoutTab)254     protected boolean updateSnap(long dt, PropertyModel layoutTab) {
255         final float step = dt * SNAP_SPEED / 1000.0f;
256         final float renderX = layoutTab.get(LayoutTab.RENDER_X);
257         final float renderY = layoutTab.get(LayoutTab.RENDER_Y);
258         final float x = updateSnap(step, renderX, layoutTab.get(LayoutTab.X));
259         final float y = updateSnap(step, renderY, layoutTab.get(LayoutTab.Y));
260         final boolean change = x != renderX || y != renderY;
261         layoutTab.set(LayoutTab.RENDER_X, x);
262         layoutTab.set(LayoutTab.RENDER_Y, y);
263         return change;
264     }
265 
updateSnap(float step, float current, float ref)266     private float updateSnap(float step, float current, float ref) {
267         if (Math.abs(current - ref) > mPxToDp) return ref;
268         final float refRounded = Math.round(ref * mDpToPx) * mPxToDp;
269         if (refRounded < ref) {
270             current -= step;
271             current = Math.max(refRounded, current);
272         } else {
273             current += step;
274             current = Math.min(refRounded, current);
275         }
276         return current;
277     }
278 
279     /**
280      * Request that the renderer render a frame (after the current frame). This
281      * should be called whenever a new frame should be rendered.
282      */
requestRender()283     public void requestRender() {
284         mRenderHost.requestRender();
285     }
286 
287     /**
288      * Requests one more frame of refresh for the transforms and changing properties. Primarily,
289      * this is so animations can continue to animate.
290      */
requestUpdate()291     public void requestUpdate() {
292         mUpdateHost.requestUpdate();
293     }
294 
295     /**
296      * Called when the context and size of the view has changed.
297      *
298      * @param context     The current Android's context.
299      */
contextChanged(Context context)300     public void contextChanged(Context context) {
301         mContext = context;
302         LayoutTab.resetDimensionConstants(context);
303     }
304 
305     /**
306      * Called when the size of the viewport has changed.
307      * @param visibleViewportPx             The visible viewport that represents the area on the
308      *                                      screen this {@link Layout} gets to draw to in px
309      *                                      (potentially takes into account browser controls).
310      * @param screenViewportPx              The viewport of the screen in px.
311      * @param topBrowserControlsHeightPx    The top browser controls height in px.
312      * @param bottomBrowserControlsHeightPx The bottom browser controls height in px.
313      * @param orientation                   The new orientation.  Valid values are defined by
314      *                                      {@link Orientation}.
315      */
sizeChanged(RectF visibleViewportPx, RectF screenViewportPx, int topBrowserControlsHeightPx, int bottomBrowserControlsHeightPx, @Orientation int orientation)316     final void sizeChanged(RectF visibleViewportPx, RectF screenViewportPx,
317             int topBrowserControlsHeightPx, int bottomBrowserControlsHeightPx,
318             @Orientation int orientation) {
319         // 1. Pull out this Layout's width and height properties based on the viewport.
320         float width = screenViewportPx.width() / mDpToPx;
321         float height = screenViewportPx.height() / mDpToPx;
322         float topBrowserControlsHeightDp = topBrowserControlsHeightPx / mDpToPx;
323         float bottomBrowserControlsHeightDp = bottomBrowserControlsHeightPx / mDpToPx;
324 
325         // 2. Check if any Layout-specific properties have changed.
326         boolean layoutPropertiesChanged = Float.compare(mWidthDp, width) != 0
327                 || Float.compare(mHeightDp, height) != 0
328                 || Float.compare(mTopBrowserControlsHeightDp, topBrowserControlsHeightDp) != 0
329                 || Float.compare(mBottomBrowserControlsHeightDp, bottomBrowserControlsHeightDp) != 0
330                 || mCurrentOrientation != orientation;
331 
332         // 3. Update the internal sizing properties.
333         mWidthDp = width;
334         mHeightDp = height;
335         mTopBrowserControlsHeightDp = topBrowserControlsHeightDp;
336         mBottomBrowserControlsHeightDp = bottomBrowserControlsHeightDp;
337         mCurrentOrientation = orientation;
338 
339         // 4. Notify the actual Layout if necessary.
340         if (layoutPropertiesChanged) {
341             notifySizeChanged(width, height, orientation);
342         }
343     }
344 
345     /**
346      * Notifies when the size or the orientation of the view has actually changed.
347      *
348      * @param width       The new width in dp.
349      * @param height      The new height in dp.
350      * @param orientation The new orientation.
351      */
notifySizeChanged(float width, float height, @Orientation int orientation)352     protected void notifySizeChanged(float width, float height, @Orientation int orientation) {}
353 
354     /**
355      * Sets the managers needed to for the layout to get information from outside. The managers
356      * are tailored to be called from the GL thread.
357      *
358      * @param modelSelector The {@link TabModelSelector} to be set on the layout.
359      * @param manager       The {@link TabContentManager} to get tab display content.
360      */
setTabModelSelector(TabModelSelector modelSelector, TabContentManager manager)361     public void setTabModelSelector(TabModelSelector modelSelector, TabContentManager manager) {
362         mTabModelSelector = modelSelector;
363         setTabContentManager(manager);
364     }
365 
366     /**
367      * Sets the manager needed for the layout to get thumbnails.
368      *
369      * @param manager The {@link TabContentManager} to get tab display content.
370      */
setTabContentManager(TabContentManager manager)371     protected void setTabContentManager(TabContentManager manager) {
372         if (manager == null) return;
373 
374         if (mTabContentManager != null) mTabContentManager.removeThumbnailChangeListener(this);
375         mTabContentManager = manager;
376         mTabContentManager.addThumbnailChangeListener(this);
377     }
378 
379     /**
380      * @return The sizing mode for the layout.
381      */
getViewportMode()382     public @ViewportMode int getViewportMode() {
383         return ViewportMode.ALWAYS_SHOWING_BROWSER_CONTROLS;
384     }
385 
386     /**
387      * Informs this cache of the visible {@link Tab} {@code id}s, as well as the
388      * primary screen-filling tab.
389      */
updateCacheVisibleIdsAndPrimary(List<Integer> visible, int primaryTabId)390     protected void updateCacheVisibleIdsAndPrimary(List<Integer> visible, int primaryTabId) {
391         if (mTabContentManager != null) mTabContentManager.updateVisibleIds(visible, primaryTabId);
392     }
393 
394     /**
395      * Informs this cache of the visible {@link Tab} {@code id}s, in cases where there
396      * is no primary screen-filling tab.
397      */
updateCacheVisibleIds(List<Integer> visible)398     protected void updateCacheVisibleIds(List<Integer> visible) {
399         if (mTabContentManager != null) mTabContentManager.updateVisibleIds(visible, -1);
400     }
401 
402     /**
403      * To be called when the layout is starting a transition out of the view mode.
404      * @param nextTabId          The id of the next tab.
405      * @param hintAtTabSelection Whether or not the new tab selection should be broadcast as a hint
406      *                           potentially before this {@link Layout} is done hiding and the
407      *                           selection occurs.
408      */
startHiding(int nextTabId, boolean hintAtTabSelection)409     public void startHiding(int nextTabId, boolean hintAtTabSelection) {
410         mUpdateHost.startHiding(nextTabId, hintAtTabSelection);
411         mIsStartingToHide = true;
412         mNextTabId = nextTabId;
413     }
414 
415     /**
416      * @return True is the layout is in the process of hiding itself.
417      */
isStartingToHide()418     public boolean isStartingToHide() {
419         return mIsStartingToHide;
420     }
421 
422     /**
423      * @return True is the layout is in the process of showing itself.
424      */
isStartingToShow()425     public boolean isStartingToShow() {
426         return mIsStartingToShow;
427     }
428 
429     /**
430      * @return The incognito state of the layout.
431      */
isIncognito()432     public boolean isIncognito() {
433         return mTabModelSelector.isIncognitoSelected();
434     }
435 
436     /**
437      * To be called when the transition into the layout is done.
438      */
doneShowing()439     public void doneShowing() {
440         if (!mIsStartingToShow) return;
441 
442         mIsStartingToShow = false;
443         mUpdateHost.doneShowing();
444     }
445 
446     /**
447      * To be called when the transition out of the view mode is done.
448      * This is currently called by the renderer when all the animation are done while hiding.
449      */
doneHiding()450     public void doneHiding() {
451         if (!mIsStartingToHide) return;
452 
453         mIsStartingToHide = false;
454         if (mNextTabId != Tab.INVALID_TAB_ID) {
455             TabModel model = mTabModelSelector.getModelForTabId(mNextTabId);
456             if (model != null) {
457                 TabModelUtils.setIndex(model, TabModelUtils.getTabIndexById(model, mNextTabId));
458             }
459             mNextTabId = Tab.INVALID_TAB_ID;
460         }
461         mUpdateHost.doneHiding();
462         if (mRenderHost != null && mRenderHost.getResourceManager() != null) {
463             mRenderHost.getResourceManager().clearTintedResourceCache();
464         }
465 
466         if (getSceneLayer() != null) getSceneLayer().removeFromParent();
467     }
468 
469     /**
470      * Called when a tab is getting selected. Typically when exiting the overview mode.
471      * @param time  The current time of the app in ms.
472      * @param tabId The id of the selected tab.
473      */
onTabSelecting(long time, int tabId)474     public void onTabSelecting(long time, int tabId) {
475         startHiding(tabId, true);
476     }
477 
478     /**
479      * Initialize the layout to be shown.
480      * @param time   The current time of the app in ms.
481      * @param animate Whether to play an entry animation.
482      */
show(long time, boolean animate)483     public void show(long time, boolean animate) {
484         // TODO(crbug.com/1108496): Remove after LayoutManager explicitly hide the old layout.
485         mIsStartingToHide = false;
486         mIsStartingToShow = true;
487         mNextTabId = Tab.INVALID_TAB_ID;
488     }
489 
490     /**
491      * Hands the layout an Android view to attach it's views to.
492      * @param container The Android View to attach the layout's views to.
493      */
attachViews(ViewGroup container)494     public void attachViews(ViewGroup container) { }
495 
496     /**
497      * Signal to the Layout to detach it's views from the container.
498      */
detachViews()499     public void detachViews() { }
500 
501     /**
502      * Forces the current animation to finish and broadcasts the proper event.
503      */
forceAnimationToFinish()504     protected void forceAnimationToFinish() {}
505 
506     /**
507      * @return The width of the drawing area in dp.
508      */
getWidth()509     public float getWidth() {
510         return mWidthDp;
511     }
512 
513     /**
514      * @return The height of the drawing area in dp.
515      */
getHeight()516     public float getHeight() {
517         return mHeightDp;
518     }
519 
520     /**
521      * @return The height of the bottom browser controls in dp.
522      */
getBottomBrowserControlsHeight()523     public float getBottomBrowserControlsHeight() {
524         return mBottomBrowserControlsHeightDp;
525     }
526 
527     /**
528      * @see Orientation
529      * @return The orientation of the screen (portrait or landscape). Values are defined by
530      *         {@link Orientation}.
531      */
getOrientation()532     public @Orientation int getOrientation() {
533         return mCurrentOrientation;
534     }
535 
536     /**
537      * Initializes a {@link LayoutTab} with data from the {@link LayoutUpdateHost}. This function
538      * eventually needs to be called but may be overridden to manage the posting traffic.
539      *
540      * @param layoutTab The {@link LayoutTab} To initialize from a
541      *                  {@link Tab} on the UI thread.
542      * @return          Whether the asynchronous initialization of the {@link LayoutTab} has really
543      *                  been posted.
544      */
initLayoutTabFromHost(LayoutTab layoutTab)545     protected boolean initLayoutTabFromHost(LayoutTab layoutTab) {
546         if (layoutTab.isInitFromHostNeeded()) {
547             mUpdateHost.initLayoutTabFromHost(layoutTab.getId());
548             return true;
549         }
550         return false;
551     }
552 
553     /**
554      * Called by the LayoutManager when an animation should be killed.
555      */
unstallImmediately()556     public void unstallImmediately() { }
557 
558     /**
559      * Called by the LayoutManager when an animation should be killed.
560      * @param tabId The tab that the kill signal is associated with
561      */
unstallImmediately(int tabId)562     public void unstallImmediately(int tabId) { }
563 
564     /**
565      * Called by the LayoutManager when they system back button is pressed.
566      * @return Whether or not the layout consumed the event.
567      */
onBackPressed()568     public boolean onBackPressed() {
569         return false;
570     }
571 
572     /**
573      * Called when a tab get selected. Typically when a tab get closed and the new current tab get
574      * selected.
575      * @param time      The current time of the app in ms.
576      * @param tabId     The id of the selected tab.
577      * @param prevId    The id of the previously selected tab.
578      * @param incognito Whether or not the affected model was incognito.
579      */
onTabSelected(long time, int tabId, int prevId, boolean incognito)580     public void onTabSelected(long time, int tabId, int prevId, boolean incognito) {
581     }
582 
583     /**
584      * Called when a tab is about to be closed. When called, the closing tab will still
585      * be part of the model.
586      * @param time  The current time of the app in ms.
587      * @param tabId The id of the tab being closed
588      */
onTabClosing(long time, int tabId)589     public void onTabClosing(long time, int tabId) {
590     }
591 
592     /**
593      * Called when a tab is being closed. When called, the closing tab will not
594      * be part of the model.
595      * @param time      The current time of the app in ms.
596      * @param tabId     The id of the tab being closed.
597      * @param nextTabId The id if the tab that is being switched to.
598      * @param incognito Whether or not the affected model was incognito.
599      */
onTabClosed(long time, int tabId, int nextTabId, boolean incognito)600     public void onTabClosed(long time, int tabId, int nextTabId, boolean incognito) {
601     }
602 
603     /**
604      * Called when all the tabs in the current stack need to be closed.
605      * When called, the tabs will still be part of the model.
606      * @param time      The current time of the app in ms.
607      * @param incognito True if this the incognito tab model should close all tabs, false otherwise.
608      */
onTabsAllClosing(long time, boolean incognito)609     public void onTabsAllClosing(long time, boolean incognito) {
610     }
611 
612     /**
613      * Called before a tab is created from the top left button.
614      *
615      * @param sourceTabId The id of the source tab.
616      */
onTabCreating(int sourceTabId)617     public void onTabCreating(int sourceTabId) { }
618 
619     /**
620      * Called when a tab is created from the top left button.
621      * @param time           The current time of the app in ms.
622      * @param tabId          The id of the newly created tab.
623      * @param tabIndex       The index of the newly created tab.
624      * @param sourceTabId    The id of the source tab.
625      * @param newIsIncognito Whether the new tab is incognito.
626      * @param background     Whether the tab is created in the background.
627      * @param originX        The X screen coordinate in dp of the last touch down event that spawned
628      *                       this tab.
629      * @param originY        The Y screen coordinate in dp of the last touch down event that spawned
630      *                       this tab.
631      */
onTabCreated(long time, int tabId, int tabIndex, int sourceTabId, boolean newIsIncognito, boolean background, float originX, float originY)632     public void onTabCreated(long time, int tabId, int tabIndex, int sourceTabId,
633             boolean newIsIncognito, boolean background, float originX, float originY) {
634     }
635 
636     /**
637      * Called when a tab is restored (created FROM_RESTORE).
638      * @param time  The current time of the app in ms.
639      * @param tabId The id of the restored tab.
640      */
onTabRestored(long time, int tabId)641     public void onTabRestored(long time, int tabId) { }
642 
643     /**
644      * Called when the current tabModel switched (e.g. standard -> incognito).
645      *
646      * @param incognito True if the new model is incognito.
647      */
onTabModelSwitched(boolean incognito)648     public void onTabModelSwitched(boolean incognito) {
649     }
650 
651     /**
652      * Called when a tab is finally closed if the action was previously undoable.
653      * @param time      The current time of the app in ms.
654      * @param id        The id of the Tab.
655      * @param incognito True if the tab is incognito
656      */
onTabClosureCommitted(long time, int id, boolean incognito)657     public void onTabClosureCommitted(long time, int id, boolean incognito) { }
658 
659     @Override
onThumbnailChange(int id)660     public void onThumbnailChange(int id) {
661         requestUpdate();
662     }
663 
664     /**
665      * Steps the animation forward and updates all the animated values.
666      * @param time      The current time of the app in ms.
667      * @param jumpToEnd Whether to finish the animation.
668      * @return          Whether the animation was finished.
669      */
onUpdateAnimation(long time, boolean jumpToEnd)670     protected boolean onUpdateAnimation(long time, boolean jumpToEnd) {
671         return true;
672     }
673 
674     /**
675      * @return Whether or not there is an animation currently being driven by this {@link Layout}.
676      */
677     @VisibleForTesting
isLayoutAnimating()678     public boolean isLayoutAnimating() {
679         return false;
680     }
681 
682     /**
683      * @return The {@link LayoutTab}s to be drawn.
684      */
getLayoutTabsToRender()685     public LayoutTab[] getLayoutTabsToRender() {
686         return mLayoutTabs;
687     }
688 
689     /**
690      * @param id The id of the {@link LayoutTab} to search for.
691      * @return   A {@link LayoutTab} represented by a {@link Tab} with an id of {@code id}.
692      */
getLayoutTab(int id)693     public LayoutTab getLayoutTab(int id) {
694         if (mLayoutTabs != null) {
695             for (int i = 0; i < mLayoutTabs.length; i++) {
696                 if (mLayoutTabs[i].getId() == id) return mLayoutTabs[i];
697             }
698         }
699         return null;
700     }
701 
702     /**
703      * @return Whether the layout is handling the model updates when a tab is closing.
704      */
handlesTabClosing()705     public boolean handlesTabClosing() {
706         return false;
707     }
708 
709     /**
710      * @return Whether the layout is handling the model updates when a tab is creating.
711      */
handlesTabCreating()712     public boolean handlesTabCreating() {
713         if (mLayoutTabs == null || mLayoutTabs.length != 1) return false;
714         return false;
715     }
716 
717     /**
718      * @return Whether the layout is handling the model updates when closing all the tabs.
719      */
handlesCloseAll()720     public boolean handlesCloseAll() {
721         return false;
722     }
723 
724     /**
725      * Whether or not the toolbar IncognitoToggleButton (if present) should be enabled. E.g., it can
726      * be disabled while animating a tab selection to avoid odd behavior.
727      */
shouldAllowIncognitoSwitching()728     public boolean shouldAllowIncognitoSwitching() {
729         return true;
730     }
731 
732     /**
733      * @return True if the content decoration layer should be shown.
734      */
shouldDisplayContentOverlay()735     public boolean shouldDisplayContentOverlay() {
736         return false;
737     }
738 
739     /**
740      * @return True if the host container can set itself as focusable e.g. for accessibility.
741      *         Subclasses can override e.g. to provide a different default focused view.
742      */
canHostBeFocusable()743     public boolean canHostBeFocusable() {
744         return true;
745     }
746 
747     /**
748      * @param e                 The {@link MotionEvent} to consider.
749      * @param offsets           The current touch offsets that should be applied to the
750      *                          {@link EventFilter}s.
751      * @param isKeyboardShowing Whether or not the keyboard is showing.
752      * @return The {@link EventFilter} the {@link Layout} is listening to.
753      */
findInterceptingEventFilter( MotionEvent e, PointF offsets, boolean isKeyboardShowing)754     public EventFilter findInterceptingEventFilter(
755             MotionEvent e, PointF offsets, boolean isKeyboardShowing) {
756         EventFilter layoutEventFilter = getEventFilter();
757         if (layoutEventFilter != null) {
758             if (offsets != null) {
759                 layoutEventFilter.setCurrentMotionEventOffsets(offsets.x, offsets.y);
760             }
761             if (layoutEventFilter.onInterceptTouchEvent(e, isKeyboardShowing)) {
762                 return layoutEventFilter;
763             }
764         }
765         return null;
766     }
767 
768     /**
769      * Build a {@link SceneLayer} if it hasn't already been built, and update it and return it.
770      *
771      * @param viewport          A viewport in which to display content in px.
772      * @param visibleViewport   The visible section of the viewport in px.
773      * @param layerTitleCache   A layer title cache.
774      * @param tabContentManager A tab content manager.
775      * @param resourceManager   A resource manager.
776      * @param browserControls   A browser controls state provider.
777      * @return                  A {@link SceneLayer} that represents the content for this
778      *                          {@link Layout}.
779      */
getUpdatedSceneLayer(RectF viewport, RectF visibleViewport, LayerTitleCache layerTitleCache, TabContentManager tabContentManager, ResourceManager resourceManager, BrowserControlsStateProvider browserControls)780     public final SceneLayer getUpdatedSceneLayer(RectF viewport, RectF visibleViewport,
781             LayerTitleCache layerTitleCache, TabContentManager tabContentManager,
782             ResourceManager resourceManager, BrowserControlsStateProvider browserControls) {
783         updateSceneLayer(viewport, visibleViewport, layerTitleCache, tabContentManager,
784                 resourceManager, browserControls);
785         return getSceneLayer();
786     }
787 
788     /**
789      * @return Whether or not to force the browser controls Android view to hide.
790      */
forceHideBrowserControlsAndroidView()791     public boolean forceHideBrowserControlsAndroidView() {
792         return false;
793     }
794 
795     /**
796      * @return Whether or not the layout should permanently show the browser controls.
797      */
forceShowBrowserControlsAndroidView()798     public boolean forceShowBrowserControlsAndroidView() {
799         return false;
800     }
801 
802     /**
803      * @return The EventFilter to use for processing events for this Layout.
804      */
getEventFilter()805     protected abstract EventFilter getEventFilter();
806 
807     /**
808      * Get an instance of {@link SceneLayer}. Any class inheriting {@link Layout}
809      * should override this function in order for other functions to work.
810      *
811      * @return The scene layer for this {@link Layout}.
812      */
getSceneLayer()813     protected abstract SceneLayer getSceneLayer();
814 
815     /**
816      * Update {@link SceneLayer} instance this layout holds. Any class inheriting {@link Layout}
817      * should override this function in order for other functions to work.
818      */
updateSceneLayer(RectF viewport, RectF contentViewport, LayerTitleCache layerTitleCache, TabContentManager tabContentManager, ResourceManager resourceManager, BrowserControlsStateProvider browserControls)819     protected void updateSceneLayer(RectF viewport, RectF contentViewport,
820             LayerTitleCache layerTitleCache, TabContentManager tabContentManager,
821             ResourceManager resourceManager, BrowserControlsStateProvider browserControls) {}
822 
823     /**
824      * @return The {@link LayoutType}.
825      */
826     @LayoutType
getLayoutType()827     public abstract int getLayoutType();
828 }
829