1 // Copyright 2019 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.tab;
6 
7 import androidx.annotation.NonNull;
8 
9 import org.chromium.base.ObserverList.RewindableIterator;
10 import org.chromium.base.UserData;
11 
12 /**
13  * Helper that coordinates the browser controls offsets from the perspective of a particular Tab.
14  */
15 public class TabBrowserControlsOffsetHelper extends EmptyTabObserver implements UserData {
16     private static final Class<TabBrowserControlsOffsetHelper> USER_DATA_KEY =
17             TabBrowserControlsOffsetHelper.class;
18 
19     private final TabImpl mTab;
20 
21     private int mTopControlsOffset;
22     private int mBottomControlsOffset;
23     private int mContentOffset;
24     private int mTopControlsMinHeightOffset;
25     private int mBottomControlsMinHeightOffset;
26 
27     /** {@code true} if offset was changed by compositor. */
28     private boolean mOffsetInitialized;
29 
30     /**
31      * Get (or lazily create) the offset helper for a particular Tab.
32      * @param tab The tab whose helper is being retrieved.
33      * @return The offset helper for a given tab.
34      */
35     @NonNull
get(Tab tab)36     public static TabBrowserControlsOffsetHelper get(Tab tab) {
37         TabBrowserControlsOffsetHelper helper = tab.getUserDataHost().getUserData(USER_DATA_KEY);
38         if (helper == null) {
39             helper = new TabBrowserControlsOffsetHelper(tab);
40             tab.getUserDataHost().setUserData(USER_DATA_KEY, helper);
41         }
42         return helper;
43     }
44 
TabBrowserControlsOffsetHelper(Tab tab)45     private TabBrowserControlsOffsetHelper(Tab tab) {
46         mTab = (TabImpl) tab;
47         tab.addObserver(this);
48     }
49 
50     /**
51      * Sets new top control, content, and min-height offset from renderer.
52      * @param topControlsOffset Top control offset.
53      * @param contentOffset Content offset.
54      * @param topControlsMinHeightOffset Current min-height offset for the top controls that may be
55      *                                   changing as a result of an in-progress min-height change
56      *                                   animation in the renderer.
57      */
setTopOffset(int topControlsOffset, int contentOffset, int topControlsMinHeightOffset)58     void setTopOffset(int topControlsOffset, int contentOffset, int topControlsMinHeightOffset) {
59         if (mOffsetInitialized && topControlsOffset == mTopControlsOffset
60                 && mContentOffset == contentOffset
61                 && mTopControlsMinHeightOffset == topControlsMinHeightOffset) {
62             return;
63         }
64         mTopControlsOffset = topControlsOffset;
65         mContentOffset = contentOffset;
66         mTopControlsMinHeightOffset = topControlsMinHeightOffset;
67         notifyControlsOffsetChanged();
68     }
69 
70     /**
71      * Sets new bottom control offset from renderer.
72      * @param bottomControlsOffset Bottom control offset.
73      * @param bottomControlsMinHeightOffset Current min-height offset for the bottom controls that
74      *                                      may be changing as a result of an in-progress min-height
75      *                                      change animation in the renderer.
76      */
setBottomOffset(int bottomControlsOffset, int bottomControlsMinHeightOffset)77     void setBottomOffset(int bottomControlsOffset, int bottomControlsMinHeightOffset) {
78         if (mOffsetInitialized && mBottomControlsOffset == bottomControlsOffset
79                 && mBottomControlsMinHeightOffset == bottomControlsMinHeightOffset) {
80             return;
81         }
82         mBottomControlsOffset = bottomControlsOffset;
83         mBottomControlsMinHeightOffset = bottomControlsMinHeightOffset;
84         notifyControlsOffsetChanged();
85     }
86 
notifyControlsOffsetChanged()87     private void notifyControlsOffsetChanged() {
88         mOffsetInitialized = true;
89         RewindableIterator<TabObserver> observers = mTab.getTabObservers();
90         while (observers.hasNext()) {
91             observers.next().onBrowserControlsOffsetChanged(mTab, mTopControlsOffset,
92                     mBottomControlsOffset, mContentOffset, mTopControlsMinHeightOffset,
93                     mBottomControlsMinHeightOffset);
94         }
95     }
96 
97     @Override
onCrash(Tab tab)98     public void onCrash(Tab tab) {
99         super.onCrash(tab);
100         mTopControlsOffset = 0;
101         mBottomControlsOffset = 0;
102         mContentOffset = 0;
103         mOffsetInitialized = false;
104     }
105 
106     /** @return Top control offset */
topControlsOffset()107     public int topControlsOffset() {
108         return mTopControlsOffset;
109     }
110 
111     /** @return Bottom control offset */
bottomControlsOffset()112     public int bottomControlsOffset() {
113         return mBottomControlsOffset;
114     }
115 
116     /** @return Content offset */
contentOffset()117     public int contentOffset() {
118         return mContentOffset;
119     }
120 
121     /** @return Top controls min-height offset */
topControlsMinHeightOffset()122     public int topControlsMinHeightOffset() {
123         return mTopControlsMinHeightOffset;
124     }
125 
126     /** @return Bottom controls min-height offset */
bottomControlsMinHeightOffset()127     public int bottomControlsMinHeightOffset() {
128         return mBottomControlsMinHeightOffset;
129     }
130 
131     /** @return Whether the control offset is initialized by compositor. */
offsetInitialized()132     public boolean offsetInitialized() {
133         return mOffsetInitialized;
134     }
135 }
136