/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.widget; import android.animation.ObjectAnimator; import android.annotation.InterpolatorRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.drawable.Animatable; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ClipDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.shapes.RoundRectShape; import android.graphics.drawable.shapes.Shape; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.MathUtils; import android.util.Pools.SynchronizedPool; import android.view.Gravity; import android.view.RemotableViewMethod; import android.view.View; import android.view.ViewDebug; import android.view.ViewHierarchyEncoder; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.LinearInterpolator; import android.view.animation.Transformation; import android.widget.RemoteViews.RemoteView; import com.android.internal.R; import java.util.ArrayList; /** *
* Visual indicator of progress in some operation. Displays a bar to the user * representing how far the operation has progressed; the application can * change the amount of progress (modifying the length of the bar) as it moves * forward. There is also a secondary progress displayable on a progress bar * which is useful for displaying intermediate progress, such as the buffer * level during a streaming playback progress bar. *
* ** A progress bar can also be made indeterminate. In indeterminate mode, the * progress bar shows a cyclic animation without an indication of progress. This mode is used by * applications when the length of the task is unknown. The indeterminate progress bar can be either * a spinning wheel or a horizontal bar. *
* *The following code example shows how a progress bar can be used from * a worker thread to update the user interface to notify the user of progress: *
* ** public class MyActivity extends Activity { * private static final int PROGRESS = 0x1; * * private ProgressBar mProgress; * private int mProgressStatus = 0; * * private Handler mHandler = new Handler(); * * protected void onCreate(Bundle icicle) { * super.onCreate(icicle); * * setContentView(R.layout.progressbar_activity); * * mProgress = (ProgressBar) findViewById(R.id.progress_bar); * * // Start lengthy operation in a background thread * new Thread(new Runnable() { * public void run() { * while (mProgressStatus < 100) { * mProgressStatus = doWork(); * * // Update the progress bar * mHandler.post(new Runnable() { * public void run() { * mProgress.setProgress(mProgressStatus); * } * }); * } * } * }).start(); * } * }* *
To add a progress bar to a layout file, you can use the {@code
* <ProgressBar * style="@android:style/Widget.ProgressBar.Horizontal" * ... />* *
If you will use the progress bar to show real progress, you must use the horizontal bar. You * can then increment the progress with {@link #incrementProgressBy incrementProgressBy()} or * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If * necessary, you can adjust the maximum value (the value for a full bar) using the {@link * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed * below.
* *Another common style to apply to the progress bar is {@link * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller * version of the spinning wheel—useful when waiting for content to load. * For example, you can insert this kind of progress bar into your default layout for * a view that will be populated by some content fetched from the Internet—the spinning wheel * appears immediately and when your application receives the content, it replaces the progress bar * with the loaded content. For example:
* ** <LinearLayout * android:orientation="horizontal" * ... > * <ProgressBar * android:layout_width="wrap_content" * android:layout_height="wrap_content" * style="@android:style/Widget.ProgressBar.Small" * android:layout_marginRight="5dp" /> * <TextView * android:layout_width="wrap_content" * android:layout_height="wrap_content" * android:text="@string/loading" /> * </LinearLayout>* *
Other progress bar styles provided by the system include:
*The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary * if your application uses a light colored theme (a white background).
* *XML attributes *
* See {@link android.R.styleable#ProgressBar ProgressBar Attributes}, * {@link android.R.styleable#View View Attributes} *
* * @attr ref android.R.styleable#ProgressBar_animationResolution * @attr ref android.R.styleable#ProgressBar_indeterminate * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable * @attr ref android.R.styleable#ProgressBar_indeterminateDuration * @attr ref android.R.styleable#ProgressBar_indeterminateOnly * @attr ref android.R.styleable#ProgressBar_interpolator * @attr ref android.R.styleable#ProgressBar_max * @attr ref android.R.styleable#ProgressBar_maxHeight * @attr ref android.R.styleable#ProgressBar_maxWidth * @attr ref android.R.styleable#ProgressBar_minHeight * @attr ref android.R.styleable#ProgressBar_minWidth * @attr ref android.R.styleable#ProgressBar_mirrorForRtl * @attr ref android.R.styleable#ProgressBar_progress * @attr ref android.R.styleable#ProgressBar_progressDrawable * @attr ref android.R.styleable#ProgressBar_secondaryProgress */ @RemoteView public class ProgressBar extends View { private static final int MAX_LEVEL = 10000; private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200; /** Interpolator used for smooth progress animations. */ private static final DecelerateInterpolator PROGRESS_ANIM_INTERPOLATOR = new DecelerateInterpolator(); /** Duration of smooth progress animations. */ private static final int PROGRESS_ANIM_DURATION = 80; int mMinWidth; int mMaxWidth; int mMinHeight; int mMaxHeight; private int mProgress; private int mSecondaryProgress; private int mMax; private int mBehavior; private int mDuration; private boolean mIndeterminate; private boolean mOnlyIndeterminate; private Transformation mTransformation; private AlphaAnimation mAnimation; private boolean mHasAnimation; private Drawable mIndeterminateDrawable; private Drawable mProgressDrawable; private Drawable mCurrentDrawable; private ProgressTintInfo mProgressTintInfo; Bitmap mSampleTile; private boolean mNoInvalidate; private Interpolator mInterpolator; private RefreshProgressRunnable mRefreshProgressRunnable; private long mUiThreadId; private boolean mShouldStartAnimationDrawable; private boolean mInDrawing; private boolean mAttached; private boolean mRefreshIsPosted; /** Value used to track progress animation, in the range [0...1]. */ private float mVisualProgress; boolean mMirrorForRtl = false; private boolean mAggregatedIsVisible; private final ArrayList* Initialize the progress bar's default values: *
*Indicate whether this progress bar is in indeterminate mode.
* * @return true if the progress bar is in indeterminate mode */ @ViewDebug.ExportedProperty(category = "progress") public synchronized boolean isIndeterminate() { return mIndeterminate; } /** *Change the indeterminate mode for this progress bar. In indeterminate * mode, the progress is ignored and the progress bar shows an infinite * animation instead.
* * If this progress bar's style only supports indeterminate mode (such as the circular * progress bars), then this will be ignored. * * @param indeterminate true to enable the indeterminate mode */ @android.view.RemotableViewMethod public synchronized void setIndeterminate(boolean indeterminate) { if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) { mIndeterminate = indeterminate; if (indeterminate) { // swap between indeterminate and regular backgrounds swapCurrentDrawable(mIndeterminateDrawable); startAnimation(); } else { swapCurrentDrawable(mProgressDrawable); stopAnimation(); } } } private void swapCurrentDrawable(Drawable newDrawable) { final Drawable oldDrawable = mCurrentDrawable; mCurrentDrawable = newDrawable; if (oldDrawable != mCurrentDrawable) { if (oldDrawable != null) { oldDrawable.setVisible(false, false); } if (mCurrentDrawable != null) { mCurrentDrawable.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); } } } /** *Get the drawable used to draw the progress bar in * indeterminate mode.
* * @return a {@link android.graphics.drawable.Drawable} instance * * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable) * @see #setIndeterminate(boolean) */ public Drawable getIndeterminateDrawable() { return mIndeterminateDrawable; } /** * Define the drawable used to draw the progress bar in indeterminate mode. * * @param d the new drawable * @see #getIndeterminateDrawable() * @see #setIndeterminate(boolean) */ public void setIndeterminateDrawable(Drawable d) { if (mIndeterminateDrawable != d) { if (mIndeterminateDrawable != null) { mIndeterminateDrawable.setCallback(null); unscheduleDrawable(mIndeterminateDrawable); } mIndeterminateDrawable = d; if (d != null) { d.setCallback(this); d.setLayoutDirection(getLayoutDirection()); if (d.isStateful()) { d.setState(getDrawableState()); } applyIndeterminateTint(); } if (mIndeterminate) { swapCurrentDrawable(d); postInvalidate(); } } } /** * Applies a tint to the indeterminate drawable. Does not modify the * current tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default. ** Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will * automatically mutate the drawable and apply the specified tint and * tint mode using * {@link Drawable#setTintList(ColorStateList)}. * * @param tint the tint to apply, may be {@code null} to clear tint * * @attr ref android.R.styleable#ProgressBar_indeterminateTint * @see #getIndeterminateTintList() * @see Drawable#setTintList(ColorStateList) */ @RemotableViewMethod public void setIndeterminateTintList(@Nullable ColorStateList tint) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); } mProgressTintInfo.mIndeterminateTintList = tint; mProgressTintInfo.mHasIndeterminateTint = true; applyIndeterminateTint(); } /** * @return the tint applied to the indeterminate drawable * @attr ref android.R.styleable#ProgressBar_indeterminateTint * @see #setIndeterminateTintList(ColorStateList) */ @Nullable public ColorStateList getIndeterminateTintList() { return mProgressTintInfo != null ? mProgressTintInfo.mIndeterminateTintList : null; } /** * Specifies the blending mode used to apply the tint specified by * {@link #setIndeterminateTintList(ColorStateList)} to the indeterminate * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. * * @param tintMode the blending mode used to apply the tint, may be * {@code null} to clear tint * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode * @see #setIndeterminateTintList(ColorStateList) * @see Drawable#setTintMode(PorterDuff.Mode) */ public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); } mProgressTintInfo.mIndeterminateTintMode = tintMode; mProgressTintInfo.mHasIndeterminateTintMode = true; applyIndeterminateTint(); } /** * Returns the blending mode used to apply the tint to the indeterminate * drawable, if specified. * * @return the blending mode used to apply the tint to the indeterminate * drawable * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode * @see #setIndeterminateTintMode(PorterDuff.Mode) */ @Nullable public PorterDuff.Mode getIndeterminateTintMode() { return mProgressTintInfo != null ? mProgressTintInfo.mIndeterminateTintMode : null; } private void applyIndeterminateTint() { if (mIndeterminateDrawable != null && mProgressTintInfo != null) { final ProgressTintInfo tintInfo = mProgressTintInfo; if (tintInfo.mHasIndeterminateTint || tintInfo.mHasIndeterminateTintMode) { mIndeterminateDrawable = mIndeterminateDrawable.mutate(); if (tintInfo.mHasIndeterminateTint) { mIndeterminateDrawable.setTintList(tintInfo.mIndeterminateTintList); } if (tintInfo.mHasIndeterminateTintMode) { mIndeterminateDrawable.setTintMode(tintInfo.mIndeterminateTintMode); } // The drawable (or one of its children) may not have been // stateful before applying the tint, so let's try again. if (mIndeterminateDrawable.isStateful()) { mIndeterminateDrawable.setState(getDrawableState()); } } } } /** * Define the tileable drawable used to draw the progress bar in * indeterminate mode. *
* If the drawable is a BitmapDrawable or contains BitmapDrawables, a * tiled copy will be generated for display as a progress bar. * * @param d the new drawable * @see #getIndeterminateDrawable() * @see #setIndeterminate(boolean) */ public void setIndeterminateDrawableTiled(Drawable d) { if (d != null) { d = tileifyIndeterminate(d); } setIndeterminateDrawable(d); } /** *
Get the drawable used to draw the progress bar in * progress mode.
* * @return a {@link android.graphics.drawable.Drawable} instance * * @see #setProgressDrawable(android.graphics.drawable.Drawable) * @see #setIndeterminate(boolean) */ public Drawable getProgressDrawable() { return mProgressDrawable; } /** * Define the drawable used to draw the progress bar in progress mode. * * @param d the new drawable * @see #getProgressDrawable() * @see #setIndeterminate(boolean) */ public void setProgressDrawable(Drawable d) { if (mProgressDrawable != d) { if (mProgressDrawable != null) { mProgressDrawable.setCallback(null); unscheduleDrawable(mProgressDrawable); } mProgressDrawable = d; if (d != null) { d.setCallback(this); d.setLayoutDirection(getLayoutDirection()); if (d.isStateful()) { d.setState(getDrawableState()); } // Make sure the ProgressBar is always tall enough int drawableHeight = d.getMinimumHeight(); if (mMaxHeight < drawableHeight) { mMaxHeight = drawableHeight; requestLayout(); } applyProgressTints(); } if (!mIndeterminate) { swapCurrentDrawable(d); postInvalidate(); } updateDrawableBounds(getWidth(), getHeight()); updateDrawableState(); doRefreshProgress(R.id.progress, mProgress, false, false, false); doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false, false); } } /** * Applies the progress tints in order of increasing specificity. */ private void applyProgressTints() { if (mProgressDrawable != null && mProgressTintInfo != null) { applyPrimaryProgressTint(); applyProgressBackgroundTint(); applySecondaryProgressTint(); } } /** * Should only be called if we've already verified that mProgressDrawable * and mProgressTintInfo are non-null. */ private void applyPrimaryProgressTint() { if (mProgressTintInfo.mHasProgressTint || mProgressTintInfo.mHasProgressTintMode) { final Drawable target = getTintTarget(R.id.progress, true); if (target != null) { if (mProgressTintInfo.mHasProgressTint) { target.setTintList(mProgressTintInfo.mProgressTintList); } if (mProgressTintInfo.mHasProgressTintMode) { target.setTintMode(mProgressTintInfo.mProgressTintMode); } // The drawable (or one of its children) may not have been // stateful before applying the tint, so let's try again. if (target.isStateful()) { target.setState(getDrawableState()); } } } } /** * Should only be called if we've already verified that mProgressDrawable * and mProgressTintInfo are non-null. */ private void applyProgressBackgroundTint() { if (mProgressTintInfo.mHasProgressBackgroundTint || mProgressTintInfo.mHasProgressBackgroundTintMode) { final Drawable target = getTintTarget(R.id.background, false); if (target != null) { if (mProgressTintInfo.mHasProgressBackgroundTint) { target.setTintList(mProgressTintInfo.mProgressBackgroundTintList); } if (mProgressTintInfo.mHasProgressBackgroundTintMode) { target.setTintMode(mProgressTintInfo.mProgressBackgroundTintMode); } // The drawable (or one of its children) may not have been // stateful before applying the tint, so let's try again. if (target.isStateful()) { target.setState(getDrawableState()); } } } } /** * Should only be called if we've already verified that mProgressDrawable * and mProgressTintInfo are non-null. */ private void applySecondaryProgressTint() { if (mProgressTintInfo.mHasSecondaryProgressTint || mProgressTintInfo.mHasSecondaryProgressTintMode) { final Drawable target = getTintTarget(R.id.secondaryProgress, false); if (target != null) { if (mProgressTintInfo.mHasSecondaryProgressTint) { target.setTintList(mProgressTintInfo.mSecondaryProgressTintList); } if (mProgressTintInfo.mHasSecondaryProgressTintMode) { target.setTintMode(mProgressTintInfo.mSecondaryProgressTintMode); } // The drawable (or one of its children) may not have been // stateful before applying the tint, so let's try again. if (target.isStateful()) { target.setState(getDrawableState()); } } } } /** * Applies a tint to the progress indicator, if one exists, or to the * entire progress drawable otherwise. Does not modify the current tint * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. ** The progress indicator should be specified as a layer with * id {@link android.R.id#progress} in a {@link LayerDrawable} * used as the progress drawable. *
* Subsequent calls to {@link #setProgressDrawable(Drawable)} will * automatically mutate the drawable and apply the specified tint and * tint mode using * {@link Drawable#setTintList(ColorStateList)}. * * @param tint the tint to apply, may be {@code null} to clear tint * * @attr ref android.R.styleable#ProgressBar_progressTint * @see #getProgressTintList() * @see Drawable#setTintList(ColorStateList) */ @RemotableViewMethod public void setProgressTintList(@Nullable ColorStateList tint) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); } mProgressTintInfo.mProgressTintList = tint; mProgressTintInfo.mHasProgressTint = true; if (mProgressDrawable != null) { applyPrimaryProgressTint(); } } /** * Returns the tint applied to the progress drawable, if specified. * * @return the tint applied to the progress drawable * @attr ref android.R.styleable#ProgressBar_progressTint * @see #setProgressTintList(ColorStateList) */ @Nullable public ColorStateList getProgressTintList() { return mProgressTintInfo != null ? mProgressTintInfo.mProgressTintList : null; } /** * Specifies the blending mode used to apply the tint specified by * {@link #setProgressTintList(ColorStateList)}} to the progress * indicator. The default mode is {@link PorterDuff.Mode#SRC_IN}. * * @param tintMode the blending mode used to apply the tint, may be * {@code null} to clear tint * @attr ref android.R.styleable#ProgressBar_progressTintMode * @see #getProgressTintMode() * @see Drawable#setTintMode(PorterDuff.Mode) */ public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); } mProgressTintInfo.mProgressTintMode = tintMode; mProgressTintInfo.mHasProgressTintMode = true; if (mProgressDrawable != null) { applyPrimaryProgressTint(); } } /** * Returns the blending mode used to apply the tint to the progress * drawable, if specified. * * @return the blending mode used to apply the tint to the progress * drawable * @attr ref android.R.styleable#ProgressBar_progressTintMode * @see #setProgressTintMode(PorterDuff.Mode) */ @Nullable public PorterDuff.Mode getProgressTintMode() { return mProgressTintInfo != null ? mProgressTintInfo.mProgressTintMode : null; } /** * Applies a tint to the progress background, if one exists. Does not * modify the current tint mode, which is * {@link PorterDuff.Mode#SRC_ATOP} by default. *
* The progress background must be specified as a layer with * id {@link android.R.id#background} in a {@link LayerDrawable} * used as the progress drawable. *
* Subsequent calls to {@link #setProgressDrawable(Drawable)} where the * drawable contains a progress background will automatically mutate the * drawable and apply the specified tint and tint mode using * {@link Drawable#setTintList(ColorStateList)}. * * @param tint the tint to apply, may be {@code null} to clear tint * * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint * @see #getProgressBackgroundTintList() * @see Drawable#setTintList(ColorStateList) */ @RemotableViewMethod public void setProgressBackgroundTintList(@Nullable ColorStateList tint) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); } mProgressTintInfo.mProgressBackgroundTintList = tint; mProgressTintInfo.mHasProgressBackgroundTint = true; if (mProgressDrawable != null) { applyProgressBackgroundTint(); } } /** * Returns the tint applied to the progress background, if specified. * * @return the tint applied to the progress background * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint * @see #setProgressBackgroundTintList(ColorStateList) */ @Nullable public ColorStateList getProgressBackgroundTintList() { return mProgressTintInfo != null ? mProgressTintInfo.mProgressBackgroundTintList : null; } /** * Specifies the blending mode used to apply the tint specified by * {@link #setProgressBackgroundTintList(ColorStateList)}} to the progress * background. The default mode is {@link PorterDuff.Mode#SRC_IN}. * * @param tintMode the blending mode used to apply the tint, may be * {@code null} to clear tint * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode * @see #setProgressBackgroundTintList(ColorStateList) * @see Drawable#setTintMode(PorterDuff.Mode) */ public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); } mProgressTintInfo.mProgressBackgroundTintMode = tintMode; mProgressTintInfo.mHasProgressBackgroundTintMode = true; if (mProgressDrawable != null) { applyProgressBackgroundTint(); } } /** * @return the blending mode used to apply the tint to the progress * background * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode * @see #setProgressBackgroundTintMode(PorterDuff.Mode) */ @Nullable public PorterDuff.Mode getProgressBackgroundTintMode() { return mProgressTintInfo != null ? mProgressTintInfo.mProgressBackgroundTintMode : null; } /** * Applies a tint to the secondary progress indicator, if one exists. * Does not modify the current tint mode, which is * {@link PorterDuff.Mode#SRC_ATOP} by default. *
* The secondary progress indicator must be specified as a layer with * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable} * used as the progress drawable. *
* Subsequent calls to {@link #setProgressDrawable(Drawable)} where the * drawable contains a secondary progress indicator will automatically * mutate the drawable and apply the specified tint and tint mode using * {@link Drawable#setTintList(ColorStateList)}. * * @param tint the tint to apply, may be {@code null} to clear tint * * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint * @see #getSecondaryProgressTintList() * @see Drawable#setTintList(ColorStateList) */ public void setSecondaryProgressTintList(@Nullable ColorStateList tint) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); } mProgressTintInfo.mSecondaryProgressTintList = tint; mProgressTintInfo.mHasSecondaryProgressTint = true; if (mProgressDrawable != null) { applySecondaryProgressTint(); } } /** * Returns the tint applied to the secondary progress drawable, if * specified. * * @return the tint applied to the secondary progress drawable * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint * @see #setSecondaryProgressTintList(ColorStateList) */ @Nullable public ColorStateList getSecondaryProgressTintList() { return mProgressTintInfo != null ? mProgressTintInfo.mSecondaryProgressTintList : null; } /** * Specifies the blending mode used to apply the tint specified by * {@link #setSecondaryProgressTintList(ColorStateList)}} to the secondary * progress indicator. The default mode is * {@link PorterDuff.Mode#SRC_ATOP}. * * @param tintMode the blending mode used to apply the tint, may be * {@code null} to clear tint * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode * @see #setSecondaryProgressTintList(ColorStateList) * @see Drawable#setTintMode(PorterDuff.Mode) */ public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); } mProgressTintInfo.mSecondaryProgressTintMode = tintMode; mProgressTintInfo.mHasSecondaryProgressTintMode = true; if (mProgressDrawable != null) { applySecondaryProgressTint(); } } /** * Returns the blending mode used to apply the tint to the secondary * progress drawable, if specified. * * @return the blending mode used to apply the tint to the secondary * progress drawable * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode * @see #setSecondaryProgressTintMode(PorterDuff.Mode) */ @Nullable public PorterDuff.Mode getSecondaryProgressTintMode() { return mProgressTintInfo != null ? mProgressTintInfo.mSecondaryProgressTintMode : null; } /** * Returns the drawable to which a tint or tint mode should be applied. * * @param layerId id of the layer to modify * @param shouldFallback whether the base drawable should be returned * if the id does not exist * @return the drawable to modify */ @Nullable private Drawable getTintTarget(int layerId, boolean shouldFallback) { Drawable layer = null; final Drawable d = mProgressDrawable; if (d != null) { mProgressDrawable = d.mutate(); if (d instanceof LayerDrawable) { layer = ((LayerDrawable) d).findDrawableByLayerId(layerId); } if (shouldFallback && layer == null) { layer = d; } } return layer; } /** * Define the tileable drawable used to draw the progress bar in * progress mode. *
* If the drawable is a BitmapDrawable or contains BitmapDrawables, a
* tiled copy will be generated for display as a progress bar.
*
* @param d the new drawable
* @see #getProgressDrawable()
* @see #setIndeterminate(boolean)
*/
public void setProgressDrawableTiled(Drawable d) {
if (d != null) {
d = tileify(d, false);
}
setProgressDrawable(d);
}
/**
* @return The drawable currently used to draw the progress bar
*/
Drawable getCurrentDrawable() {
return mCurrentDrawable;
}
@Override
protected boolean verifyDrawable(@NonNull Drawable who) {
return who == mProgressDrawable || who == mIndeterminateDrawable
|| super.verifyDrawable(who);
}
@Override
public void jumpDrawablesToCurrentState() {
super.jumpDrawablesToCurrentState();
if (mProgressDrawable != null) mProgressDrawable.jumpToCurrentState();
if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState();
}
/**
* @hide
*/
@Override
public void onResolveDrawables(int layoutDirection) {
final Drawable d = mCurrentDrawable;
if (d != null) {
d.setLayoutDirection(layoutDirection);
}
if (mIndeterminateDrawable != null) {
mIndeterminateDrawable.setLayoutDirection(layoutDirection);
}
if (mProgressDrawable != null) {
mProgressDrawable.setLayoutDirection(layoutDirection);
}
}
@Override
public void postInvalidate() {
if (!mNoInvalidate) {
super.postInvalidate();
}
}
private class RefreshProgressRunnable implements Runnable {
public void run() {
synchronized (ProgressBar.this) {
final int count = mRefreshData.size();
for (int i = 0; i < count; i++) {
final RefreshData rd = mRefreshData.get(i);
doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate);
rd.recycle();
}
mRefreshData.clear();
mRefreshIsPosted = false;
}
}
}
private static class RefreshData {
private static final int POOL_MAX = 24;
private static final SynchronizedPool
* This method will immediately update the visual position of the progress
* indicator. To animate the visual position to the target value, use
* {@link #setProgress(int, boolean)}}.
*
* @param progress the new progress, between 0 and {@link #getMax()}
*
* @see #setIndeterminate(boolean)
* @see #isIndeterminate()
* @see #getProgress()
* @see #incrementProgressBy(int)
*/
@android.view.RemotableViewMethod
public synchronized void setProgress(int progress) {
setProgressInternal(progress, false, false);
}
/**
* Sets the current progress to the specified value, optionally animating
* the visual position between the current and target values.
*
* Animation does not affect the result of {@link #getProgress()}, which
* will return the target value immediately after this method is called.
*
* @param progress the new progress value, between 0 and {@link #getMax()}
* @param animate {@code true} to animate between the current and target
* values or {@code false} to not animate
*/
public void setProgress(int progress, boolean animate) {
setProgressInternal(progress, false, animate);
}
@android.view.RemotableViewMethod
synchronized boolean setProgressInternal(int progress, boolean fromUser, boolean animate) {
if (mIndeterminate) {
// Not applicable.
return false;
}
progress = MathUtils.constrain(progress, 0, mMax);
if (progress == mProgress) {
// No change from current.
return false;
}
mProgress = progress;
refreshProgress(R.id.progress, mProgress, fromUser, animate);
return true;
}
/**
*
* Set the current secondary progress to the specified value. Does not do
* anything if the progress bar is in indeterminate mode.
* Get the progress bar's current level of progress. Return 0 when the
* progress bar is in indeterminate mode. Get the progress bar's current level of secondary progress. Return 0 when the
* progress bar is in indeterminate mode. Return the upper limit of this progress bar's range. Set the range of the progress bar to 0...max. Increase the progress bar's progress by the specified amount. Increase the progress bar's secondary progress by the specified amount. Start the indeterminate progress animation. Stop the indeterminate progress animation.