| 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; | |
| 8 import android.animation.AnimatorListenerAdapter; | |
| 9 import android.animation.ObjectAnimator; | |
| 10 import android.content.Context; | 7 import android.content.Context; |
| 11 import android.graphics.drawable.Drawable; | |
| 12 import android.graphics.drawable.LayerDrawable; | |
| 13 import android.util.AttributeSet; | 8 import android.util.AttributeSet; |
| 14 import android.view.View; | |
| 15 | 9 |
| 16 import org.chromium.base.VisibleForTesting; | |
| 17 import org.chromium.ui.interpolators.BakedBezierInterpolator; | 10 import org.chromium.ui.interpolators.BakedBezierInterpolator; |
| 18 | 11 |
| 19 /** | 12 /** |
| 20 * Progress bar for use in the Toolbar view. | 13 * Progress bar for use in the Toolbar view. |
| 21 */ | 14 */ |
| 22 public class ToolbarProgressBar extends SmoothProgressBar { | 15 public class ToolbarProgressBar extends ClipDrawableProgressBar { |
| 23 private static final long PROGRESS_CLEARING_DELAY_MS = 200; | 16 private static final long ALPHA_ANIMATION_DURATION_MS = 150; |
| 24 private static final int SHOW_HIDE_DURATION_MS = 100; | 17 private static final long HIDING_DELAY_MS = 100; |
| 25 | 18 |
| 26 private final Runnable mClearLoadProgressRunnable; | 19 // Public duration constants are for testing. |
| 27 private int mDesiredVisibility; | 20 public static final long SHOWING_DURATION_MS = ALPHA_ANIMATION_DURATION_MS; |
| 28 private Animator mShowAnimator; | 21 public static final long HIDING_DURATION_MS = ALPHA_ANIMATION_DURATION_MS +
HIDING_DELAY_MS; |
| 29 private Animator mHideAnimator; | 22 |
| 23 private boolean mIsStarted; |
| 24 private float mTargetAlpha = 0.0f; |
| 25 private final Runnable mHideRunnable = new Runnable() { |
| 26 @Override |
| 27 public void run() { |
| 28 animateAlphaTo(0.0f); |
| 29 } |
| 30 }; |
| 30 | 31 |
| 31 /** | 32 /** |
| 32 * Creates a toolbar progress bar. | 33 * Creates a toolbar progress bar. |
| 34 * |
| 33 * @param context the application environment. | 35 * @param context the application environment. |
| 34 * @param attrs the xml attributes that should be used to initialize this vi
ew. | 36 * @param attrs the xml attributes that should be used to initialize this vi
ew. |
| 35 */ | 37 */ |
| 36 public ToolbarProgressBar(Context context, AttributeSet attrs) { | 38 public ToolbarProgressBar(Context context, AttributeSet attrs) { |
| 37 super(context, attrs); | 39 super(context, attrs); |
| 38 // The base constructor will trigger a progress change and alter the exp
ected | 40 setAlpha(mTargetAlpha); |
| 39 // visibility, so force a visibility change to reset the state. | 41 } |
| 40 setVisibility(VISIBLE); | |
| 41 | 42 |
| 42 mClearLoadProgressRunnable = new Runnable() { | 43 /** |
| 43 @Override | 44 * Start showing progress bar animation. |
| 44 public void run() { | 45 */ |
| 45 setProgress(0); | 46 public void start() { |
| 46 } | 47 mIsStarted = true; |
| 47 }; | 48 removeCallbacks(mHideRunnable); |
| 49 animateAlphaTo(1.0f); |
| 50 } |
| 48 | 51 |
| 49 // Hide the background portion of the system progress bar. | 52 /** |
| 50 Drawable progressDrawable = getProgressDrawable(); | 53 * Start hiding progress bar animation. |
| 51 if (progressDrawable instanceof LayerDrawable) { | 54 * @param fadeOut Whether a delayed fading out animation should be posted. |
| 52 Drawable progressBackgroundDrawable = | 55 */ |
| 53 ((LayerDrawable) progressDrawable) | 56 public void finish(boolean fadeOut) { |
| 54 .findDrawableByLayerId(android.R.id.background); | 57 mIsStarted = false; |
| 55 if (progressBackgroundDrawable != null) { | 58 |
| 56 progressBackgroundDrawable.setVisible(false, false); | 59 removeCallbacks(mHideRunnable); |
| 57 progressBackgroundDrawable.setAlpha(0); | 60 |
| 58 } | 61 if (fadeOut) { |
| 62 postDelayed(mHideRunnable, HIDING_DELAY_MS); |
| 63 } else { |
| 64 mTargetAlpha = 0.0f; |
| 65 setAlpha(0.0f); |
| 59 } | 66 } |
| 60 } | 67 } |
| 61 | 68 |
| 62 @Override | 69 private void animateAlphaTo(float targetAlpha) { |
| 63 public void setSecondaryProgress(int secondaryProgress) { | 70 mTargetAlpha = targetAlpha; |
| 64 super.setSecondaryProgress(secondaryProgress); | 71 float alphaDiff = targetAlpha - getAlpha(); |
| 65 setVisibilityForProgress(); | 72 if (alphaDiff != 0.0f) { |
| 66 } | 73 animate().alpha(targetAlpha) |
| 67 | 74 .setDuration((long) Math.abs(alphaDiff * ALPHA_ANIMATION_DUR
ATION_MS)) |
| 68 @Override | 75 .setInterpolator(alphaDiff > 0 |
| 69 protected void setProgressInternal(int progress) { | 76 ? BakedBezierInterpolator.FADE_IN_CURVE |
| 70 super.setProgressInternal(progress); | 77 : BakedBezierInterpolator.FADE_OUT_CURVE); |
| 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 } | 78 } |
| 125 } | 79 } |
| 126 | 80 |
| 127 /** | 81 // ClipDrawableProgressBar implementation. |
| 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 } | |
| 158 }); | |
| 159 } | |
| 160 | 82 |
| 161 @Override | 83 @Override |
| 162 public void setProgress(int progress) { | 84 public void setProgress(float progress) { |
| 163 // If the show animator has started, the progress bar needs to be tracke
d as if it is | 85 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); | 86 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 } | 87 } |
| 186 } | 88 } |
| OLD | NEW |