/* * 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.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; /** *
* A user interface element that indicates the progress of an operation. * Progress bar supports two modes to represent progress: determinate, and indeterminate. For * a visual overview of the difference between determinate and indeterminate progress modes, see * * Progress & activity. * Display progress bars to a user in a non-interruptive way. * Show the progress bar in your app's user interface or in a notification * instead of within a dialog. *
** Use indeterminate mode for the progress bar when you do not know how long an * operation will take. * Indeterminate mode is the default for progress bar and shows a cyclic animation without a * specific amount of progress indicated. * The following example shows an indeterminate progress bar: *
* <ProgressBar * android:id="@+id/indeterminateBar" * android:layout_width="wrap_content" * android:layout_height="wrap_content" * /> ** *
* Use determinate mode for the progress bar when you want to show that a specific quantity of * progress has occurred. * For example, the percent remaining of a file being retrieved, the amount records in * a batch written to database, or the percent remaining of an audio file that is playing. *
*
* To indicate determinate progress, you set the style of the progress bar to * {@link android.R.style#Widget_ProgressBar_Horizontal} and set the amount of progress. * The following example shows a determinate progress bar that is 25% complete: *
* <ProgressBar * android:id="@+id/determinateBar" * style="@android:style/Widget.ProgressBar.Horizontal" * android:layout_width="wrap_content" * android:layout_height="wrap_content" * android:progress="25"/> ** You can update the percentage of progress displayed by using the * {@link #setProgress(int)} method, or by calling * {@link #incrementProgressBy(int)} to increase the current progress completed * by a specified amount. * By default, the progress bar is full when the progress value reaches 100. * You can adjust this default by setting the * {@link android.R.styleable#ProgressBar_max android:max} attribute. * *
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_min * @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 mMin; private boolean mMinInitialized; private int mMax; private boolean mMaxInitialized; 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; int mSampleWidth = 0; 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); } } /** * @hide */ public boolean getMirrorForRtl() { return mMirrorForRtl; } /** * 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, mMin, 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 lower limit of this progress bar's range. Return the upper limit of this progress bar's range. Set the lower range of the progress bar to min. Set the upper range of the progress bar 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.