Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/widget/ClipDrawableProgressBar.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ClipDrawableProgressBar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ClipDrawableProgressBar.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..22d013c2c8dc09d7248cf4d2d61da5e5656e1fae |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ClipDrawableProgressBar.java |
| @@ -0,0 +1,237 @@ |
| +// Copyright 2015 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.content.Context; |
| +import android.content.res.TypedArray; |
| +import android.graphics.Color; |
| +import android.graphics.Rect; |
| +import android.graphics.drawable.ClipDrawable; |
| +import android.graphics.drawable.ColorDrawable; |
| +import android.util.AttributeSet; |
| +import android.view.Gravity; |
| +import android.widget.ImageView; |
| + |
| +import org.chromium.base.ApiCompatibilityUtils; |
| +import org.chromium.chrome.R; |
| + |
| +/** |
| + * An alternative progress bar implemented using ClipDrawable for simplicity and performance. |
| + */ |
| +public class ClipDrawableProgressBar extends ImageView { |
| + |
| + // ClipDrawable's max is a fixed constant 10000. |
| + // http://developer.android.com/reference/android/graphics/drawable/ClipDrawable.html |
| + private static final int CLIP_DRAWABLE_MAX = 10000; |
| + |
| + private final Rect mDirtyBound = new Rect(); |
| + private InvalidationListener mListener; |
| + private int mProgressBarColor = Color.TRANSPARENT; |
| + private int mBackgroundColor = Color.TRANSPARENT; |
| + private boolean mIsLastInvalidationProgressChange; |
| + private float mProgress; |
| + private int mDesiredVisibility; |
| + |
| + /** |
| + * Interface for listening to drawing invalidation. |
| + */ |
| + public interface InvalidationListener { |
| + /** |
| + * Called on drawing invalidation. |
| + * @param dirtyRect Invalidated area. |
| + */ |
| + void onInvalidation(Rect dirtyRect); |
| + } |
| + |
| + /** |
| + * Constructor for inflating from XML. |
| + */ |
| + public ClipDrawableProgressBar(Context context, AttributeSet attrs) { |
| + super(context, attrs); |
| + init(context, attrs, 0); |
| + } |
| + |
| + private void init(Context context, AttributeSet attrs, int defStyle) { |
| + mDesiredVisibility = getVisibility(); |
| + |
| + if (attrs != null) { |
|
Ted C
2015/07/15 02:41:12
shouldn't we assert that the attrs are non-null?
Kibeom Kim (inactive)
2015/07/15 11:22:45
Done. (I think fallback transparent background col
Ted C
2015/07/15 17:42:59
Agreed, a transparent background is fine.
|
| + TypedArray a = context.obtainStyledAttributes( |
| + attrs, R.styleable.ClipDrawableProgressBar, defStyle, 0); |
| + mProgressBarColor = a.getColor(R.styleable.ClipDrawableProgressBar_progressBarColor, 0); |
|
Ted C
2015/07/15 02:41:12
along with the comment about, use TRANSPARENT inst
Kibeom Kim (inactive)
2015/07/15 11:22:45
Done.
|
| + mBackgroundColor = a.getColor(R.styleable.ClipDrawableProgressBar_backgroundColor, 0); |
| + a.recycle(); |
| + } |
| + |
| + setImageDrawable(new ClipDrawable(new ColorDrawable(mProgressBarColor), Gravity.START, |
| + ClipDrawable.HORIZONTAL)); |
| + setBackgroundColor(mBackgroundColor); |
|
Ted C
2015/07/15 02:41:12
if background color is transparent, should we be s
Kibeom Kim (inactive)
2015/07/15 11:22:45
Hmm, from what I've read, it still sets ColorDrawa
|
| + } |
| + |
| + /** |
| + * Get the progress bar's current level of progress. |
| + * |
| + * @return The current progress, between 0.0 and 1.0. |
| + */ |
| + public float getProgress() { |
| + return mProgress; |
| + } |
| + |
| + /** |
| + * Set the current progress to the specified value. |
| + * |
| + * @param progress The new progress, between 0.0 and 1.0. |
| + */ |
| + public void setProgress(float progress) { |
| + assert 0.0f <= progress && progress <= 1.0f; |
| + |
|
Ted C
2015/07/15 02:41:12
early exit if mProgress == progress?
Kibeom Kim (inactive)
2015/07/15 11:22:45
Done.
|
| + float currentProgress = mProgress; |
| + mProgress = progress; |
| + getDrawable().setLevel(Math.round(progress * CLIP_DRAWABLE_MAX)); |
| + |
| + if (getVisibility() == VISIBLE && mListener != null) { |
| + if (mIsLastInvalidationProgressChange) { |
| + float left = Math.min(currentProgress, progress); |
| + float right = Math.max(currentProgress, progress); |
| + |
| + if (ApiCompatibilityUtils.isLayoutRtl(this)) { |
| + float leftTemp = left; |
| + left = 1.0f - right; |
| + right = 1.0f - leftTemp; |
| + } |
| + |
| + mDirtyBound.set((int) (left * getWidth()), 0, |
| + (int) Math.ceil(right * getWidth()), getHeight()); |
| + mListener.onInvalidation(mDirtyBound); |
| + } else { |
| + mListener.onInvalidation(null); |
| + } |
| + |
| + mIsLastInvalidationProgressChange = true; |
| + } |
| + } |
| + |
| + /** |
| + * @return Background color of this progress bar. |
| + */ |
| + public int getProgressBarBackgroundColor() { |
| + return mBackgroundColor; |
| + } |
| + |
| + /** |
| + * Sets background color of this progress bar. |
| + */ |
| + public void setProgressBarBackgroundColor(int color) { |
|
Ted C
2015/07/15 02:41:12
I would just override setBackgroundColor explicitl
Kibeom Kim (inactive)
2015/07/15 11:22:45
Done.
|
| + super.setBackgroundColor(color); |
| + mBackgroundColor = color; |
| + |
| + if (mListener != null && getVisibility() == VISIBLE) { |
| + mListener.onInvalidation(null); |
| + mIsLastInvalidationProgressChange = false; |
| + } |
| + } |
| + |
| + /** |
| + * Adds an observer to be notified of drawing invalidation. |
| + * |
| + * @param listener The observer to be added. |
| + */ |
| + public void setInvalidationListener(InvalidationListener listener) { |
| + mListener = listener; |
| + mIsLastInvalidationProgressChange = false; |
| + } |
| + |
| + /** |
| + * Get a rect that contains all the non-opaque pixels. |
| + * @param alphaBound Instance used to return the result. |
| + */ |
| + public void getAlphaBound(Rect alphaBound) { |
| + if (getAlpha() < 1.0f) { |
| + alphaBound.set(0, 0, getWidth(), getHeight()); |
| + return; |
| + } |
| + |
| + alphaBound.setEmpty(); |
| + if (Color.alpha(mBackgroundColor) < 255) { |
| + if (ApiCompatibilityUtils.isLayoutRtl(this)) { |
| + alphaBound.set(0, 0, (int) Math.ceil(mProgress * getWidth()), getHeight()); |
| + } else { |
| + alphaBound.set((int) (mProgress * getWidth()), 0, getWidth(), getHeight()); |
| + } |
| + } |
| + if (Color.alpha(mProgressBarColor) < 255) { |
| + if (ApiCompatibilityUtils.isLayoutRtl(this)) { |
| + alphaBound.union((int) (mProgress * getWidth()), 0, getWidth(), getHeight()); |
| + } else { |
| + alphaBound.union(0, 0, (int) Math.ceil(mProgress * getWidth()), getHeight()); |
| + } |
| + } |
| + |
| + return; |
| + } |
| + |
| + /** |
| + * @return Whether the actual internal visibility is changed. |
| + */ |
| + private boolean updateInternalVisibility() { |
| + int oldVisibility = getVisibility(); |
| + int newVisibility = mDesiredVisibility; |
| + if (getAlpha() == 0 && mDesiredVisibility == VISIBLE) { |
| + newVisibility = INVISIBLE; |
| + } |
| + |
| + if (oldVisibility != newVisibility) { |
| + super.setVisibility(newVisibility); |
| + if (mListener != null) { |
| + mListener.onInvalidation(null); |
| + mIsLastInvalidationProgressChange = false; |
| + } |
| + return true; |
| + } |
| + |
| + return false; |
| + } |
| + |
| + // View implementations. |
| + |
| + @Override |
| + public void setVisibility(int visibility) { |
|
Ted C
2015/07/15 02:41:12
probably worth adding a javadoc that this value wi
Kibeom Kim (inactive)
2015/07/15 11:22:46
Done.
|
| + mDesiredVisibility = visibility; |
| + updateInternalVisibility(); |
| + } |
| + |
| + @Override |
| + protected boolean onSetAlpha(int alpha) { |
| + boolean result = super.onSetAlpha(alpha); |
| + |
| + if (mListener != null && !updateInternalVisibility()) { |
| + mListener.onInvalidation(null); |
| + mIsLastInvalidationProgressChange = false; |
| + } |
| + |
| + return result; |
| + } |
| + |
| + @Override |
| + protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
| + super.onSizeChanged(w, h, oldw, oldh); |
| + |
| + if (mListener != null && getVisibility() == VISIBLE && (w != oldw || h != oldh)) { |
| + mListener.onInvalidation(null); |
| + mIsLastInvalidationProgressChange = false; |
| + } |
| + } |
| + |
| + @Override |
| + public void onRtlPropertiesChanged(int layoutDirection) { |
| + int currentLayoutDirection = ApiCompatibilityUtils.getLayoutDirection(this); |
| + super.onRtlPropertiesChanged(layoutDirection); |
| + |
| + if (mListener != null && getVisibility() == VISIBLE |
| + && currentLayoutDirection != layoutDirection) { |
| + mListener.onInvalidation(null); |
| + mIsLastInvalidationProgressChange = false; |
| + } |
| + } |
| +} |