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

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/widget/MaterialProgressBar.java

Issue 2586643002: [Downloads] Add a horizontal material-styled ProgressBar (Closed)
Patch Set: Created 4 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 side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/widget/MaterialProgressBar.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/MaterialProgressBar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/MaterialProgressBar.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba11dcd72cce27b22087a872ef2de5cebb88cdf5
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/MaterialProgressBar.java
@@ -0,0 +1,256 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.widget;
+
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.support.v4.view.ViewCompat;
+import android.util.AttributeSet;
+import android.view.View;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.chrome.R;
+
+/**
+ * Material-styled horizontal progress bar
+ *
+ * This class is to be used in place of the support library's progress bar, which does not support
+ * indeterminate progress bar styling on JB or KK.
+ *
+ * -------------------------------------------------------------------------------------------------
+ * DESIGN SPEC
+ *
+ * https://material.io/guidelines/components/progress-activity.html
+ *
+ * Secondary progress is represented by a second bar that is drawn on top of the primary progress,
+ * and is completely optional.
+ *
+ * -------------------------------------------------------------------------------------------------
+ * DEFINING THE CONTROL STYLING IN AN XML LAYOUT
+ *
+ * Add the "chrome" namespace as an attribute to the main tag of the layout file:
+ * xmlns:chrome="http://schemas.android.com/apk/res-auto
+ *
+ * These attributes control styling of the bar:
+ * chrome:colorBackground Background color of a determinate progress bar.
+ * chrome:colorProgress Represents progress along a determinate progress bar.
+ * Also used as the background color for indeterminate progress.
+ * chrome:colorSecondaryProgress Represents secondary progress on top of the regular progress.
+ * chrome:colorThrobber Color of the pulses fired along the indeterminate progress bar.
+ */
+public class MaterialProgressBar extends View implements AnimatorUpdateListener {
+ private static final long INDETERMINATE_ANIMATION_DURATION_MS = 2500;
+
+ private final ValueAnimator mIndeterminateAnimator = ValueAnimator.ofFloat(0.0f, 3.0f);
+ private final Paint mBackgroundPaint = new Paint();
+ private final Paint mProgressPaint = new Paint();
+ private final Paint mSecondaryProgressPaint = new Paint();
+ private final Paint mThrobberPaint = new Paint();
+
+ private boolean mIsIndeterminate;
+ private int mProgress;
+ private int mSecondaryProgress;
+
+ public MaterialProgressBar(Context context) {
+ super(context);
+ initialize(context, null, 0);
+ }
+
+ public MaterialProgressBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initialize(context, attrs, 0);
+ }
+
+ public MaterialProgressBar(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ initialize(context, attrs, defStyle);
+ }
+
+ /** Sets the background color, corresponding to "chrome:colorBackground". */
+ @Override
+ public void setBackgroundColor(int color) {
+ mBackgroundPaint.setColor(color);
+ postInvalidateOnAnimation();
+ }
+
+ /** Sets the progress color, corresponding to "chrome:colorProgress". */
+ public void setProgressColor(int color) {
+ mProgressPaint.setColor(color);
+ postInvalidateOnAnimation();
+ }
+
+ /** Sets the secondary color, corresponding to "chrome:colorSecondaryProgress". */
+ public void setSecondaryProgressColor(int color) {
+ mSecondaryProgressPaint.setColor(color);
+ postInvalidateOnAnimation();
+ }
+
+ /** Sets the indeterminate throbber color, corresponding to "chrome:colorThrobber". */
+ public void setThrobberColor(int color) {
+ mThrobberPaint.setColor(color);
+ postInvalidateOnAnimation();
+ }
+
+ /**
+ * Sets the progress value being displayed.
+ * @param progress Progress value, ranging from 0 to 100. Will be clamped into the range.
+ */
+ public void setProgress(int progress) {
+ mProgress = Math.max(0, Math.min(100, progress));
+ postInvalidateOnAnimation();
+ }
+
+ /**
+ * Sets the secondary progress value being displayed.
+ * @param progress Progress value, ranging from 0 to 100. Will be clamped into the range.
+ */
+ public void setSecondaryProgress(int progress) {
+ mSecondaryProgress = Math.max(0, Math.min(100, progress));
+ postInvalidateOnAnimation();
+ }
+
+ /** Sets whether the progress bar is indeterminate or not. */
+ public void setIndeterminate(boolean indeterminate) {
+ if (mIsIndeterminate == indeterminate) return;
+ mIsIndeterminate = indeterminate;
+
+ if (mIsIndeterminate) startIndeterminateAnimation();
+ postInvalidateOnAnimation();
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+ if (visibility == View.VISIBLE) {
+ startIndeterminateAnimation();
+ } else {
+ stopIndeterminateAnimation();
+ }
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ postInvalidateOnAnimation();
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ if (mIsIndeterminate) {
+ drawIndeterminateBar(canvas);
+ } else {
+ drawDeterminateBar(canvas);
Ian Wen 2016/12/20 23:17:58 Not sure if we need to support determinate bar in
gone 2016/12/21 00:54:23 We could, but I'm going for an all encompassing so
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ startIndeterminateAnimation();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ stopIndeterminateAnimation();
+ }
+
+ private void initialize(Context context, AttributeSet attrs, int defStyle) {
+ Resources resources = context.getResources();
+ int backgroundColor =
+ ApiCompatibilityUtils.getColor(resources, R.color.progress_bar_background);
+ int progressColor =
+ ApiCompatibilityUtils.getColor(resources, R.color.progress_bar_foreground);
+ int secondaryProgressColor =
+ ApiCompatibilityUtils.getColor(resources, R.color.progress_bar_secondary);
+ int throbberColor =
+ ApiCompatibilityUtils.getColor(resources, R.color.progress_bar_default_throbber);
+
+ if (attrs != null) {
+ TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.MaterialProgressBar, defStyle, 0);
+ backgroundColor =
+ a.getColor(R.styleable.MaterialProgressBar_colorBackground, backgroundColor);
+ progressColor =
+ a.getColor(R.styleable.MaterialProgressBar_colorProgress, progressColor);
+ secondaryProgressColor = a.getColor(
+ R.styleable.MaterialProgressBar_colorSecondaryProgress, secondaryProgressColor);
+ throbberColor =
+ a.getColor(R.styleable.MaterialProgressBar_colorThrobber, throbberColor);
+ a.recycle();
+ }
+
+ setBackgroundColor(backgroundColor);
+ setProgressColor(progressColor);
+ setSecondaryProgressColor(secondaryProgressColor);
+ setThrobberColor(throbberColor);
+
+ mIndeterminateAnimator.setRepeatCount(ValueAnimator.INFINITE);
+ mIndeterminateAnimator.setDuration(INDETERMINATE_ANIMATION_DURATION_MS);
+ mIndeterminateAnimator.addUpdateListener(this);
+ }
+
+ private void startIndeterminateAnimation() {
+ if (!mIsIndeterminate || mIndeterminateAnimator.isRunning()) return;
+ if (!ViewCompat.isAttachedToWindow(this) || getVisibility() != View.VISIBLE) return;
+ mIndeterminateAnimator.start();
+ }
+
+ private void stopIndeterminateAnimation() {
+ if (!mIndeterminateAnimator.isRunning()) return;
+ mIndeterminateAnimator.cancel();
+ }
+
+ private void drawIndeterminateBar(Canvas canvas) {
+ int width = canvas.getWidth();
+ drawRect(canvas, mProgressPaint, 0, width);
+
+ // The first pulse fires off at the beginning of the animation.
+ float value = (Float) mIndeterminateAnimator.getAnimatedValue();
+ float left = width * (float) (Math.pow(value, 1.5f) - 0.5f);
+ float right = width * value;
+ drawRect(canvas, mThrobberPaint, left, right);
+
+ // The second pulse fires off at some point after the first pulse has been fired.
+ final float secondPulseStart = 1.1f;
+ final float secondPulseLength = 1.0f;
+ if (value >= secondPulseStart) {
+ float percentage = (value - secondPulseStart) / secondPulseLength;
+ left = width * (float) (Math.pow(percentage, 3.0f) - 0.1f);
+ right = width * percentage;
+ drawRect(canvas, mThrobberPaint, left, right);
+ }
+ }
+
+ private void drawDeterminateBar(Canvas canvas) {
+ int width = canvas.getWidth();
+ drawRect(canvas, mBackgroundPaint, 0, width);
+
+ if (mProgress > 0) {
+ float percentage = mProgress / 100.0f;
+ drawRect(canvas, mProgressPaint, 0, width * percentage);
+ }
+
+ if (mSecondaryProgress > 0) {
+ float percentage = mSecondaryProgress / 100.0f;
+ drawRect(canvas, mSecondaryProgressPaint, 0, width * percentage);
+ }
+ }
+
+ private void drawRect(Canvas canvas, Paint paint, float start, float end) {
+ if (ViewCompat.getLayoutDirection(this) == View.LAYOUT_DIRECTION_RTL) {
+ int width = canvas.getWidth();
+ float rtlStart = width - end;
+ float rtlEnd = width - start;
+ canvas.drawRect(rtlStart, 0, rtlEnd, canvas.getHeight(), paint);
+ } else {
+ canvas.drawRect(start, 0, end, canvas.getHeight(), paint);
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698