Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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.widget; | 5 package org.chromium.chrome.browser.widget; |
| 6 | 6 |
| 7 import android.animation.Animator; | 7 import android.animation.TimeAnimator; |
| 8 import android.animation.AnimatorListenerAdapter; | 8 import android.animation.TimeAnimator.TimeListener; |
| 9 import android.animation.ObjectAnimator; | |
| 10 import android.content.Context; | 9 import android.content.Context; |
| 11 import android.graphics.drawable.Drawable; | |
| 12 import android.graphics.drawable.LayerDrawable; | |
| 13 import android.util.AttributeSet; | 10 import android.util.AttributeSet; |
| 14 import android.view.View; | |
| 15 | 11 |
| 16 import org.chromium.base.VisibleForTesting; | 12 import org.chromium.base.VisibleForTesting; |
| 17 import org.chromium.ui.interpolators.BakedBezierInterpolator; | 13 import org.chromium.chrome.browser.util.MathUtils; |
| 18 | 14 |
| 19 /** | 15 /** |
| 20 * Progress bar for use in the Toolbar view. | 16 * Progress bar for use in the Toolbar view. |
| 21 */ | 17 */ |
| 22 public class ToolbarProgressBar extends SmoothProgressBar { | 18 public class ToolbarProgressBar extends ClipDrawableProgressBar { |
| 23 private static final long PROGRESS_CLEARING_DELAY_MS = 200; | 19 private static final float ALPHA_CHANGE_SPEED_PER_SECOND = 8.0f; |
| 24 private static final int SHOW_HIDE_DURATION_MS = 100; | 20 private static final long HIDING_DELAY_MS = 100; |
| 25 | 21 |
| 26 private final Runnable mClearLoadProgressRunnable; | 22 // Public duration constants are for testing. |
| 27 private int mDesiredVisibility; | 23 public static final long SHOWING_DURATION_MS = |
| 28 private Animator mShowAnimator; | 24 (long) Math.ceil(1.0f / ALPHA_CHANGE_SPEED_PER_SECOND * 1000); |
| 29 private Animator mHideAnimator; | 25 public static final long HIDING_DURATION_MS = HIDING_DELAY_MS |
| 26 + (long) Math.ceil(1.0f / ALPHA_CHANGE_SPEED_PER_SECOND * 1000); | |
| 27 | |
| 28 private boolean mIsStarted; | |
| 29 private float mTargetAlpha; | |
| 30 private boolean mIsHideRunnablePosted; | |
| 31 private TimeAnimator mAlphaAnimator = new TimeAnimator(); | |
| 32 private final Runnable mHideRunnable = new Runnable() { | |
| 33 @Override | |
| 34 public void run() { | |
| 35 animateAlphaTo(0.0f); | |
| 36 mIsHideRunnablePosted = false; | |
| 37 } | |
| 38 }; | |
| 30 | 39 |
| 31 /** | 40 /** |
| 32 * Creates a toolbar progress bar. | 41 * Creates a toolbar progress bar. |
| 42 * | |
| 33 * @param context the application environment. | 43 * @param context the application environment. |
| 34 * @param attrs the xml attributes that should be used to initialize this vi ew. | 44 * @param attrs the xml attributes that should be used to initialize this vi ew. |
| 35 */ | 45 */ |
| 36 public ToolbarProgressBar(Context context, AttributeSet attrs) { | 46 public ToolbarProgressBar(Context context, AttributeSet attrs) { |
| 37 super(context, attrs); | 47 super(context, attrs); |
| 38 // The base constructor will trigger a progress change and alter the exp ected | |
| 39 // visibility, so force a visibility change to reset the state. | |
| 40 setVisibility(VISIBLE); | |
| 41 | 48 |
| 42 mClearLoadProgressRunnable = new Runnable() { | 49 setAlpha(mTargetAlpha); |
| 50 | |
| 51 mAlphaAnimator.setTimeListener(new TimeListener() { | |
|
Ted C
2015/07/15 02:41:12
What is the benefit of the alpha animator?
Doesn'
Kibeom Kim (inactive)
2015/07/15 11:22:46
I like TimeAnimator in general, I don't know why I
| |
| 43 @Override | 52 @Override |
| 44 public void run() { | 53 public void onTimeUpdate(TimeAnimator animation, long totalTimeMs, l ong deltaTimeMs) { |
| 45 setProgress(0); | 54 float alpha = getAlpha(); |
| 46 } | |
| 47 }; | |
| 48 | 55 |
| 49 // Hide the background portion of the system progress bar. | 56 if (alpha == mTargetAlpha) { |
| 50 Drawable progressDrawable = getProgressDrawable(); | 57 mAlphaAnimator.end(); |
| 51 if (progressDrawable instanceof LayerDrawable) { | 58 return; |
| 52 Drawable progressBackgroundDrawable = | 59 } |
| 53 ((LayerDrawable) progressDrawable) | |
| 54 .findDrawableByLayerId(android.R.id.background); | |
| 55 if (progressBackgroundDrawable != null) { | |
| 56 progressBackgroundDrawable.setVisible(false, false); | |
| 57 progressBackgroundDrawable.setAlpha(0); | |
| 58 } | |
| 59 } | |
| 60 } | |
| 61 | 60 |
| 62 @Override | 61 float maxAlphaChange = ALPHA_CHANGE_SPEED_PER_SECOND * deltaTime Ms / 1000.0f; |
| 63 public void setSecondaryProgress(int secondaryProgress) { | 62 setAlpha(alpha |
| 64 super.setSecondaryProgress(secondaryProgress); | 63 + MathUtils.clamp(mTargetAlpha - alpha, -maxAlphaChange, maxAlphaChange)); |
| 65 setVisibilityForProgress(); | |
| 66 } | |
| 67 | |
| 68 @Override | |
| 69 protected void setProgressInternal(int progress) { | |
| 70 super.setProgressInternal(progress); | |
| 71 | |
| 72 if (progress == getMax()) { | |
| 73 postDelayed(mClearLoadProgressRunnable, PROGRESS_CLEARING_DELAY_MS); | |
| 74 } | |
| 75 | |
| 76 setVisibilityForProgress(); | |
| 77 } | |
| 78 | |
| 79 @Override | |
| 80 public void setVisibility(int v) { | |
| 81 mDesiredVisibility = v; | |
| 82 setVisibilityForProgress(); | |
| 83 } | |
| 84 | |
| 85 private void setVisibilityForProgress() { | |
| 86 if (mDesiredVisibility != VISIBLE) { | |
| 87 super.setVisibility(mDesiredVisibility); | |
| 88 return; | |
| 89 } | |
| 90 | |
| 91 int progress = Math.max(getProgress(), getSecondaryProgress()); | |
| 92 super.setVisibility(progress == 0 ? INVISIBLE : VISIBLE); | |
| 93 } | |
| 94 | |
| 95 @Override | |
| 96 protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
| 97 super.onSizeChanged(w, h, oldw, oldh); | |
| 98 | |
| 99 // Some versions of Android have a bug where they don't properly update the drawables with | |
| 100 // the correct bounds. setProgressDrawable has been overridden to prope rly push the bounds | |
| 101 // but on rotation they weren't always being set. Forcing a bounds upda te on size changes | |
| 102 // fixes the problem. | |
| 103 setProgressDrawable(getProgressDrawable()); | |
| 104 } | |
| 105 | |
| 106 @Override | |
| 107 protected void onLayout(boolean changed, int left, int top, int right, int b ottom) { | |
| 108 super.onLayout(changed, left, top, right, bottom); | |
| 109 buildAnimators(); | |
| 110 setPivotY(getHeight()); | |
| 111 } | |
| 112 | |
| 113 @Override | |
| 114 public void setProgressDrawable(Drawable d) { | |
| 115 Drawable currentDrawable = getProgressDrawable(); | |
| 116 | |
| 117 super.setProgressDrawable(d); | |
| 118 | |
| 119 if (currentDrawable != null && d instanceof LayerDrawable) { | |
| 120 LayerDrawable ld = (LayerDrawable) d; | |
| 121 for (int i = 0; i < ld.getNumberOfLayers(); i++) { | |
| 122 ld.getDrawable(i).setBounds(currentDrawable.getBounds()); | |
| 123 } | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 /** | |
| 128 * @return Whether or not this progress bar has animations running for showi ng/hiding itself. | |
| 129 */ | |
| 130 @VisibleForTesting | |
| 131 boolean isAnimatingForShowOrHide() { | |
| 132 return (mShowAnimator != null && mShowAnimator.isStarted()) | |
| 133 || (mHideAnimator != null && mHideAnimator.isStarted()); | |
| 134 } | |
| 135 | |
| 136 private void buildAnimators() { | |
| 137 if (mShowAnimator != null && mShowAnimator.isRunning()) mShowAnimator.en d(); | |
| 138 if (mHideAnimator != null && mHideAnimator.isRunning()) mHideAnimator.en d(); | |
| 139 | |
| 140 mShowAnimator = ObjectAnimator.ofFloat(this, View.SCALE_Y, 0.f, 1.f); | |
| 141 mShowAnimator.setDuration(SHOW_HIDE_DURATION_MS); | |
| 142 mShowAnimator.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE); | |
| 143 mShowAnimator.addListener(new AnimatorListenerAdapter() { | |
| 144 @Override | |
| 145 public void onAnimationStart(Animator animation) { | |
| 146 setSecondaryProgress(getMax()); | |
| 147 } | |
| 148 }); | |
| 149 | |
| 150 mHideAnimator = ObjectAnimator.ofFloat(this, View.SCALE_Y, 1.f, 0.f); | |
| 151 mHideAnimator.setDuration(SHOW_HIDE_DURATION_MS); | |
| 152 mHideAnimator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE); | |
| 153 mHideAnimator.addListener(new AnimatorListenerAdapter() { | |
| 154 @Override | |
| 155 public void onAnimationEnd(Animator animation) { | |
| 156 setSecondaryProgress(0); | |
| 157 } | 64 } |
| 158 }); | 65 }); |
| 159 } | 66 } |
| 160 | 67 |
| 68 /** | |
| 69 * Start showing progress bar animation. | |
| 70 */ | |
| 71 public void start() { | |
| 72 mIsStarted = true; | |
| 73 | |
| 74 removeCallbacks(mHideRunnable); | |
| 75 mIsHideRunnablePosted = false; | |
| 76 | |
| 77 animateAlphaTo(1.0f); | |
| 78 } | |
| 79 | |
| 80 /** | |
| 81 * Start hiding progress bar animation. | |
| 82 */ | |
| 83 public void finish() { | |
| 84 mIsStarted = false; | |
|
Ted C
2015/07/15 02:41:12
Is page load finished always going to happen right
Kibeom Kim (inactive)
2015/07/15 11:22:46
I think, regardless of happening right after 100%
Ted C
2015/07/15 17:42:59
Not sure I agree with the "correctness" assertion.
Kibeom Kim (inactive)
2015/07/16 04:45:48
Investigation so far:
In general, progress can be
| |
| 85 | |
| 86 removeCallbacks(mHideRunnable); | |
| 87 postDelayed(mHideRunnable, HIDING_DELAY_MS); | |
| 88 mIsHideRunnablePosted = true; | |
| 89 } | |
| 90 | |
| 91 /** | |
| 92 * @return Whether or not this progress bar has animations running or schedu led for | |
| 93 * showing/hiding itself. | |
| 94 */ | |
| 95 @VisibleForTesting | |
| 96 public boolean isAnimatingForShowOrHide() { | |
| 97 return mAlphaAnimator.isStarted() || mIsHideRunnablePosted; | |
| 98 } | |
| 99 | |
| 100 private void animateAlphaTo(float targetAlpha) { | |
| 101 mTargetAlpha = targetAlpha; | |
| 102 if (getAlpha() != targetAlpha) mAlphaAnimator.start(); | |
| 103 } | |
| 104 | |
| 105 // ClipDrawableProgressBar implementation. | |
| 106 | |
| 161 @Override | 107 @Override |
| 162 public void setProgress(int progress) { | 108 public void setProgress(float progress) { |
| 163 // If the show animator has started, the progress bar needs to be tracke d as if it is | 109 assert mIsStarted; |
| 164 // currently showing. This makes sure we trigger the proper hide animat ion and cancel the | |
| 165 // show animation if we show/hide the bar very fast. See crbug.com/4533 60. | |
| 166 boolean isShowing = | |
| 167 getProgress() > 0 || (mShowAnimator != null && mShowAnimator.isS tarted()); | |
| 168 boolean willShow = progress > 0; | |
| 169 | |
| 170 removeCallbacks(mClearLoadProgressRunnable); | |
| 171 super.setProgress(progress); | 110 super.setProgress(progress); |
| 172 | |
| 173 if (isShowing != willShow) { | |
| 174 if (mShowAnimator == null || mHideAnimator == null) buildAnimators() ; | |
| 175 | |
| 176 if (mShowAnimator.isRunning()) mShowAnimator.end(); | |
| 177 if (mHideAnimator.isRunning()) mHideAnimator.end(); | |
| 178 | |
| 179 if (willShow) { | |
| 180 mShowAnimator.start(); | |
| 181 } else { | |
| 182 mHideAnimator.start(); | |
| 183 } | |
| 184 } | |
| 185 } | 111 } |
| 186 } | 112 } |
| OLD | NEW |