| 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 26ff6fb7818d294679d0970135cc1cb708fa104c..5b59f278b9beeb9b228d0ae3f4c6387a5c252b60 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,8 +4,14 @@
|
|
|
| package org.chromium.chrome.browser.widget;
|
|
|
| +import android.animation.Animator;
|
| +import android.animation.AnimatorListenerAdapter;
|
| +import android.animation.ObjectAnimator;
|
| 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;
|
| @@ -13,91 +19,168 @@
|
| /**
|
| * Progress bar for use in the Toolbar view.
|
| */
|
| -public class ToolbarProgressBar extends ClipDrawableProgressBar {
|
| - private long mAlphaAnimationDurationMs = 130;
|
| - private long mHidingDelayMs = 100;
|
| +public class ToolbarProgressBar extends SmoothProgressBar {
|
| + private static final long PROGRESS_CLEARING_DELAY_MS = 200;
|
| + private static final int SHOW_HIDE_DURATION_MS = 100;
|
|
|
| - private boolean mIsStarted;
|
| - private float mTargetAlpha = 0.0f;
|
| - private final Runnable mHideRunnable = new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - animateAlphaTo(0.0f);
|
| - }
|
| - };
|
| + private final Runnable mClearLoadProgressRunnable;
|
| + private int mDesiredVisibility;
|
| + private Animator mShowAnimator;
|
| + private Animator mHideAnimator;
|
|
|
| /**
|
| * 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);
|
| - setAlpha(mTargetAlpha);
|
| + // 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);
|
| + }
|
| + }
|
| }
|
|
|
| - /**
|
| - * Start showing progress bar animation.
|
| - */
|
| - public void start() {
|
| - mIsStarted = true;
|
| - removeCallbacks(mHideRunnable);
|
| - animateAlphaTo(1.0f);
|
| + @Override
|
| + public void setSecondaryProgress(int secondaryProgress) {
|
| + super.setSecondaryProgress(secondaryProgress);
|
| + setVisibilityForProgress();
|
| }
|
|
|
| - /**
|
| - * Start hiding progress bar animation.
|
| - * @param delayed Whether a delayed fading out animation should be posted.
|
| - */
|
| - public void finish(boolean delayed) {
|
| - mIsStarted = false;
|
| + @Override
|
| + protected void setProgressInternal(int progress) {
|
| + super.setProgressInternal(progress);
|
|
|
| - removeCallbacks(mHideRunnable);
|
| + if (progress == getMax()) {
|
| + postDelayed(mClearLoadProgressRunnable, PROGRESS_CLEARING_DELAY_MS);
|
| + }
|
|
|
| - if (delayed) {
|
| - postDelayed(mHideRunnable, mHidingDelayMs);
|
| - } else {
|
| - mTargetAlpha = 0.0f;
|
| - setAlpha(0.0f);
|
| + setVisibilityForProgress();
|
| + }
|
| +
|
| + @Override
|
| + public void setVisibility(int v) {
|
| + mDesiredVisibility = v;
|
| + setVisibilityForProgress();
|
| + }
|
| +
|
| + private void setVisibilityForProgress() {
|
| + if (mDesiredVisibility != VISIBLE) {
|
| + super.setVisibility(mDesiredVisibility);
|
| + return;
|
| + }
|
| +
|
| + int progress = Math.max(getProgress(), getSecondaryProgress());
|
| + super.setVisibility(progress == 0 ? INVISIBLE : VISIBLE);
|
| + }
|
| +
|
| + @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());
|
| + }
|
| +
|
| + @Override
|
| + protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
| + super.onLayout(changed, left, top, right, bottom);
|
| + buildAnimators();
|
| + setPivotY(getHeight());
|
| + }
|
| +
|
| + @Override
|
| + public void setProgressDrawable(Drawable d) {
|
| + Drawable currentDrawable = getProgressDrawable();
|
| +
|
| + super.setProgressDrawable(d);
|
| +
|
| + if (currentDrawable != null && d instanceof LayerDrawable) {
|
| + LayerDrawable ld = (LayerDrawable) d;
|
| + for (int i = 0; i < ld.getNumberOfLayers(); i++) {
|
| + ld.getDrawable(i).setBounds(currentDrawable.getBounds());
|
| + }
|
| }
|
| }
|
|
|
| /**
|
| - * Set alpha show&hide animation duration. This is for faster testing.
|
| - * @param alphaAnimationDurationMs Alpha animation duration in milliseconds.
|
| + * @return Whether or not this progress bar has animations running for showing/hiding itself.
|
| */
|
| @VisibleForTesting
|
| - public void setAlphaAnimationDuration(long alphaAnimationDurationMs) {
|
| - mAlphaAnimationDurationMs = alphaAnimationDurationMs;
|
| + boolean isAnimatingForShowOrHide() {
|
| + return (mShowAnimator != null && mShowAnimator.isStarted())
|
| + || (mHideAnimator != null && mHideAnimator.isStarted());
|
| }
|
|
|
| - /**
|
| - * Set hiding delay duration. This is for faster testing.
|
| - * @param hidngDelayMs Hiding delay duration in milliseconds.
|
| - */
|
| - @VisibleForTesting
|
| - public void setHidingDelay(long hidngDelayMs) {
|
| - mHidingDelayMs = hidngDelayMs;
|
| + 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;
|
| - float alphaDiff = targetAlpha - getAlpha();
|
| - if (alphaDiff != 0.0f) {
|
| - animate().alpha(targetAlpha)
|
| - .setDuration((long) Math.abs(alphaDiff * mAlphaAnimationDurationMs))
|
| - .setInterpolator(alphaDiff > 0
|
| - ? BakedBezierInterpolator.FADE_IN_CURVE
|
| - : BakedBezierInterpolator.FADE_OUT_CURVE);
|
| + @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);
|
| + 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();
|
| + }
|
| }
|
| }
|
| -
|
| - // ClipDrawableProgressBar implementation.
|
| -
|
| - @Override
|
| - public void setProgress(float progress) {
|
| - assert mIsStarted;
|
| - super.setProgress(progress);
|
| - }
|
| }
|
|
|