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

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java

Issue 810853003: Upstream FullscreenManager (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update comments Created 6 years 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
(Empty)
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
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.fullscreen;
6
7 import android.animation.Animator;
8 import android.animation.AnimatorListenerAdapter;
9 import android.animation.ObjectAnimator;
10 import android.app.Activity;
11 import android.content.res.Resources;
12 import android.os.Build;
13 import android.os.Handler;
14 import android.os.Message;
15 import android.os.SystemClock;
16 import android.util.Property;
17 import android.view.Gravity;
18 import android.view.MotionEvent;
19 import android.view.View;
20 import android.view.ViewGroup;
21 import android.view.ViewGroup.LayoutParams;
22 import android.view.Window;
23 import android.widget.FrameLayout;
24
25 import org.chromium.base.ActivityState;
26 import org.chromium.base.ApiCompatibilityUtils;
27 import org.chromium.base.ApplicationStatus;
28 import org.chromium.base.ApplicationStatus.ActivityStateListener;
29 import org.chromium.base.BaseChromiumApplication;
30 import org.chromium.base.BaseChromiumApplication.WindowFocusChangedListener;
31 import org.chromium.base.TraceEvent;
32 import org.chromium.base.VisibleForTesting;
33 import org.chromium.chrome.browser.Tab;
34 import org.chromium.chrome.browser.fullscreen.FullscreenHtmlApiHandler.Fullscree nHtmlApiDelegate;
35 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
36 import org.chromium.content.browser.ContentViewCore;
37
38 import java.util.ArrayList;
39 import java.util.HashSet;
40
41 /**
42 * A class that manages control and content views to create the fullscreen mode.
43 */
44 public class ChromeFullscreenManager
45 extends FullscreenManager implements ActivityStateListener, WindowFocusC hangedListener {
46 // Minimum showtime of the toolbar (in ms).
47 private static final long MINIMUM_SHOW_DURATION_MS = 3000;
48
49 // Maximum length of the slide in/out animation of the toolbar (in ms).
50 private static final long MAX_ANIMATION_DURATION_MS = 500;
51
52 private static final int MSG_ID_CONTROLS_REQUEST_LAYOUT = 1;
53 private static final int MSG_ID_HIDE_CONTROLS = 2;
54
55 private final HashSet<Integer> mPersistentControlTokens = new HashSet<Intege r>();
56
57 private final Activity mActivity;
58 private final Window mWindow;
59 private final Handler mHandler;
60 private final int mControlContainerHeight;
61
62 private View mControlContainer;
63
64 private long mMinShowNotificationMs = MINIMUM_SHOW_DURATION_MS;
65 private long mMaxAnimationDurationMs = MAX_ANIMATION_DURATION_MS;
66
67 private final boolean mEnabled;
68
69 private float mBrowserControlOffset = Float.NaN;
70 private float mRendererControlOffset = Float.NaN;
71 private float mRendererContentOffset;
72 private float mPreviousContentOffset;
73 private float mControlOffset;
74 private float mPreviousControlOffset;
75 private boolean mIsEnteringPersistentModeState;
76
77 private boolean mInGesture;
78 private boolean mContentViewScrolling;
79
80 private int mPersistentControlsCurrentToken;
81 private long mCurrentShowTime;
82
83 private ObjectAnimator mControlAnimation;
84 private boolean mCurrentAnimationIsShowing;
85
86 private boolean mDisableBrowserOverride;
87
88 private boolean mTopControlsPermanentlyHidden;
89 private boolean mTopControlsAndroidViewHidden;
90
91 private final ArrayList<FullscreenListener> mListeners = new ArrayList<Fulls creenListener>();
92
93 /**
94 * A listener that gets notified of changes to the fullscreen state.
95 */
96 public interface FullscreenListener {
97 /**
98 * Called whenever the content's offset changes.
99 * @param offset The new offset of the content from the top of the scree n.
100 */
101 public void onContentOffsetChanged(float offset);
102
103 /**
104 * Called whenever the content's visible offset changes.
105 * @param offset The new offset of the visible content from the top of t he screen.
106 */
107 public void onVisibleContentOffsetChanged(float offset);
108
109 /**
110 * Called when a ContentVideoView is created/destroyed.
111 * @param enabled Whether to enter or leave overlay video mode.
112 */
113 public void onToggleOverlayVideoMode(boolean enabled);
114 }
115
116 private class ControlsOffsetProperty extends Property<ChromeFullscreenManage r, Float> {
117 public ControlsOffsetProperty() {
118 super(Float.class, "controlsOffset");
119 }
120
121 @Override
122 public Float get(ChromeFullscreenManager object) {
123 return getControlOffset();
124 }
125
126 @Override
127 public void set(ChromeFullscreenManager manager, Float offset) {
128 if (mDisableBrowserOverride) return;
129 float browserOffset = offset.floatValue();
130 if (Float.compare(mBrowserControlOffset, browserOffset) == 0) return ;
131 mBrowserControlOffset = browserOffset;
132 manager.updateControlOffset();
133 manager.updateVisuals();
134 }
135 }
136
137 private final Runnable mUpdateVisibilityRunnable = new Runnable() {
138 @Override
139 public void run() {
140 int visibility = shouldShowAndroidControls() ? View.VISIBLE : View.I NVISIBLE;
141 if (mControlContainer.getVisibility() == visibility) return;
142 // requestLayout is required to trigger a new gatherTransparentRegio n(), which
143 // only occurs together with a layout and let's SurfaceFlinger trim overlays.
144 // This may be almost equivalent to using View.GONE, but we still us e View.INVISIBLE
145 // since drawing caches etc. won't be destroyed, and the layout may be less expensive.
146 mControlContainer.setVisibility(visibility);
147 mControlContainer.requestLayout();
148 }
149 };
150
151 /**
152 * Creates an instance of the fullscreen mode manager.
153 * @param activity The activity that supports fullscreen.
154 * @param controlContainer Container holding the controls (Toolbar).
155 * @param enabled Whether fullscreen is globally enabled.
156 * @param modelSelector The model selector providing access to the current t ab.
157 */
158 public ChromeFullscreenManager(Activity activity, View controlContainer, boo lean enabled,
159 boolean persistentFullscreenSupported, TabModelSelector modelSelecto r,
160 int resControlContainerHeight) {
161 super(activity.getWindow(), modelSelector, enabled, persistentFullscreen Supported);
162
163 mActivity = activity;
164 ApplicationStatus.registerStateListenerForActivity(this, activity);
165 ((BaseChromiumApplication) activity.getApplication())
166 .registerWindowFocusChangedListener(this);
167
168 mWindow = activity.getWindow();
169 mHandler = new Handler() {
170 @Override
171 public void handleMessage(Message msg) {
172 if (msg == null) return;
173 switch (msg.what) {
174 case MSG_ID_CONTROLS_REQUEST_LAYOUT:
175 mControlContainer.requestLayout();
176 break;
177 case MSG_ID_HIDE_CONTROLS:
178 update(false);
179 break;
180 default:
181 assert false : "Unexpected message for ID: " + msg.what;
182 break;
183 }
184 }
185 };
186 setControlContainer(controlContainer);
187 Resources resources = mWindow.getContext().getResources();
188 mControlContainerHeight = resources.getDimensionPixelSize(resControlCont ainerHeight);
189 mRendererContentOffset = mControlContainerHeight;
190 mEnabled = enabled;
191 updateControlOffset();
192 }
193
194 /**
195 * @return Whether or not fullscreen is enabled.
196 */
197 public boolean isEnabled() {
198 return mEnabled;
199 }
200
201 /**
202 * Set the control container that is being hidden and shown when manipulatin g the fullscreen
203 * state.
204 * @param controlContainer The container at the top of the screen that conta ins the controls.
205 */
206 public void setControlContainer(View controlContainer) {
207 assert controlContainer != null;
208 mControlContainer = controlContainer;
209 }
210
211 @Override
212 public void onActivityStateChange(Activity activity, int newState) {
213 if (newState == ActivityState.STOPPED) {
214 // Exit fullscreen in onStop to ensure the system UI flags are set c orrectly when
215 // showing again (on JB MR2+ builds, the omnibox would be covered by the
216 // notification bar when this was done in onStart()).
217 setPersistentFullscreenMode(false);
218 } else if (newState == ActivityState.STARTED) {
219 showControlsTransient();
220 } else if (newState == ActivityState.DESTROYED) {
221 ApplicationStatus.unregisterActivityStateListener(this);
222 ((BaseChromiumApplication) mWindow.getContext().getApplicationContex t())
223 .unregisterWindowFocusChangedListener(this);
224 }
225 }
226
227 @Override
228 public void onWindowFocusChanged(Activity activity, boolean hasFocus) {
229 if (mActivity == activity) onWindowFocusChanged(hasFocus);
230 }
231
232 @Override
233 protected FullscreenHtmlApiDelegate createApiDelegate() {
234 return new FullscreenHtmlApiDelegate() {
235 @Override
236 public View getNotificationAnchorView() {
237 return mControlContainer;
238 }
239
240 @Override
241 public int getNotificationOffsetY() {
242 return (int) getControlOffset();
243 }
244
245 @Override
246 public void onEnterFullscreen() {
247 mIsEnteringPersistentModeState = true;
248 }
249
250 @Override
251 public boolean cancelPendingEnterFullscreen() {
252 boolean wasPending = mIsEnteringPersistentModeState;
253 mIsEnteringPersistentModeState = false;
254 return wasPending;
255 }
256
257 @Override
258 public void onFullscreenExited(ContentViewCore contentViewCore) {
259 contentViewCore.getWebContents().updateTopControlsState(false, t rue, true);
260 contentViewCore.getWebContents().updateTopControlsState(true, tr ue, false);
261 }
262
263 @Override
264 public boolean shouldShowNotificationBubble() {
265 return !isOverlayVideoMode();
266 }
267 };
268 }
269
270 /**
271 * Disables the ability for the browser to override the renderer provided to p controls
272 * position for testing.
273 */
274 @VisibleForTesting
275 public void disableBrowserOverrideForTest() {
276 mDisableBrowserOverride = true;
277 mPersistentControlTokens.clear();
278 mHandler.removeMessages(MSG_ID_HIDE_CONTROLS);
279 if (mControlAnimation != null) {
280 mControlAnimation.cancel();
281 mControlAnimation = null;
282 }
283 mBrowserControlOffset = Float.NaN;
284 updateVisuals();
285 }
286
287 /**
288 * Allows tests to override the animation durations for faster tests.
289 * @param minShowDuration The minimum time the controls must be shown.
290 * @param maxAnimationDuration The maximum animation time to show/hide the c ontrols.
291 */
292 @VisibleForTesting
293 public void setAnimationDurationsForTest(long minShowDuration, long maxAnima tionDuration) {
294 mMinShowNotificationMs = minShowDuration;
295 mMaxAnimationDurationMs = maxAnimationDuration;
296 }
297
298 @Override
299 public void showControlsTransient() {
300 if (mPersistentControlTokens.isEmpty()) update(true);
301 }
302
303 @Override
304 public int showControlsPersistent() {
305 int token = mPersistentControlsCurrentToken++;
306 mPersistentControlTokens.add(token);
307 if (mPersistentControlTokens.size() == 1) update(true);
308 return token;
309 }
310
311 @Override
312 public int showControlsPersistentAndClearOldToken(int oldToken) {
313 if (oldToken != INVALID_TOKEN) mPersistentControlTokens.remove(oldToken) ;
314 return showControlsPersistent();
315 }
316
317 @Override
318 public void hideControlsPersistent(int token) {
319 if (mPersistentControlTokens.remove(token) && mPersistentControlTokens.i sEmpty()) {
320 update(false);
321 }
322 }
323
324 /**
325 * @param remove Whether or not to forcefully remove the toolbar.
326 */
327 public void setTopControlsPermamentlyHidden(boolean remove) {
328 if (remove == mTopControlsPermanentlyHidden) return;
329 mTopControlsPermanentlyHidden = remove;
330 updateVisuals();
331 }
332
333 /**
334 * @return Whether or not the toolbar is forcefully being removed.
335 */
336 public boolean areTopControlsPermanentlyHidden() {
337 return mTopControlsPermanentlyHidden;
338 }
339
340 /**
341 * @return Whether the top controls should be drawn as a texture.
342 */
343 public boolean drawControlsAsTexture() {
344 return getControlOffset() > -mControlContainerHeight;
345 }
346
347 /**
348 * @return The height of the top controls in pixels.
349 */
350 public int getTopControlsHeight() {
351 return mEnabled ? mControlContainerHeight : 0;
352 }
353
354 @Override
355 public float getContentOffset() {
356 if (!mEnabled || mTopControlsPermanentlyHidden) return 0;
357 return rendererContentOffset();
358 }
359
360 /**
361 * @return The offset of the controls from the top of the screen.
362 */
363 public float getControlOffset() {
364 if (!mEnabled) return 0;
365 if (mTopControlsPermanentlyHidden) return -getTopControlsHeight();
366 return mControlOffset;
367 }
368
369 @SuppressWarnings("SelfEquality")
370 private void updateControlOffset() {
371 float offset = 0;
372 // Inline Float.isNan with "x != x":
373 final boolean isNaNBrowserControlOffset = mBrowserControlOffset != mBrow serControlOffset;
374 final float rendererControlOffset = rendererControlOffset();
375 final boolean isNaNRendererControlOffset = rendererControlOffset != rend ererControlOffset;
376 if (!isNaNBrowserControlOffset || !isNaNRendererControlOffset) {
377 offset = Math.max(
378 isNaNBrowserControlOffset ? -mControlContainerHeight : mBrow serControlOffset,
379 isNaNRendererControlOffset ? -mControlContainerHeight : rend ererControlOffset);
380 }
381 mControlOffset = offset;
382 }
383
384 @Override
385 public void setOverlayVideoMode(boolean enabled) {
386 super.setOverlayVideoMode(enabled);
387
388 for (int i = 0; i < mListeners.size(); i++) {
389 mListeners.get(i).onToggleOverlayVideoMode(enabled);
390 }
391 }
392
393 /**
394 * @return Whether the browser has a control offset override.
395 */
396 @VisibleForTesting
397 public boolean hasBrowserControlOffsetOverride() {
398 return !Float.isNaN(mBrowserControlOffset) || mControlAnimation != null
399 || !mPersistentControlTokens.isEmpty();
400 }
401
402 /**
403 * Returns how tall the opaque portion of the control container is.
404 */
405 public float controlContainerHeight() {
406 return mControlContainerHeight;
407 }
408
409 private float rendererContentOffset() {
410 if (!mEnabled) return mControlContainerHeight;
411 return mRendererContentOffset;
412 }
413
414 private float rendererControlOffset() {
415 if (!mEnabled) return 0;
416 return mRendererControlOffset;
417 }
418
419 /**
420 * @return The visible offset of the content from the top of the screen.
421 */
422 public float getVisibleContentOffset() {
423 if (!mEnabled) return 0;
424 return mControlContainerHeight + getControlOffset();
425 }
426
427 /**
428 * @param listener The {@link FullscreenListener} to be notified of fullscre en changes.
429 */
430 public void addListener(FullscreenListener listener) {
431 if (!mListeners.contains(listener)) mListeners.add(listener);
432 }
433
434 /**
435 * @param listener The {@link FullscreenListener} to no longer be notified o f fullscreen
436 * changes.
437 */
438 public void removeListener(FullscreenListener listener) {
439 mListeners.remove(listener);
440 }
441
442 /**
443 * Updates the content view's viewport size to have it render the content co rrectly.
444 *
445 * @param viewCore The ContentViewCore to update.
446 */
447 public void updateContentViewViewportSize(ContentViewCore viewCore) {
448 if (!mEnabled || viewCore == null) return;
449 if (mInGesture || mContentViewScrolling) return;
450
451 // Update content viewport size only when the top controls are not anima ting.
452 int contentOffset = (int) rendererContentOffset();
453 if (contentOffset != 0 && contentOffset != mControlContainerHeight) retu rn;
454 viewCore.setTopControlsHeight(mControlContainerHeight, contentOffset > 0 );
455 }
456
457 @Override
458 public void updateContentViewChildrenState() {
459 ContentViewCore contentViewCore = getActiveContentViewCore();
460 if (contentViewCore == null || !mEnabled) return;
461 ViewGroup view = contentViewCore.getContainerView();
462
463 float topViewsTranslation = (getControlOffset() + mControlContainerHeigh t);
464 applyTranslationToTopChildViews(view, topViewsTranslation);
465 applyMarginToFullChildViews(view, topViewsTranslation);
466 updateContentViewViewportSize(contentViewCore);
467 }
468
469 /**
470 * Utility routine for ensuring visibility updates are synchronized with
471 * animation, preventing message loop stalls due to untimely invalidation.
472 */
473 private void scheduleVisibilityUpdate() {
474 final int desiredVisibility = shouldShowAndroidControls() ? View.VISIBLE : View.INVISIBLE;
475 if (mControlContainer.getVisibility() == desiredVisibility) return;
476 mControlContainer.removeCallbacks(mUpdateVisibilityRunnable);
477 ApiCompatibilityUtils.postOnAnimation(mControlContainer, mUpdateVisibili tyRunnable);
478 }
479
480 private void updateVisuals() {
481 if (!mEnabled) return;
482
483 TraceEvent.begin("FullscreenManager:updateVisuals");
484
485 float offset = getControlOffset();
486 if (Float.compare(mPreviousControlOffset, offset) != 0) {
487 mPreviousControlOffset = offset;
488 getHtmlApiHandler().updateBubblePosition();
489
490 scheduleVisibilityUpdate();
491 if (shouldShowAndroidControls()) mControlContainer.setTranslationY(g etControlOffset());
492
493 // In ICS, the toolbar can appear clipped when compositor content is not being drawn
494 // beneath it (at the top of the page, during side swipe). Requesti ng a layout clears
495 // up the issue (see crbug.com/172631).
496 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
497 if (!mHandler.hasMessages(MSG_ID_CONTROLS_REQUEST_LAYOUT)) {
498 mHandler.sendEmptyMessage(MSG_ID_CONTROLS_REQUEST_LAYOUT);
499 }
500 }
501 for (int i = 0; i < mListeners.size(); i++) {
502 mListeners.get(i).onVisibleContentOffsetChanged(getVisibleConten tOffset());
503 }
504 }
505
506 final ContentViewCore contentViewCore = getActiveContentViewCore();
507 if (contentViewCore != null && offset == -mControlContainerHeight
508 && mIsEnteringPersistentModeState) {
509 getHtmlApiHandler().enterFullscreen(contentViewCore);
510 mIsEnteringPersistentModeState = false;
511 }
512
513 updateContentViewChildrenState();
514
515 float contentOffset = getContentOffset();
516 if (Float.compare(mPreviousContentOffset, contentOffset) != 0) {
517 for (int i = 0; i < mListeners.size(); i++) {
518 mListeners.get(i).onContentOffsetChanged(contentOffset);
519 }
520 mPreviousContentOffset = contentOffset;
521 }
522
523 TraceEvent.end("FullscreenManager:updateVisuals");
524 }
525
526 /**
527 * @param hide Whether or not to force the top controls Android view to hide . If this is
528 * {@code false} the top controls Android view will show/hide ba sed on position, if
529 * it is {@code true} the top controls Android view will always be hidden.
530 */
531 public void setHideTopControlsAndroidView(boolean hide) {
532 if (mTopControlsAndroidViewHidden == hide) return;
533 mTopControlsAndroidViewHidden = hide;
534 scheduleVisibilityUpdate();
535 }
536
537 private boolean shouldShowAndroidControls() {
538 if (mTopControlsAndroidViewHidden) return false;
539
540 boolean showControls = getControlOffset() == 0;
541 ContentViewCore contentViewCore = getActiveContentViewCore();
542 if (contentViewCore == null) return showControls;
543 ViewGroup contentView = contentViewCore.getContainerView();
544
545 for (int i = 0; i < contentView.getChildCount(); i++) {
546 View child = contentView.getChildAt(i);
547 if (!(child.getLayoutParams() instanceof FrameLayout.LayoutParams)) continue;
548
549 FrameLayout.LayoutParams layoutParams =
550 (FrameLayout.LayoutParams) child.getLayoutParams();
551 if (Gravity.TOP == (layoutParams.gravity & Gravity.FILL_VERTICAL)) {
552 showControls = true;
553 break;
554 }
555 }
556
557 showControls |= !mPersistentControlTokens.isEmpty();
558
559 return showControls;
560 }
561
562 private void applyMarginToFullChildViews(ViewGroup contentView, float margin ) {
563 for (int i = 0; i < contentView.getChildCount(); i++) {
564 View child = contentView.getChildAt(i);
565 if (!(child.getLayoutParams() instanceof FrameLayout.LayoutParams)) continue;
566 FrameLayout.LayoutParams layoutParams =
567 (FrameLayout.LayoutParams) child.getLayoutParams();
568
569 if (layoutParams.height == LayoutParams.MATCH_PARENT
570 && layoutParams.topMargin != (int) margin) {
571 layoutParams.topMargin = (int) margin;
572 child.requestLayout();
573 TraceEvent.instant("FullscreenManager:child.requestLayout()");
574 }
575 }
576 }
577
578 private void applyTranslationToTopChildViews(ViewGroup contentView, float tr anslation) {
579 for (int i = 0; i < contentView.getChildCount(); i++) {
580 View child = contentView.getChildAt(i);
581 if (!(child.getLayoutParams() instanceof FrameLayout.LayoutParams)) continue;
582
583 FrameLayout.LayoutParams layoutParams =
584 (FrameLayout.LayoutParams) child.getLayoutParams();
585 if (Gravity.TOP == (layoutParams.gravity & Gravity.FILL_VERTICAL)) {
586 child.setTranslationY(translation);
587 TraceEvent.instant("FullscreenManager:child.setTranslationY()");
588 }
589 }
590 }
591
592 private ContentViewCore getActiveContentViewCore() {
593 Tab tab = getTabModelSelector().getCurrentTab();
594 return tab != null ? tab.getContentViewCore() : null;
595 }
596
597 @Override
598 public void setPositionsForTabToNonFullscreen() {
599 setPositionsForTab(0, mControlContainerHeight);
600 }
601
602 @Override
603 public void setPositionsForTab(float controlsOffset, float contentOffset) {
604 if (!mEnabled) return;
605 float rendererControlOffset =
606 Math.round(Math.max(controlsOffset, -mControlContainerHeight));
607 float rendererContentOffset = Math.min(
608 Math.round(contentOffset), rendererControlOffset + mControlConta inerHeight);
609
610 if (Float.compare(rendererControlOffset, mRendererControlOffset) == 0
611 && Float.compare(rendererContentOffset, mRendererContentOffset) == 0) {
612 return;
613 }
614
615 mRendererControlOffset = rendererControlOffset;
616 mRendererContentOffset = rendererContentOffset;
617 updateControlOffset();
618
619 if (mControlAnimation == null) updateVisuals();
620 }
621
622 /**
623 * @param e The dispatched motion event
624 * @return Whether or not this motion event is in the top control container area and should be
625 * consumed.
626 */
627 public boolean onInterceptMotionEvent(MotionEvent e) {
628 return mEnabled && e.getY() < getControlOffset() + mControlContainerHeig ht
629 && !mTopControlsAndroidViewHidden;
630 }
631
632 /**
633 * Notifies the fullscreen manager that a motion event has occurred.
634 * @param e The dispatched motion event.
635 */
636 public void onMotionEvent(MotionEvent e) {
637 if (!mEnabled) return;
638 int eventAction = e.getActionMasked();
639 if (eventAction == MotionEvent.ACTION_DOWN
640 || eventAction == MotionEvent.ACTION_POINTER_DOWN) {
641 mInGesture = true;
642 getHtmlApiHandler().hideNotificationBubble();
643 } else if (eventAction == MotionEvent.ACTION_CANCEL
644 || eventAction == MotionEvent.ACTION_UP) {
645 mInGesture = false;
646 updateVisuals();
647 }
648 }
649
650 private void update(boolean show) {
651 // On forced show/hide, reset the flags that may suppress ContentView re size.
652 // As this method is also called when tab is switched, this also cleanup the scrolling
653 // flag set based on the previous ContentView's scrolling state.
654 mInGesture = false;
655 mContentViewScrolling = false;
656
657 if (!mEnabled) return;
658
659 if (show) mCurrentShowTime = SystemClock.uptimeMillis();
660
661 boolean postHideMessage = false;
662 if (!show) {
663 if (mControlAnimation != null && mCurrentAnimationIsShowing) {
664 postHideMessage = true;
665 } else {
666 long timeDelta = SystemClock.uptimeMillis() - mCurrentShowTime;
667 animateIfNecessary(false, Math.max(mMinShowNotificationMs - time Delta, 0));
668 }
669 } else {
670 animateIfNecessary(true, 0);
671 if (mPersistentControlTokens.isEmpty()) postHideMessage = true;
672 }
673
674 mHandler.removeMessages(MSG_ID_HIDE_CONTROLS);
675 if (postHideMessage) {
676 long timeDelta = SystemClock.uptimeMillis() - mCurrentShowTime;
677 mHandler.sendEmptyMessageDelayed(
678 MSG_ID_HIDE_CONTROLS, Math.max(mMinShowNotificationMs - time Delta, 0));
679 }
680 }
681
682 private void animateIfNecessary(final boolean show, long startDelay) {
683 if (mControlAnimation != null) {
684 if (!mControlAnimation.isRunning() || mCurrentAnimationIsShowing != show) {
685 mControlAnimation.cancel();
686 mControlAnimation = null;
687 } else {
688 return;
689 }
690 }
691
692 float destination = show ? 0 : -mControlContainerHeight;
693 long duration = (long) (mMaxAnimationDurationMs
694 * Math.abs((destination - getControlOffset()) / mControlContaine rHeight));
695 mControlAnimation = ObjectAnimator.ofFloat(this, new ControlsOffsetPrope rty(), destination);
696 mControlAnimation.addListener(new AnimatorListenerAdapter() {
697 private boolean mCanceled = false;
698
699 @Override
700 public void onAnimationCancel(Animator anim) {
701 mCanceled = true;
702 }
703
704 @Override
705 public void onAnimationEnd(Animator animation) {
706 if (!show && !mCanceled) mBrowserControlOffset = Float.NaN;
707 mControlAnimation = null;
708 }
709 });
710 mControlAnimation.setStartDelay(startDelay);
711 mControlAnimation.setDuration(duration);
712 mControlAnimation.start();
713 mCurrentAnimationIsShowing = show;
714 }
715
716 @Override
717 public void onContentViewScrollingStateChanged(boolean scrolling) {
718 mContentViewScrolling = scrolling;
719 if (!scrolling) updateVisuals();
720 }
721 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698