Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1249)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/banners/SwipableOverlayView.java

Issue 893483002: Make infobars hide on scroll (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Observer removal Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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.banners; 5 package org.chromium.chrome.browser.banners;
6 6
7 import android.animation.Animator; 7 import android.animation.Animator;
8 import android.animation.AnimatorListenerAdapter; 8 import android.animation.AnimatorListenerAdapter;
9 import android.animation.AnimatorSet; 9 import android.animation.AnimatorSet;
10 import android.animation.ObjectAnimator; 10 import android.animation.ObjectAnimator;
11 import android.animation.PropertyValuesHolder; 11 import android.animation.PropertyValuesHolder;
12 import android.content.Context; 12 import android.content.Context;
13 import android.util.AttributeSet; 13 import android.util.AttributeSet;
14 import android.view.GestureDetector; 14 import android.view.GestureDetector;
15 import android.view.GestureDetector.SimpleOnGestureListener; 15 import android.view.GestureDetector.SimpleOnGestureListener;
16 import android.view.Gravity; 16 import android.view.Gravity;
17 import android.view.MotionEvent; 17 import android.view.MotionEvent;
18 import android.view.View; 18 import android.view.View;
19 import android.view.ViewGroup; 19 import android.view.ViewGroup;
20 import android.view.animation.DecelerateInterpolator; 20 import android.view.animation.DecelerateInterpolator;
21 import android.view.animation.Interpolator; 21 import android.view.animation.Interpolator;
22 import android.widget.FrameLayout; 22 import android.widget.FrameLayout;
23 import android.widget.ScrollView;
23 24
25 import org.chromium.chrome.browser.EmptyTabObserver;
26 import org.chromium.chrome.browser.Tab;
27 import org.chromium.chrome.browser.TabObserver;
24 import org.chromium.content.browser.ContentViewCore; 28 import org.chromium.content.browser.ContentViewCore;
25 import org.chromium.content_public.browser.GestureStateListener; 29 import org.chromium.content_public.browser.GestureStateListener;
26 import org.chromium.ui.UiUtils; 30 import org.chromium.ui.UiUtils;
27 31
28 /** 32 /**
29 * View that appears on the screen as the user scrolls on the page and can be sw iped away. 33 * View that appears on the screen as the user scrolls on the page and can be sw iped away.
30 * Meant to be tacked onto the {@link org.chromium.content.browser.ContentViewCo re}'s view and 34 * Meant to be tacked onto the {@link org.chromium.content.browser.ContentViewCo re}'s view and
31 * alerted when either the page scroll position or viewport size changes. 35 * alerted when either the page scroll position or viewport size changes.
32 * 36 *
33 * GENERAL BEHAVIOR 37 * GENERAL BEHAVIOR
(...skipping 26 matching lines...) Expand all
60 * horizontally (with "enough" defined by the DISMISS_SWIPE_THRESHOLD AND DISMIS S_FLING_THRESHOLD) 64 * horizontally (with "enough" defined by the DISMISS_SWIPE_THRESHOLD AND DISMIS S_FLING_THRESHOLD)
61 * triggers an animation that removes the View from the hierarchy. Failing to m eet the threshold 65 * triggers an animation that removes the View from the hierarchy. Failing to m eet the threshold
62 * will result in the View being translated back to the center of the screen. 66 * will result in the View being translated back to the center of the screen.
63 * 67 *
64 * Because the fling velocity handed in by Android is highly inaccurate and ofte n indicates 68 * Because the fling velocity handed in by Android is highly inaccurate and ofte n indicates
65 * that a fling is moving in an opposite direction than expected, the scroll dir ection is tracked 69 * that a fling is moving in an opposite direction than expected, the scroll dir ection is tracked
66 * to determine which direction the user was dragging the View when the fling wa s initiated. When a 70 * to determine which direction the user was dragging the View when the fling wa s initiated. When a
67 * fling is completed, the more forgiving FLING_THRESHOLD is used to determine h ow far a user must 71 * fling is completed, the more forgiving FLING_THRESHOLD is used to determine h ow far a user must
68 * swipe to dismiss the View rather than try to use the fling velocity. 72 * swipe to dismiss the View rather than try to use the fling velocity.
69 */ 73 */
70 public abstract class SwipableOverlayView extends FrameLayout { 74 public abstract class SwipableOverlayView extends ScrollView {
71 private static final float ALPHA_THRESHOLD = 0.25f; 75 private static final float ALPHA_THRESHOLD = 0.25f;
72 private static final float DISMISS_SWIPE_THRESHOLD = 0.75f; 76 private static final float DISMISS_SWIPE_THRESHOLD = 0.75f;
73 private static final float FULL_THRESHOLD = 0.5f; 77 private static final float FULL_THRESHOLD = 0.5f;
74 private static final float VERTICAL_FLING_SHOW_THRESHOLD = 0.2f; 78 private static final float VERTICAL_FLING_SHOW_THRESHOLD = 0.2f;
75 private static final float VERTICAL_FLING_HIDE_THRESHOLD = 0.9f; 79 private static final float VERTICAL_FLING_HIDE_THRESHOLD = 0.9f;
80 private static final long REATTACH_FADE_IN_MS = 250;
76 protected static final float ZERO_THRESHOLD = 0.001f; 81 protected static final float ZERO_THRESHOLD = 0.001f;
77 82
78 private static final int GESTURE_NONE = 0; 83 private static final int GESTURE_NONE = 0;
79 private static final int GESTURE_SCROLLING = 1; 84 private static final int GESTURE_SCROLLING = 1;
80 private static final int GESTURE_FLINGING = 2; 85 private static final int GESTURE_FLINGING = 2;
81 86
82 private static final int DRAGGED_LEFT = -1; 87 private static final int DRAGGED_LEFT = -1;
83 private static final int DRAGGED_CANCEL = 0; 88 private static final int DRAGGED_CANCEL = 0;
84 private static final int DRAGGED_RIGHT = 1; 89 private static final int DRAGGED_RIGHT = 1;
85 90
86 protected static final long MS_ANIMATION_DURATION = 250; 91 protected static final long MS_ANIMATION_DURATION = 250;
87 private static final long MS_DISMISS_FLING_THRESHOLD = MS_ANIMATION_DURATION * 2; 92 private static final long MS_DISMISS_FLING_THRESHOLD = MS_ANIMATION_DURATION * 2;
88 private static final long MS_SLOW_DISMISS = MS_ANIMATION_DURATION * 3; 93 private static final long MS_SLOW_DISMISS = MS_ANIMATION_DURATION * 3;
89 94
95 /** Resets the state of the SwipableOverlayView, as needed. */
96 protected class SwipableOverlayViewTabObserver extends EmptyTabObserver {
97 @Override
98 public void onDidNavigateMainFrame(Tab tab, String url, String baseUrl,
99 boolean isNavigationToDifferentPage, boolean isFragmentNavigatio n,
100 int statusCode) {
101 setDoStayInvisible(false);
102 }
103 }
104
90 // Detects when the user is dragging the View. 105 // Detects when the user is dragging the View.
91 private final GestureDetector mGestureDetector; 106 private final GestureDetector mGestureDetector;
92 107
93 // Detects when the user is dragging the ContentViewCore. 108 // Detects when the user is dragging the ContentViewCore.
94 private final GestureStateListener mGestureStateListener; 109 private final GestureStateListener mGestureStateListener;
95 110
111 // Listens for changes in the layout.
112 private final View.OnLayoutChangeListener mLayoutChangeListener;
113
96 // Monitors for animation completions and resets the state. 114 // Monitors for animation completions and resets the state.
97 private final AnimatorListenerAdapter mAnimatorListenerAdapter; 115 private final AnimatorListenerAdapter mAnimatorListenerAdapter;
98 116
99 // Interpolator used for the animation. 117 // Interpolator used for the animation.
100 private final Interpolator mInterpolator; 118 private final Interpolator mInterpolator;
101 119
120 // Observes the Tab.
121 private final TabObserver mTabObserver;
122
102 // Tracks whether the user is scrolling or flinging. 123 // Tracks whether the user is scrolling or flinging.
103 private int mGestureState; 124 private int mGestureState;
104 125
105 // Animation currently being used to translate the View. 126 // Animation currently being used to translate the View.
106 private AnimatorSet mCurrentAnimation; 127 private AnimatorSet mCurrentAnimation;
107 128
108 // Direction the user is horizontally dragging. 129 // Direction the user is horizontally dragging.
109 private int mDragDirection; 130 private int mDragDirection;
110 131
111 // How quickly the user is horizontally dragging. 132 // How quickly the user is horizontally dragging.
(...skipping 16 matching lines...) Expand all
128 149
129 // Whether or not the View ever been fully displayed. 150 // Whether or not the View ever been fully displayed.
130 private boolean mIsBeingDisplayedForFirstTime; 151 private boolean mIsBeingDisplayedForFirstTime;
131 152
132 // Whether or not the View has been, or is being, dismissed. 153 // Whether or not the View has been, or is being, dismissed.
133 private boolean mIsDismissed; 154 private boolean mIsDismissed;
134 155
135 // The ContentViewCore to which the overlay is added. 156 // The ContentViewCore to which the overlay is added.
136 private ContentViewCore mContentViewCore; 157 private ContentViewCore mContentViewCore;
137 158
159 // Keeps the View from becoming visible when it normally would.
160 private boolean mDoStayInvisible;
161
162 // Whether the View should be allowed to be swiped away.
163 private boolean mIsSwipable = true;
164
138 /** 165 /**
139 * Creates a SwipableOverlayView. 166 * Creates a SwipableOverlayView.
140 * @param context Context for acquiring resources. 167 * @param context Context for acquiring resources.
141 * @param attrs Attributes from the XML layout inflation. 168 * @param attrs Attributes from the XML layout inflation.
142 */ 169 */
143 public SwipableOverlayView(Context context, AttributeSet attrs) { 170 public SwipableOverlayView(Context context, AttributeSet attrs) {
144 super(context, attrs); 171 super(context, attrs);
145 SimpleOnGestureListener gestureListener = createGestureListener(); 172 SimpleOnGestureListener gestureListener = createGestureListener();
146 mGestureDetector = new GestureDetector(context, gestureListener); 173 mGestureDetector = new GestureDetector(context, gestureListener);
147 mGestureStateListener = createGestureStateListener(); 174 mGestureStateListener = createGestureStateListener();
148 mGestureState = GESTURE_NONE; 175 mGestureState = GESTURE_NONE;
176 mLayoutChangeListener = createLayoutChangeListener();
149 mAnimatorListenerAdapter = createAnimatorListenerAdapter(); 177 mAnimatorListenerAdapter = createAnimatorListenerAdapter();
150 mInterpolator = new DecelerateInterpolator(1.0f); 178 mInterpolator = new DecelerateInterpolator(1.0f);
179 mTabObserver = createTabObserver();
151 } 180 }
152 181
153 /** 182 /**
154 * Adds this View to the given ContentViewCore's view. 183 * Indicates whether the View should be allowed to be swiped away.
155 * @param layout Layout to add this View to. 184 * @param swipable Whether the View is reacts to horizontal gestures.
156 */ 185 */
157 protected void addToView(ContentViewCore contentViewCore) { 186 protected void setIsSwipable(boolean swipable) {
158 assert mContentViewCore == null; 187 mIsSwipable = swipable;
159 mContentViewCore = contentViewCore;
160 contentViewCore.getContainerView().addView(this, 0, createLayoutParams() );
161 contentViewCore.addGestureStateListener(mGestureStateListener);
162
163 // Listen for the layout to know when to animate the View coming onto th e screen.
164 addOnLayoutChangeListener(createLayoutChangeListener());
165 } 188 }
166 189
167 /** 190 /**
191 * Watches the given ContentViewCore for scrolling changes.
192 */
193 public void setContentViewCore(ContentViewCore contentViewCore) {
194 if (mContentViewCore != null) {
195 mContentViewCore.removeGestureStateListener(mGestureStateListener);
196 }
197
198 mContentViewCore = contentViewCore;
199 if (mContentViewCore != null) {
200 mContentViewCore.addGestureStateListener(mGestureStateListener);
201 }
202 }
203
204 public void addToParentView(ViewGroup parentView) {
205 if (parentView != null && parentView.indexOfChild(this) == -1) {
206 parentView.addView(this, createLayoutParams());
207
208 // Listen for the layout to know when to animate the View coming ont o the screen.
209 addOnLayoutChangeListener(mLayoutChangeListener);
210 }
211 }
212
213 /**
214 * Removes the SwipableOverlayView from its parent and stops monitoring the ContentViewCore.
215 * @return Whether the View was removed from its parent.
216 */
217 public boolean removeFromParentView() {
218 if (getParent() == null) return false;
219
220 ((ViewGroup) getParent()).removeView(this);
221 removeOnLayoutChangeListener(mLayoutChangeListener);
222 return true;
223 }
224
225 /**
168 * Creates a set of LayoutParams that makes the View hug the bottom of the s creen. Override it 226 * Creates a set of LayoutParams that makes the View hug the bottom of the s creen. Override it
169 * for other types of behavior. 227 * for other types of behavior.
170 * @return LayoutParams for use when adding the View to its parent. 228 * @return LayoutParams for use when adding the View to its parent.
171 */ 229 */
172 protected ViewGroup.MarginLayoutParams createLayoutParams() { 230 public ViewGroup.MarginLayoutParams createLayoutParams() {
173 return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutPar ams.WRAP_CONTENT, 231 return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutPar ams.WRAP_CONTENT,
174 Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL); 232 Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
175 } 233 }
176 234
177 /** 235 /**
178 * Removes the View from its parent. 236 * Call with {@code true} when a higher priority bottom element is visible t o keep the View
237 * from ever becoming visible. Call with {@code false} to restore normal vi sibility behavior.
238 * @param doStayInvisible Whether the View should stay invisible even when t hey would
239 * normally become visible.
179 */ 240 */
180 boolean removeFromParent() { 241 public void setDoStayInvisible(boolean doStayInvisible) {
181 if (mContentViewCore != null) { 242 mDoStayInvisible = doStayInvisible;
182 mContentViewCore.getContainerView().removeView(this); 243 }
183 mContentViewCore = null; 244
184 return true; 245 @Override
246 protected void onAttachedToWindow() {
247 super.onAttachedToWindow();
248 if (!mDoStayInvisible) {
249 ObjectAnimator.ofFloat(this, "alpha", 0.f, 1.f).setDuration(REATTACH _FADE_IN_MS)
250 .start();
251 setVisibility(VISIBLE);
185 } 252 }
186 return false;
187 } 253 }
188 254
189 /** 255 /**
256 * @return TabObserver that can be used to monitor a Tab.
257 */
258 protected TabObserver createTabObserver() {
259 return new SwipableOverlayViewTabObserver();
260 }
261
262 /**
263 * @return TabObserver that is used to monitor a Tab.
264 */
265 public TabObserver getTabObserver() {
266 return mTabObserver;
267 }
268
269 /**
190 * See {@link #android.view.ViewGroup.onLayout(boolean, int, int, int, int)} . 270 * See {@link #android.view.ViewGroup.onLayout(boolean, int, int, int, int)} .
191 */ 271 */
192 @Override 272 @Override
193 protected void onLayout(boolean changed, int l, int t, int r, int b) { 273 protected void onLayout(boolean changed, int l, int t, int r, int b) {
194 // Hide the View when the keyboard is showing. 274 // Hide the View when the keyboard is showing.
195 boolean keyboardIsShowing = UiUtils.isKeyboardShowing(getContext(), this ); 275 boolean isShowing = (getVisibility() == View.VISIBLE);
196 setVisibility(keyboardIsShowing ? INVISIBLE : VISIBLE); 276 if (UiUtils.isKeyboardShowing(getContext(), this)) {
277 if (isShowing) {
278 setVisibility(View.INVISIBLE);
279 }
280 } else {
281 if (!isShowing && !mDoStayInvisible) {
282 setVisibility(View.VISIBLE);
283 }
284 }
197 285
198 // Update the viewport height when the parent View's height changes (e.g . after rotation). 286 // Update the viewport height when the parent View's height changes (e.g . after rotation).
199 int currentParentHeight = getParent() == null ? 0 : ((View) getParent()) .getHeight(); 287 int currentParentHeight = getParent() == null ? 0 : ((View) getParent()) .getHeight();
200 if (mParentHeight != currentParentHeight) { 288 if (mParentHeight != currentParentHeight) {
201 mParentHeight = currentParentHeight; 289 mParentHeight = currentParentHeight;
202 mGestureState = GESTURE_NONE; 290 mGestureState = GESTURE_NONE;
203 if (mCurrentAnimation != null) mCurrentAnimation.end(); 291 if (mCurrentAnimation != null) mCurrentAnimation.end();
204 } 292 }
205 293
206 // Update the known effective height of the View. 294 // Update the known effective height of the View.
207 mTotalHeight = getMeasuredHeight(); 295 mTotalHeight = getMeasuredHeight();
208 if (getLayoutParams() instanceof MarginLayoutParams) { 296 if (getLayoutParams() instanceof MarginLayoutParams) {
209 MarginLayoutParams params = (MarginLayoutParams) getLayoutParams(); 297 MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
210 mTotalHeight += params.topMargin + params.bottomMargin; 298 mTotalHeight += params.topMargin + params.bottomMargin;
211 } 299 }
212 300
213 super.onLayout(changed, l, t, r, b); 301 super.onLayout(changed, l, t, r, b);
214 } 302 }
215 303
216 /** 304 /**
217 * See {@link #android.view.View.onTouchEvent(MotionEvent)}. 305 * See {@link #android.view.View.onTouchEvent(MotionEvent)}.
218 */ 306 */
219 @Override 307 @Override
220 public boolean onTouchEvent(MotionEvent event) { 308 public boolean onTouchEvent(MotionEvent event) {
309 if (!mIsSwipable) return false;
310
221 if (mGestureDetector.onTouchEvent(event)) return true; 311 if (mGestureDetector.onTouchEvent(event)) return true;
222 if (mCurrentAnimation != null) return true; 312 if (mCurrentAnimation != null) return true;
223 313
224 int action = event.getActionMasked(); 314 int action = event.getActionMasked();
225 if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANC EL) { 315 if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANC EL) {
226 onFinishHorizontalGesture(); 316 onFinishHorizontalGesture();
227 return true; 317 return true;
228 } 318 }
229 return false; 319 return false;
230 } 320 }
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 474
385 /** 475 /**
386 * Creates a listener that is used only to animate the View coming onto the screen. 476 * Creates a listener that is used only to animate the View coming onto the screen.
387 * @return The SimpleOnGestureListener that will monitor the View. 477 * @return The SimpleOnGestureListener that will monitor the View.
388 */ 478 */
389 private View.OnLayoutChangeListener createLayoutChangeListener() { 479 private View.OnLayoutChangeListener createLayoutChangeListener() {
390 return new View.OnLayoutChangeListener() { 480 return new View.OnLayoutChangeListener() {
391 @Override 481 @Override
392 public void onLayoutChange(View v, int left, int top, int right, int bottom, 482 public void onLayoutChange(View v, int left, int top, int right, int bottom,
393 int oldLeft, int oldTop, int oldRight, int oldBottom) { 483 int oldLeft, int oldTop, int oldRight, int oldBottom) {
394 removeOnLayoutChangeListener(this); 484 removeOnLayoutChangeListener(mLayoutChangeListener);
395 485
396 // Animate the View coming in from the bottom of the screen. 486 // Animate the View coming in from the bottom of the screen.
397 setTranslationY(mTotalHeight); 487 setTranslationY(mTotalHeight);
398 mIsBeingDisplayedForFirstTime = true; 488 mIsBeingDisplayedForFirstTime = true;
399 createVerticalSnapAnimation(true); 489 createVerticalSnapAnimation(true);
400 mCurrentAnimation.start(); 490 mCurrentAnimation.start();
401 } 491 }
402 }; 492 };
403 } 493 }
404 494
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 } 643 }
554 644
555 /** 645 /**
556 * Creates an AnimatorListenerAdapter that cleans up after an animation is c ompleted. 646 * Creates an AnimatorListenerAdapter that cleans up after an animation is c ompleted.
557 * @return {@link AnimatorListenerAdapter} to use for animations. 647 * @return {@link AnimatorListenerAdapter} to use for animations.
558 */ 648 */
559 private AnimatorListenerAdapter createAnimatorListenerAdapter() { 649 private AnimatorListenerAdapter createAnimatorListenerAdapter() {
560 return new AnimatorListenerAdapter() { 650 return new AnimatorListenerAdapter() {
561 @Override 651 @Override
562 public void onAnimationEnd(Animator animation) { 652 public void onAnimationEnd(Animator animation) {
563 if (mIsDismissed) removeFromParent(); 653 if (mIsDismissed) removeFromParentView();
564 654
565 mGestureState = GESTURE_NONE; 655 mGestureState = GESTURE_NONE;
566 mCurrentAnimation = null; 656 mCurrentAnimation = null;
567 mIsBeingDisplayedForFirstTime = false; 657 mIsBeingDisplayedForFirstTime = false;
568 } 658 }
569 }; 659 };
570 } 660 }
571 661
572 /** 662 /**
573 * Records the conditions of the page when a gesture is initiated. 663 * Records the conditions of the page when a gesture is initiated.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
606 /** 696 /**
607 * Called when the View has been clicked. 697 * Called when the View has been clicked.
608 */ 698 */
609 protected abstract void onViewClicked(); 699 protected abstract void onViewClicked();
610 700
611 /** 701 /**
612 * Called when the View needs to show that it's been pressed. 702 * Called when the View needs to show that it's been pressed.
613 */ 703 */
614 protected abstract void onViewPressed(MotionEvent event); 704 protected abstract void onViewPressed(MotionEvent event);
615 } 705 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698