Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java |
| index 5b59f278b9beeb9b228d0ae3f4c6387a5c252b60..9531f53ff4f6d0c8a86ed1d1cf320ac327f5d4a3 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java |
| @@ -4,183 +4,109 @@ |
| package org.chromium.chrome.browser.widget; |
| -import android.animation.Animator; |
| -import android.animation.AnimatorListenerAdapter; |
| -import android.animation.ObjectAnimator; |
| +import android.animation.TimeAnimator; |
| +import android.animation.TimeAnimator.TimeListener; |
| import android.content.Context; |
| -import android.graphics.drawable.Drawable; |
| -import android.graphics.drawable.LayerDrawable; |
| import android.util.AttributeSet; |
| -import android.view.View; |
| import org.chromium.base.VisibleForTesting; |
| -import org.chromium.ui.interpolators.BakedBezierInterpolator; |
| +import org.chromium.chrome.browser.util.MathUtils; |
| /** |
| * Progress bar for use in the Toolbar view. |
| */ |
| -public class ToolbarProgressBar extends SmoothProgressBar { |
| - private static final long PROGRESS_CLEARING_DELAY_MS = 200; |
| - private static final int SHOW_HIDE_DURATION_MS = 100; |
| - |
| - private final Runnable mClearLoadProgressRunnable; |
| - private int mDesiredVisibility; |
| - private Animator mShowAnimator; |
| - private Animator mHideAnimator; |
| +public class ToolbarProgressBar extends ClipDrawableProgressBar { |
| + private static final float ALPHA_CHANGE_SPEED_PER_SECOND = 8.0f; |
| + private static final long HIDING_DELAY_MS = 100; |
| + |
| + // Public duration constants are for testing. |
| + public static final long SHOWING_DURATION_MS = |
| + (long) Math.ceil(1.0f / ALPHA_CHANGE_SPEED_PER_SECOND * 1000); |
| + public static final long HIDING_DURATION_MS = HIDING_DELAY_MS |
| + + (long) Math.ceil(1.0f / ALPHA_CHANGE_SPEED_PER_SECOND * 1000); |
| + |
| + private boolean mIsStarted; |
| + private float mTargetAlpha; |
| + private boolean mIsHideRunnablePosted; |
| + private TimeAnimator mAlphaAnimator = new TimeAnimator(); |
| + private final Runnable mHideRunnable = new Runnable() { |
| + @Override |
| + public void run() { |
| + animateAlphaTo(0.0f); |
| + mIsHideRunnablePosted = false; |
| + } |
| + }; |
| /** |
| * Creates a toolbar progress bar. |
| + * |
| * @param context the application environment. |
| * @param attrs the xml attributes that should be used to initialize this view. |
| */ |
| public ToolbarProgressBar(Context context, AttributeSet attrs) { |
| super(context, attrs); |
| - // The base constructor will trigger a progress change and alter the expected |
| - // visibility, so force a visibility change to reset the state. |
| - setVisibility(VISIBLE); |
| - |
| - mClearLoadProgressRunnable = new Runnable() { |
| - @Override |
| - public void run() { |
| - setProgress(0); |
| - } |
| - }; |
| - |
| - // Hide the background portion of the system progress bar. |
| - Drawable progressDrawable = getProgressDrawable(); |
| - if (progressDrawable instanceof LayerDrawable) { |
| - Drawable progressBackgroundDrawable = |
| - ((LayerDrawable) progressDrawable) |
| - .findDrawableByLayerId(android.R.id.background); |
| - if (progressBackgroundDrawable != null) { |
| - progressBackgroundDrawable.setVisible(false, false); |
| - progressBackgroundDrawable.setAlpha(0); |
| - } |
| - } |
| - } |
| - |
| - @Override |
| - public void setSecondaryProgress(int secondaryProgress) { |
| - super.setSecondaryProgress(secondaryProgress); |
| - setVisibilityForProgress(); |
| - } |
| - @Override |
| - protected void setProgressInternal(int progress) { |
| - super.setProgressInternal(progress); |
| + setAlpha(mTargetAlpha); |
| - if (progress == getMax()) { |
| - postDelayed(mClearLoadProgressRunnable, PROGRESS_CLEARING_DELAY_MS); |
| - } |
| + 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
|
| + @Override |
| + public void onTimeUpdate(TimeAnimator animation, long totalTimeMs, long deltaTimeMs) { |
| + float alpha = getAlpha(); |
| - setVisibilityForProgress(); |
| - } |
| + if (alpha == mTargetAlpha) { |
| + mAlphaAnimator.end(); |
| + return; |
| + } |
| - @Override |
| - public void setVisibility(int v) { |
| - mDesiredVisibility = v; |
| - setVisibilityForProgress(); |
| + float maxAlphaChange = ALPHA_CHANGE_SPEED_PER_SECOND * deltaTimeMs / 1000.0f; |
| + setAlpha(alpha |
| + + MathUtils.clamp(mTargetAlpha - alpha, -maxAlphaChange, maxAlphaChange)); |
| + } |
| + }); |
| } |
| - private void setVisibilityForProgress() { |
| - if (mDesiredVisibility != VISIBLE) { |
| - super.setVisibility(mDesiredVisibility); |
| - return; |
| - } |
| - |
| - int progress = Math.max(getProgress(), getSecondaryProgress()); |
| - super.setVisibility(progress == 0 ? INVISIBLE : VISIBLE); |
| - } |
| + /** |
| + * Start showing progress bar animation. |
| + */ |
| + public void start() { |
| + mIsStarted = true; |
| - @Override |
| - protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
| - super.onSizeChanged(w, h, oldw, oldh); |
| - |
| - // Some versions of Android have a bug where they don't properly update the drawables with |
| - // the correct bounds. setProgressDrawable has been overridden to properly push the bounds |
| - // but on rotation they weren't always being set. Forcing a bounds update on size changes |
| - // fixes the problem. |
| - setProgressDrawable(getProgressDrawable()); |
| - } |
| + removeCallbacks(mHideRunnable); |
| + mIsHideRunnablePosted = false; |
| - @Override |
| - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { |
| - super.onLayout(changed, left, top, right, bottom); |
| - buildAnimators(); |
| - setPivotY(getHeight()); |
| + animateAlphaTo(1.0f); |
| } |
| - @Override |
| - public void setProgressDrawable(Drawable d) { |
| - Drawable currentDrawable = getProgressDrawable(); |
| - |
| - super.setProgressDrawable(d); |
| + /** |
| + * Start hiding progress bar animation. |
| + */ |
| + public void finish() { |
| + 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
|
| - if (currentDrawable != null && d instanceof LayerDrawable) { |
| - LayerDrawable ld = (LayerDrawable) d; |
| - for (int i = 0; i < ld.getNumberOfLayers(); i++) { |
| - ld.getDrawable(i).setBounds(currentDrawable.getBounds()); |
| - } |
| - } |
| + removeCallbacks(mHideRunnable); |
| + postDelayed(mHideRunnable, HIDING_DELAY_MS); |
| + mIsHideRunnablePosted = true; |
| } |
| /** |
| - * @return Whether or not this progress bar has animations running for showing/hiding itself. |
| + * @return Whether or not this progress bar has animations running or scheduled for |
| + * showing/hiding itself. |
| */ |
| @VisibleForTesting |
| - boolean isAnimatingForShowOrHide() { |
| - return (mShowAnimator != null && mShowAnimator.isStarted()) |
| - || (mHideAnimator != null && mHideAnimator.isStarted()); |
| + public boolean isAnimatingForShowOrHide() { |
| + return mAlphaAnimator.isStarted() || mIsHideRunnablePosted; |
| } |
| - private void buildAnimators() { |
| - if (mShowAnimator != null && mShowAnimator.isRunning()) mShowAnimator.end(); |
| - if (mHideAnimator != null && mHideAnimator.isRunning()) mHideAnimator.end(); |
| - |
| - mShowAnimator = ObjectAnimator.ofFloat(this, View.SCALE_Y, 0.f, 1.f); |
| - mShowAnimator.setDuration(SHOW_HIDE_DURATION_MS); |
| - mShowAnimator.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE); |
| - mShowAnimator.addListener(new AnimatorListenerAdapter() { |
| - @Override |
| - public void onAnimationStart(Animator animation) { |
| - setSecondaryProgress(getMax()); |
| - } |
| - }); |
| - |
| - mHideAnimator = ObjectAnimator.ofFloat(this, View.SCALE_Y, 1.f, 0.f); |
| - mHideAnimator.setDuration(SHOW_HIDE_DURATION_MS); |
| - mHideAnimator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE); |
| - mHideAnimator.addListener(new AnimatorListenerAdapter() { |
| - @Override |
| - public void onAnimationEnd(Animator animation) { |
| - setSecondaryProgress(0); |
| - } |
| - }); |
| + private void animateAlphaTo(float targetAlpha) { |
| + mTargetAlpha = targetAlpha; |
| + if (getAlpha() != targetAlpha) mAlphaAnimator.start(); |
| } |
| + // ClipDrawableProgressBar implementation. |
| + |
| @Override |
| - public void setProgress(int progress) { |
| - // If the show animator has started, the progress bar needs to be tracked as if it is |
| - // currently showing. This makes sure we trigger the proper hide animation and cancel the |
| - // show animation if we show/hide the bar very fast. See crbug.com/453360. |
| - boolean isShowing = |
| - getProgress() > 0 || (mShowAnimator != null && mShowAnimator.isStarted()); |
| - boolean willShow = progress > 0; |
| - |
| - removeCallbacks(mClearLoadProgressRunnable); |
| + public void setProgress(float progress) { |
| + assert mIsStarted; |
| super.setProgress(progress); |
| - |
| - if (isShowing != willShow) { |
| - if (mShowAnimator == null || mHideAnimator == null) buildAnimators(); |
| - |
| - if (mShowAnimator.isRunning()) mShowAnimator.end(); |
| - if (mHideAnimator.isRunning()) mHideAnimator.end(); |
| - |
| - if (willShow) { |
| - mShowAnimator.start(); |
| - } else { |
| - mHideAnimator.start(); |
| - } |
| - } |
| } |
| } |