OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.chrome.browser.infobar; | 5 package org.chromium.chrome.browser.infobar; |
6 | 6 |
7 import android.content.Context; | 7 import android.content.Context; |
8 import android.view.Gravity; | 8 import android.view.Gravity; |
9 import android.view.View; | |
9 import android.view.ViewGroup; | 10 import android.view.ViewGroup; |
11 import android.view.ViewTreeObserver.OnGlobalLayoutListener; | |
10 import android.widget.FrameLayout; | 12 import android.widget.FrameLayout; |
11 | 13 |
12 import org.chromium.base.ObserverList; | 14 import org.chromium.base.ObserverList; |
13 import org.chromium.base.VisibleForTesting; | 15 import org.chromium.base.VisibleForTesting; |
14 import org.chromium.base.annotations.CalledByNative; | 16 import org.chromium.base.annotations.CalledByNative; |
15 import org.chromium.chrome.browser.banners.SwipableOverlayView; | 17 import org.chromium.chrome.browser.banners.SwipableOverlayView; |
18 import org.chromium.chrome.browser.tab.EmptyTabObserver; | |
16 import org.chromium.chrome.browser.tab.Tab; | 19 import org.chromium.chrome.browser.tab.Tab; |
20 import org.chromium.chrome.browser.tab.TabObserver; | |
17 import org.chromium.content.browser.ContentViewCore; | 21 import org.chromium.content.browser.ContentViewCore; |
18 import org.chromium.content_public.browser.WebContents; | 22 import org.chromium.content_public.browser.WebContents; |
23 import org.chromium.ui.UiUtils; | |
19 import org.chromium.ui.base.DeviceFormFactor; | 24 import org.chromium.ui.base.DeviceFormFactor; |
20 | 25 |
21 import java.util.ArrayList; | 26 import java.util.ArrayList; |
22 | 27 |
23 | 28 |
24 /** | 29 /** |
25 * A container for all the infobars of a specific tab. | 30 * A container for all the infobars of a specific tab. |
26 * Note that infobars creation can be initiated from Java of from native code. | 31 * Note that infobars creation can be initiated from Java of from native code. |
27 * When initiated from native code, special code is needed to keep the Java and native infobar in | 32 * When initiated from native code, special code is needed to keep the Java and native infobar in |
28 * sync, see NativeInfoBar. | 33 * sync, see NativeInfoBar. |
29 */ | 34 */ |
30 public class InfoBarContainer extends SwipableOverlayView { | 35 public class InfoBarContainer extends SwipableOverlayView { |
31 private static final String TAG = "InfoBarContainer"; | 36 private static final String TAG = "InfoBarContainer"; |
32 | 37 |
33 /** Top margin, including the toolbar and tabstrip height and 48dp of web co ntents. */ | 38 /** Top margin, including the toolbar and tabstrip height and 48dp of web co ntents. */ |
34 private static final int TOP_MARGIN_PHONE_DP = 104; | 39 private static final int TOP_MARGIN_PHONE_DP = 104; |
35 private static final int TOP_MARGIN_TABLET_DP = 144; | 40 private static final int TOP_MARGIN_TABLET_DP = 144; |
36 | 41 |
42 /** Length of the animation to fade the InfoBarContainer back into View. */ | |
43 private static final long REATTACH_FADE_IN_MS = 250; | |
44 | |
37 /** Whether or not the InfoBarContainer is allowed to hide when the user scr olls. */ | 45 /** Whether or not the InfoBarContainer is allowed to hide when the user scr olls. */ |
38 private static boolean sIsAllowedToAutoHide = true; | 46 private static boolean sIsAllowedToAutoHide = true; |
39 | 47 |
40 /** | 48 /** |
41 * A listener for the InfoBar animations. | 49 * A listener for the InfoBar animations. |
42 */ | 50 */ |
43 public interface InfoBarAnimationListener { | 51 public interface InfoBarAnimationListener { |
44 public static final int ANIMATION_TYPE_SHOW = 0; | 52 public static final int ANIMATION_TYPE_SHOW = 0; |
45 public static final int ANIMATION_TYPE_SWAP = 1; | 53 public static final int ANIMATION_TYPE_SWAP = 1; |
46 public static final int ANIMATION_TYPE_HIDE = 2; | 54 public static final int ANIMATION_TYPE_HIDE = 2; |
(...skipping 18 matching lines...) Expand all Loading... | |
65 | 73 |
66 /** | 74 /** |
67 * Called when an {@link InfoBar} is about to be removed (before the ani mation). | 75 * Called when an {@link InfoBar} is about to be removed (before the ani mation). |
68 * @param container The notifying {@link InfoBarContainer} | 76 * @param container The notifying {@link InfoBarContainer} |
69 * @param infoBar An {@link InfoBar} being removed | 77 * @param infoBar An {@link InfoBar} being removed |
70 * @param isLast Whether the infobar container is going to be empty | 78 * @param isLast Whether the infobar container is going to be empty |
71 */ | 79 */ |
72 void onRemoveInfoBar(InfoBarContainer container, InfoBar infoBar, boolea n isLast); | 80 void onRemoveInfoBar(InfoBarContainer container, InfoBar infoBar, boolea n isLast); |
73 } | 81 } |
74 | 82 |
83 /** Toggles visibility of the InfoBarContainer when the keyboard appears. */ | |
84 private OnGlobalLayoutListener mGlobalLayoutListener = new OnGlobalLayoutLis tener() { | |
newt (away)
2016/01/22 21:43:46
Just realized a downside of using a global layout
gone
2016/01/22 22:11:41
Android doesn't like that:
01-22 14:10:17.992 290
| |
85 @Override | |
86 public void onGlobalLayout() { | |
87 // Hide the View when the keyboard is showing. | |
88 boolean isShowing = (getVisibility() == View.VISIBLE); | |
89 if (UiUtils.isKeyboardShowing(getContext(), InfoBarContainer.this)) { | |
90 if (isShowing) { | |
91 setVisibility(View.GONE); | |
92 } | |
93 } else { | |
94 if (!isShowing && !mIsObscured) { | |
95 setVisibility(View.VISIBLE); | |
96 } | |
97 } | |
98 } | |
99 }; | |
100 | |
101 /** Resets the state of the InfoBarContainer when the user navigates. */ | |
102 private final TabObserver mTabObserver = new EmptyTabObserver() { | |
103 @Override | |
104 public void onDidNavigateMainFrame(Tab tab, String url, String baseUrl, | |
105 boolean isNavigationToDifferentPage, boolean isFragmentNavigatio n, | |
106 int statusCode) { | |
107 setIsObscuredByOtherView(false); | |
108 } | |
109 }; | |
110 | |
75 private final InfoBarContainerLayout mLayout; | 111 private final InfoBarContainerLayout mLayout; |
76 | 112 |
77 /** Native InfoBarContainer pointer which will be set by nativeInit(). */ | 113 /** Native InfoBarContainer pointer which will be set by nativeInit(). */ |
78 private final long mNativeInfoBarContainer; | 114 private final long mNativeInfoBarContainer; |
79 | 115 |
80 private final Context mContext; | |
81 | |
82 /** The list of all InfoBars in this container, regardless of whether they'v e been shown yet. */ | 116 /** The list of all InfoBars in this container, regardless of whether they'v e been shown yet. */ |
83 private final ArrayList<InfoBar> mInfoBars = new ArrayList<InfoBar>(); | 117 private final ArrayList<InfoBar> mInfoBars = new ArrayList<InfoBar>(); |
84 | 118 |
85 /** True when this container has been emptied and its native counterpart has been destroyed. */ | 119 /** True when this container has been emptied and its native counterpart has been destroyed. */ |
86 private boolean mDestroyed = false; | 120 private boolean mDestroyed = false; |
87 | 121 |
88 /** The id of the tab associated with us. Set to Tab.INVALID_TAB_ID if no ta b is associated. */ | 122 /** The id of the tab associated with us. Set to Tab.INVALID_TAB_ID if no ta b is associated. */ |
89 private int mTabId; | 123 private int mTabId; |
90 | 124 |
91 /** Parent view that contains the InfoBarContainerLayout. */ | 125 /** Parent view that contains the InfoBarContainerLayout. */ |
92 private ViewGroup mParentView; | 126 private ViewGroup mParentView; |
93 | 127 |
128 /** Whether or not another View is occupying the same space as this one. */ | |
129 private boolean mIsObscured; | |
130 | |
94 private final ObserverList<InfoBarContainerObserver> mObservers = | 131 private final ObserverList<InfoBarContainerObserver> mObservers = |
95 new ObserverList<InfoBarContainerObserver>(); | 132 new ObserverList<InfoBarContainerObserver>(); |
96 | 133 |
97 public InfoBarContainer(Context context, int tabId, ViewGroup parentView, Ta b tab) { | 134 public InfoBarContainer(Context context, int tabId, ViewGroup parentView, Ta b tab) { |
98 super(context, null); | 135 super(context, null); |
99 tab.addObserver(getTabObserver()); | 136 tab.addObserver(mTabObserver); |
100 | 137 |
101 // TODO(newt): move this workaround into the infobar views if/when they' re scrollable. | 138 // TODO(newt): move this workaround into the infobar views if/when they' re scrollable. |
102 // Workaround for http://crbug.com/407149. See explanation in onMeasure( ) below. | 139 // Workaround for http://crbug.com/407149. See explanation in onMeasure( ) below. |
103 setVerticalScrollBarEnabled(false); | 140 setVerticalScrollBarEnabled(false); |
104 | 141 |
105 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( | 142 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams( |
106 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.BO TTOM); | 143 LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, Gravity.BO TTOM); |
107 int topMarginDp = DeviceFormFactor.isTablet(context) | 144 int topMarginDp = DeviceFormFactor.isTablet(context) |
108 ? TOP_MARGIN_TABLET_DP : TOP_MARGIN_PHONE_DP; | 145 ? TOP_MARGIN_TABLET_DP : TOP_MARGIN_PHONE_DP; |
109 lp.topMargin = Math.round(topMarginDp * getResources().getDisplayMetrics ().density); | 146 lp.topMargin = Math.round(topMarginDp * getResources().getDisplayMetrics ().density); |
110 setLayoutParams(lp); | 147 setLayoutParams(lp); |
111 | 148 |
112 mContext = context; | |
113 mTabId = tabId; | 149 mTabId = tabId; |
114 mParentView = parentView; | 150 mParentView = parentView; |
115 | 151 |
116 mLayout = new InfoBarContainerLayout(context); | 152 mLayout = new InfoBarContainerLayout(context); |
117 addView(mLayout, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, | 153 addView(mLayout, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, |
118 LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); | 154 LayoutParams.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL)); |
119 | 155 |
120 // Chromium's InfoBarContainer may add an InfoBar immediately during thi s initialization | 156 // Chromium's InfoBarContainer may add an InfoBar immediately during thi s initialization |
121 // call, so make sure everything in the InfoBarContainer is completely r eady beforehand. | 157 // call, so make sure everything in the InfoBarContainer is completely r eady beforehand. |
122 mNativeInfoBarContainer = nativeInit(); | 158 mNativeInfoBarContainer = nativeInit(); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
154 /** | 190 /** |
155 * Returns true if any animations are pending or in progress. | 191 * Returns true if any animations are pending or in progress. |
156 */ | 192 */ |
157 @VisibleForTesting | 193 @VisibleForTesting |
158 public boolean isAnimating() { | 194 public boolean isAnimating() { |
159 return mLayout.isAnimating(); | 195 return mLayout.isAnimating(); |
160 } | 196 } |
161 | 197 |
162 private void addToParentView() { | 198 private void addToParentView() { |
163 super.addToParentView(mParentView); | 199 super.addToParentView(mParentView); |
200 if (mParentView != null) { | |
201 mParentView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalL ayoutListener); | |
202 } | |
164 } | 203 } |
165 | 204 |
166 /** | 205 /** |
167 * Called when the parent {@link android.view.ViewGroup} has changed for | 206 * Called when the parent {@link android.view.ViewGroup} has changed for |
168 * this container. | 207 * this container. |
169 */ | 208 */ |
170 public void onParentViewChanged(int tabId, ViewGroup parentView) { | 209 public void onParentViewChanged(int tabId, ViewGroup parentView) { |
171 mTabId = tabId; | 210 mTabId = tabId; |
172 mParentView = parentView; | 211 mParentView = parentView; |
173 | 212 |
174 removeFromParentView(); | 213 removeFromParentView(); |
175 addToParentView(); | 214 addToParentView(); |
176 } | 215 } |
177 | 216 |
217 @Override | |
218 public boolean removeFromParentView() { | |
219 if (mParentView != null) { | |
220 mParentView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlob alLayoutListener); | |
221 } | |
222 return super.removeFromParentView(); | |
223 } | |
224 | |
178 /** | 225 /** |
179 * Adds an InfoBar to the view hierarchy. | 226 * Adds an InfoBar to the view hierarchy. |
180 * @param infoBar InfoBar to add to the View hierarchy. | 227 * @param infoBar InfoBar to add to the View hierarchy. |
181 */ | 228 */ |
182 @CalledByNative | 229 @CalledByNative |
183 private void addInfoBar(InfoBar infoBar) { | 230 private void addInfoBar(InfoBar infoBar) { |
184 assert !mDestroyed; | 231 assert !mDestroyed; |
185 if (infoBar == null) { | 232 if (infoBar == null) { |
186 return; | 233 return; |
187 } | 234 } |
188 if (mInfoBars.contains(infoBar)) { | 235 if (mInfoBars.contains(infoBar)) { |
189 assert false : "Trying to add an info bar that has already been adde d."; | 236 assert false : "Trying to add an info bar that has already been adde d."; |
190 return; | 237 return; |
191 } | 238 } |
192 addToParentView(); | 239 addToParentView(); |
193 | 240 |
194 // We notify observers immediately (before the animation starts). | 241 // We notify observers immediately (before the animation starts). |
195 for (InfoBarContainerObserver observer : mObservers) { | 242 for (InfoBarContainerObserver observer : mObservers) { |
196 observer.onAddInfoBar(this, infoBar, mInfoBars.isEmpty()); | 243 observer.onAddInfoBar(this, infoBar, mInfoBars.isEmpty()); |
197 } | 244 } |
198 | 245 |
199 // We add the infobar immediately to mInfoBars but we wait for the anima tion to end to | 246 // We add the infobar immediately to mInfoBars but we wait for the anima tion to end to |
200 // notify it's been added, as tests rely on this notification but expect s the infobar view | 247 // notify it's been added, as tests rely on this notification but expect s the infobar view |
201 // to be available when they get the notification. | 248 // to be available when they get the notification. |
202 mInfoBars.add(infoBar); | 249 mInfoBars.add(infoBar); |
203 infoBar.setContext(mContext); | 250 infoBar.setContext(getContext()); |
204 infoBar.setInfoBarContainer(this); | 251 infoBar.setInfoBarContainer(this); |
205 infoBar.createView(); | 252 infoBar.createView(); |
206 | 253 |
207 mLayout.addInfoBar(infoBar); | 254 mLayout.addInfoBar(infoBar); |
208 } | 255 } |
209 | 256 |
210 /** | 257 /** |
211 * Notifies that an infobar's View ({@link InfoBar#getView}) has changed. If the infobar is | 258 * Notifies that an infobar's View ({@link InfoBar#getView}) has changed. If the infobar is |
212 * visible, a view swapping animation will be run. | 259 * visible, a view swapping animation will be run. |
213 */ | 260 */ |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
254 | 301 |
255 /** | 302 /** |
256 * @return all of the InfoBars held in this container. | 303 * @return all of the InfoBars held in this container. |
257 */ | 304 */ |
258 @VisibleForTesting | 305 @VisibleForTesting |
259 public ArrayList<InfoBar> getInfoBarsForTesting() { | 306 public ArrayList<InfoBar> getInfoBarsForTesting() { |
260 return mInfoBars; | 307 return mInfoBars; |
261 } | 308 } |
262 | 309 |
263 /** | 310 /** |
311 * Tells this class that a View with higher priority is occupying the same s pace. | |
312 * | |
313 * Causes this View to hide itself until the obscuring View goes away. | |
314 * | |
315 * @param isObscured Whether this View is obscured by another one. | |
316 */ | |
317 public void setIsObscuredByOtherView(boolean isObscured) { | |
318 mIsObscured = isObscured; | |
319 if (isObscured) { | |
320 setVisibility(View.GONE); | |
321 } else { | |
322 setVisibility(View.VISIBLE); | |
323 } | |
324 } | |
325 | |
326 /** | |
264 * Sets whether the InfoBarContainer is allowed to auto-hide when the user s crolls the page. | 327 * Sets whether the InfoBarContainer is allowed to auto-hide when the user s crolls the page. |
265 * Expected to be called when Touch Exploration is enabled. | 328 * Expected to be called when Touch Exploration is enabled. |
266 * @param isAllowed Whether auto-hiding is allowed. | 329 * @param isAllowed Whether auto-hiding is allowed. |
267 */ | 330 */ |
268 public static void setIsAllowedToAutoHide(boolean isAllowed) { | 331 public static void setIsAllowedToAutoHide(boolean isAllowed) { |
269 sIsAllowedToAutoHide = isAllowed; | 332 sIsAllowedToAutoHide = isAllowed; |
270 } | 333 } |
271 | 334 |
272 @Override | 335 @Override |
273 protected boolean isAllowedToAutoHide() { | 336 protected boolean isAllowedToAutoHide() { |
274 return sIsAllowedToAutoHide; | 337 return sIsAllowedToAutoHide; |
275 } | 338 } |
276 | 339 |
340 @Override | |
341 protected void onAttachedToWindow() { | |
342 super.onAttachedToWindow(); | |
343 if (!mIsObscured) { | |
344 setVisibility(VISIBLE); | |
345 setAlpha(0f); | |
346 animate().alpha(1f).setDuration(REATTACH_FADE_IN_MS); | |
347 } | |
348 } | |
349 | |
277 private native long nativeInit(); | 350 private native long nativeInit(); |
278 private native void nativeSetWebContents( | 351 private native void nativeSetWebContents( |
279 long nativeInfoBarContainerAndroid, WebContents webContents); | 352 long nativeInfoBarContainerAndroid, WebContents webContents); |
280 private native void nativeDestroy(long nativeInfoBarContainerAndroid); | 353 private native void nativeDestroy(long nativeInfoBarContainerAndroid); |
281 } | 354 } |
OLD | NEW |