blob: 733a7753568a2955758e0ae948f54d6c873d6ae3 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.widget;
18
Alan Viverettea64ed3b2015-09-23 10:01:45 -040019import android.animation.ObjectAnimator;
Adam Powellc1bba9b2016-03-03 16:51:17 -080020import android.annotation.InterpolatorRes;
Siva Velusamy94a6d152015-05-05 15:07:00 -070021import android.annotation.NonNull;
Alan Viverette91174362014-06-17 14:51:45 -070022import android.annotation.Nullable;
Mihai Popacbc059d2019-02-05 18:35:29 +000023import android.annotation.Px;
Artur Satayeved5a6ae2019-12-10 17:47:54 +000024import android.compat.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Context;
Alan Viverette91174362014-06-17 14:51:45 -070026import android.content.res.ColorStateList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027import android.content.res.TypedArray;
Nader Jawad8e31c3e2019-04-14 21:58:04 -070028import android.graphics.BlendMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.graphics.Canvas;
Adam Powellc1bba9b2016-03-03 16:51:17 -080030import android.graphics.PorterDuff;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.Rect;
Steve Howardb25ffff2010-08-20 17:39:26 -070032import android.graphics.Shader;
33import android.graphics.drawable.Animatable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.graphics.drawable.AnimationDrawable;
35import android.graphics.drawable.BitmapDrawable;
36import android.graphics.drawable.ClipDrawable;
37import android.graphics.drawable.Drawable;
38import android.graphics.drawable.LayerDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.graphics.drawable.StateListDrawable;
40import android.graphics.drawable.shapes.RoundRectShape;
41import android.graphics.drawable.shapes.Shape;
Adam Powell84113362019-02-05 13:32:47 -080042import android.os.Build;
Steve Howardb25ffff2010-08-20 17:39:26 -070043import android.os.Parcel;
44import android.os.Parcelable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.util.AttributeSet;
Adam Powellc1bba9b2016-03-03 16:51:17 -080046import android.util.FloatProperty;
Alan Viverette12a44912015-04-16 13:06:00 -070047import android.util.MathUtils;
Svetoslav Ganovabae2a12012-11-27 16:59:37 -080048import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.view.Gravity;
Steve Howardb25ffff2010-08-20 17:39:26 -070050import android.view.RemotableViewMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.view.View;
Steve Zeigler7a367882010-02-23 16:39:08 -080052import android.view.ViewDebug;
Siva Velusamy94a6d152015-05-05 15:07:00 -070053import android.view.ViewHierarchyEncoder;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -070054import android.view.accessibility.AccessibilityEvent;
55import android.view.accessibility.AccessibilityManager;
Adam Powellc1bba9b2016-03-03 16:51:17 -080056import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.view.animation.AlphaAnimation;
58import android.view.animation.Animation;
59import android.view.animation.AnimationUtils;
Alan Viverettea64ed3b2015-09-23 10:01:45 -040060import android.view.animation.DecelerateInterpolator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.view.animation.Interpolator;
62import android.view.animation.LinearInterpolator;
63import android.view.animation.Transformation;
Ashley Rose55f9f922019-01-28 19:29:36 -050064import android.view.inspector.InspectableProperty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.widget.RemoteViews.RemoteView;
Aurimas Liutikas99441c52016-10-11 16:48:32 -070066
Adam Powellc1bba9b2016-03-03 16:51:17 -080067import com.android.internal.R;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068
yingleiw6ab02c12019-10-30 12:14:30 -070069import java.text.NumberFormat;
Adam Powella0506632012-04-10 17:19:20 -070070import java.util.ArrayList;
71
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072/**
73 * <p>
Joe Fernandez72a9d592017-04-25 22:58:34 -070074 * A user interface element that indicates the progress of an operation.
75 * Progress bar supports two modes to represent progress: determinate, and indeterminate. For
76 * a visual overview of the difference between determinate and indeterminate progress modes, see
77 * <a href="https://material.io/guidelines/components/progress-activity.html#progress-activity-types-of-indicators">
78 * Progress & activity</a>.
79 * Display progress bars to a user in a non-interruptive way.
80 * Show the progress bar in your app's user interface or in a notification
81 * instead of within a dialog.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 * </p>
Joe Fernandez72a9d592017-04-25 22:58:34 -070083 * <h3>Indeterminate Progress</h3>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 * <p>
Joe Fernandez72a9d592017-04-25 22:58:34 -070085 * Use indeterminate mode for the progress bar when you do not know how long an
86 * operation will take.
87 * Indeterminate mode is the default for progress bar and shows a cyclic animation without a
88 * specific amount of progress indicated.
89 * The following example shows an indeterminate progress bar:
Scott Main42f139c2011-04-29 10:31:10 -070090 * <pre>
91 * &lt;ProgressBar
Joe Fernandez72a9d592017-04-25 22:58:34 -070092 * android:id="@+id/indeterminateBar"
93 * android:layout_width="wrap_content"
94 * android:layout_height="wrap_content"
95 * /&gt;
96 * </pre>
97 * </p>
98 * <h3>Determinate Progress</h3>
99 * <p>
100 * Use determinate mode for the progress bar when you want to show that a specific quantity of
101 * progress has occurred.
102 * For example, the percent remaining of a file being retrieved, the amount records in
103 * a batch written to database, or the percent remaining of an audio file that is playing.
104 * <p>
105 * <p>
106 * To indicate determinate progress, you set the style of the progress bar to
107 * {@link android.R.style#Widget_ProgressBar_Horizontal} and set the amount of progress.
108 * The following example shows a determinate progress bar that is 25% complete:
Scott Main42f139c2011-04-29 10:31:10 -0700109 * <pre>
Joe Fernandez72a9d592017-04-25 22:58:34 -0700110 * &lt;ProgressBar
111 * android:id="@+id/determinateBar"
112 * style="@android:style/Widget.ProgressBar.Horizontal"
113 * android:layout_width="wrap_content"
114 * android:layout_height="wrap_content"
115 * android:progress="25"/&gt;
116 * </pre>
117 * You can update the percentage of progress displayed by using the
118 * {@link #setProgress(int)} method, or by calling
119 * {@link #incrementProgressBy(int)} to increase the current progress completed
120 * by a specified amount.
121 * By default, the progress bar is full when the progress value reaches 100.
122 * You can adjust this default by setting the
123 * {@link android.R.styleable#ProgressBar_max android:max} attribute.
124 * </p>
Scott Main42f139c2011-04-29 10:31:10 -0700125 * <p>Other progress bar styles provided by the system include:</p>
126 * <ul>
127 * <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li>
128 * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li>
129 * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li>
130 * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li>
131 * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse
132 * Widget.ProgressBar.Small.Inverse}</li>
133 * <li>{@link android.R.style#Widget_ProgressBar_Large_Inverse
134 * Widget.ProgressBar.Large.Inverse}</li>
135 * </ul>
136 * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
137 * if your application uses a light colored theme (a white background).</p>
RoboErik5b071432015-02-11 13:52:05 -0800138 *
139 * <p><strong>XML attributes</b></strong>
140 * <p>
141 * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 * {@link android.R.styleable#View View Attributes}
143 * </p>
RoboErik5b071432015-02-11 13:52:05 -0800144 *
Scott Main42f139c2011-04-29 10:31:10 -0700145 * @attr ref android.R.styleable#ProgressBar_animationResolution
146 * @attr ref android.R.styleable#ProgressBar_indeterminate
147 * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
148 * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
149 * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
150 * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
151 * @attr ref android.R.styleable#ProgressBar_interpolator
Keyvan Amiri86fb2a22016-09-29 17:53:24 -0700152 * @attr ref android.R.styleable#ProgressBar_min
Scott Main42f139c2011-04-29 10:31:10 -0700153 * @attr ref android.R.styleable#ProgressBar_max
154 * @attr ref android.R.styleable#ProgressBar_maxHeight
155 * @attr ref android.R.styleable#ProgressBar_maxWidth
156 * @attr ref android.R.styleable#ProgressBar_minHeight
157 * @attr ref android.R.styleable#ProgressBar_minWidth
Scott Mainb40c1fd2013-04-23 13:30:06 -0700158 * @attr ref android.R.styleable#ProgressBar_mirrorForRtl
Scott Main42f139c2011-04-29 10:31:10 -0700159 * @attr ref android.R.styleable#ProgressBar_progress
160 * @attr ref android.R.styleable#ProgressBar_progressDrawable
161 * @attr ref android.R.styleable#ProgressBar_secondaryProgress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 */
163@RemoteView
164public class ProgressBar extends View {
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 private static final int MAX_LEVEL = 10000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400168 /** Interpolator used for smooth progress animations. */
169 private static final DecelerateInterpolator PROGRESS_ANIM_INTERPOLATOR =
170 new DecelerateInterpolator();
171
172 /** Duration of smooth progress animations. */
173 private static final int PROGRESS_ANIM_DURATION = 80;
174
Mihai Popacbc059d2019-02-05 18:35:29 +0000175 /**
176 * Outside the framework, please use {@link ProgressBar#getMinWidth()} and
177 * {@link ProgressBar#setMinWidth(int)} instead of accessing these directly.
178 */
179 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 int mMinWidth;
181 int mMaxWidth;
Mihai Popacbc059d2019-02-05 18:35:29 +0000182 /**
183 * Outside the framework, please use {@link ProgressBar#getMinHeight()} and
184 * {@link ProgressBar#setMinHeight(int)} instead of accessing these directly.
185 */
186 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 int mMinHeight;
Mihai Popacbc059d2019-02-05 18:35:29 +0000188 /**
189 * Outside the framework, please use {@link ProgressBar#getMaxHeight()} ()} and
190 * {@link ProgressBar#setMaxHeight(int)} (int)} instead of accessing these directly.
191 */
192 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 int mMaxHeight;
194
195 private int mProgress;
196 private int mSecondaryProgress;
Keyvan Amiri86fb2a22016-09-29 17:53:24 -0700197 private int mMin;
198 private boolean mMinInitialized;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 private int mMax;
Keyvan Amiri86fb2a22016-09-29 17:53:24 -0700200 private boolean mMaxInitialized;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201
202 private int mBehavior;
shepshapard3b070452019-02-08 16:54:55 -0800203 // Better to define a Drawable that implements Animatable if you want to modify animation
204 // characteristics programatically.
205 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124052713)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 private int mDuration;
Adam Powell84113362019-02-05 13:32:47 -0800207 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 private boolean mIndeterminate;
Sumir Kataria08b675372019-02-08 11:31:22 -0800209 @UnsupportedAppUsage(trackingBug = 124049927)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 private boolean mOnlyIndeterminate;
211 private Transformation mTransformation;
212 private AlphaAnimation mAnimation;
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700213 private boolean mHasAnimation;
Alan Viverette91174362014-06-17 14:51:45 -0700214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 private Drawable mIndeterminateDrawable;
216 private Drawable mProgressDrawable;
Mihai Popa3df49262019-02-06 12:35:29 +0000217 /**
218 * Outside the framework, instead of accessing this directly, please use
219 * {@link #getCurrentDrawable()}, {@link #setProgressDrawable(Drawable)},
220 * {@link #setIndeterminateDrawable(Drawable)} and their tiled versions.
221 */
222 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 private Drawable mCurrentDrawable;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700224 private ProgressTintInfo mProgressTintInfo;
225
Alan Viverette0d2a46b2016-10-07 16:23:32 -0400226 int mSampleWidth = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 private boolean mNoInvalidate;
228 private Interpolator mInterpolator;
229 private RefreshProgressRunnable mRefreshProgressRunnable;
230 private long mUiThreadId;
231 private boolean mShouldStartAnimationDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
233 private boolean mInDrawing;
Adam Powella0506632012-04-10 17:19:20 -0700234 private boolean mAttached;
235 private boolean mRefreshIsPosted;
236
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400237 /** Value used to track progress animation, in the range [0...1]. */
238 private float mVisualProgress;
239
Mathew Inwood978c6e22018-08-21 15:58:55 +0100240 @UnsupportedAppUsage
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800241 boolean mMirrorForRtl = false;
242
Adam Powell41d96902016-03-15 14:43:19 -0700243 private boolean mAggregatedIsVisible;
244
yingleiw6ab02c12019-10-30 12:14:30 -0700245 private CharSequence mCustomStateDescription = null;
246
Adam Powella0506632012-04-10 17:19:20 -0700247 private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248
249 /**
250 * Create a new progress bar with range 0...100 and initial progress of 0.
251 * @param context the application environment
252 */
253 public ProgressBar(Context context) {
254 this(context, null);
255 }
RoboErik5b071432015-02-11 13:52:05 -0800256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 public ProgressBar(Context context, AttributeSet attrs) {
258 this(context, attrs, com.android.internal.R.attr.progressBarStyle);
259 }
260
Alan Viverette617feb92013-09-09 18:09:13 -0700261 public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
262 this(context, attrs, defStyleAttr, 0);
Adam Powell6af97e12010-11-11 21:11:53 -0800263 }
264
Alan Viverette617feb92013-09-09 18:09:13 -0700265 public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
266 super(context, attrs, defStyleAttr, defStyleRes);
267
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 mUiThreadId = Thread.currentThread().getId();
269 initProgressBar();
270
Alan Viverette617feb92013-09-09 18:09:13 -0700271 final TypedArray a = context.obtainStyledAttributes(
272 attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
Aurimas Liutikasab324cf2019-02-07 16:46:38 -0800273 saveAttributeDataForStyleable(context, R.styleable.ProgressBar,
274 attrs, a, defStyleAttr, defStyleRes);
RoboErik5b071432015-02-11 13:52:05 -0800275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 mNoInvalidate = true;
RoboErik5b071432015-02-11 13:52:05 -0800277
Alan Viverette91174362014-06-17 14:51:45 -0700278 final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
279 if (progressDrawable != null) {
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700280 // Calling setProgressDrawable can set mMaxHeight, so make sure the
281 // corresponding XML attribute for mMaxHeight is read after calling
282 // this method.
283 if (needsTileify(progressDrawable)) {
284 setProgressDrawableTiled(progressDrawable);
285 } else {
286 setProgressDrawable(progressDrawable);
287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 }
289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 mDuration = a.getInt(R.styleable.ProgressBar_indeterminateDuration, mDuration);
291
292 mMinWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_minWidth, mMinWidth);
293 mMaxWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_maxWidth, mMaxWidth);
294 mMinHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_minHeight, mMinHeight);
295 mMaxHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_maxHeight, mMaxHeight);
296
297 mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);
298
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700299 final int resID = a.getResourceId(
RoboErik5b071432015-02-11 13:52:05 -0800300 com.android.internal.R.styleable.ProgressBar_interpolator,
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700301 android.R.anim.linear_interpolator); // default to linear interpolator
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 if (resID > 0) {
303 setInterpolator(context, resID);
RoboErik5b071432015-02-11 13:52:05 -0800304 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305
Keyvan Amiri86fb2a22016-09-29 17:53:24 -0700306 setMin(a.getInt(R.styleable.ProgressBar_min, mMin));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
308
309 setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
310
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700311 setSecondaryProgress(a.getInt(
312 R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313
Alan Viverette91174362014-06-17 14:51:45 -0700314 final Drawable indeterminateDrawable = a.getDrawable(
315 R.styleable.ProgressBar_indeterminateDrawable);
316 if (indeterminateDrawable != null) {
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700317 if (needsTileify(indeterminateDrawable)) {
318 setIndeterminateDrawableTiled(indeterminateDrawable);
319 } else {
320 setIndeterminateDrawable(indeterminateDrawable);
321 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 }
323
324 mOnlyIndeterminate = a.getBoolean(
325 R.styleable.ProgressBar_indeterminateOnly, mOnlyIndeterminate);
326
327 mNoInvalidate = false;
328
329 setIndeterminate(mOnlyIndeterminate || a.getBoolean(
330 R.styleable.ProgressBar_indeterminate, mIndeterminate));
331
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800332 mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);
333
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700334 if (a.hasValue(R.styleable.ProgressBar_progressTintMode)) {
335 if (mProgressTintInfo == null) {
336 mProgressTintInfo = new ProgressTintInfo();
337 }
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700338 mProgressTintInfo.mProgressBlendMode = Drawable.parseBlendMode(a.getInt(
Alan Viverettedbc40182015-04-06 15:01:23 -0700339 R.styleable.ProgressBar_progressTintMode, -1), null);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700340 mProgressTintInfo.mHasProgressTintMode = true;
341 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700342
Alan Viverette91174362014-06-17 14:51:45 -0700343 if (a.hasValue(R.styleable.ProgressBar_progressTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700344 if (mProgressTintInfo == null) {
345 mProgressTintInfo = new ProgressTintInfo();
346 }
347 mProgressTintInfo.mProgressTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700348 R.styleable.ProgressBar_progressTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700349 mProgressTintInfo.mHasProgressTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700350 }
351
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700352 if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTintMode)) {
353 if (mProgressTintInfo == null) {
354 mProgressTintInfo = new ProgressTintInfo();
355 }
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700356 mProgressTintInfo.mProgressBackgroundBlendMode = Drawable.parseBlendMode(a.getInt(
Alan Viverettedbc40182015-04-06 15:01:23 -0700357 R.styleable.ProgressBar_progressBackgroundTintMode, -1), null);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700358 mProgressTintInfo.mHasProgressBackgroundTintMode = true;
359 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700360
Alan Viverette91174362014-06-17 14:51:45 -0700361 if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700362 if (mProgressTintInfo == null) {
363 mProgressTintInfo = new ProgressTintInfo();
364 }
365 mProgressTintInfo.mProgressBackgroundTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700366 R.styleable.ProgressBar_progressBackgroundTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700367 mProgressTintInfo.mHasProgressBackgroundTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700368 }
369
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700370 if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTintMode)) {
371 if (mProgressTintInfo == null) {
372 mProgressTintInfo = new ProgressTintInfo();
373 }
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700374 mProgressTintInfo.mSecondaryProgressBlendMode = Drawable.parseBlendMode(
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700375 a.getInt(R.styleable.ProgressBar_secondaryProgressTintMode, -1), null);
376 mProgressTintInfo.mHasSecondaryProgressTintMode = true;
377 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700378
Alan Viverette91174362014-06-17 14:51:45 -0700379 if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700380 if (mProgressTintInfo == null) {
381 mProgressTintInfo = new ProgressTintInfo();
382 }
383 mProgressTintInfo.mSecondaryProgressTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700384 R.styleable.ProgressBar_secondaryProgressTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700385 mProgressTintInfo.mHasSecondaryProgressTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700386 }
387
Alan Viverettedbc40182015-04-06 15:01:23 -0700388 if (a.hasValue(R.styleable.ProgressBar_indeterminateTintMode)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700389 if (mProgressTintInfo == null) {
390 mProgressTintInfo = new ProgressTintInfo();
391 }
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700392 mProgressTintInfo.mIndeterminateBlendMode = Drawable.parseBlendMode(a.getInt(
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700393 R.styleable.ProgressBar_indeterminateTintMode, -1), null);
394 mProgressTintInfo.mHasIndeterminateTintMode = true;
395 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700396
Alan Viverette91174362014-06-17 14:51:45 -0700397 if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700398 if (mProgressTintInfo == null) {
399 mProgressTintInfo = new ProgressTintInfo();
400 }
401 mProgressTintInfo.mIndeterminateTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700402 R.styleable.ProgressBar_indeterminateTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700403 mProgressTintInfo.mHasIndeterminateTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700404 }
405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 a.recycle();
Svetoslav7face752014-01-13 15:25:58 -0800407
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700408 applyProgressTints();
409 applyIndeterminateTint();
410
Svetoslav7face752014-01-13 15:25:58 -0800411 // If not explicitly specified this view is important for accessibility.
412 if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
413 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 }
416
417 /**
Mihai Popacbc059d2019-02-05 18:35:29 +0000418 * Sets the minimum width the progress bar can have.
419 * @param minWidth the minimum width to be set, in pixels
420 * @attr ref android.R.styleable#ProgressBar_minWidth
421 */
422 public void setMinWidth(@Px int minWidth) {
423 mMinWidth = minWidth;
424 requestLayout();
425 }
426
427 /**
428 * @return the minimum width the progress bar can have, in pixels
429 */
430 @Px public int getMinWidth() {
431 return mMinWidth;
432 }
433
434 /**
435 * Sets the maximum width the progress bar can have.
436 * @param maxWidth the maximum width to be set, in pixels
437 * @attr ref android.R.styleable#ProgressBar_maxWidth
438 */
439 public void setMaxWidth(@Px int maxWidth) {
440 mMaxWidth = maxWidth;
441 requestLayout();
442 }
443
444 /**
445 * @return the maximum width the progress bar can have, in pixels
446 */
447 @Px public int getMaxWidth() {
448 return mMaxWidth;
449 }
450
451 /**
452 * Sets the minimum height the progress bar can have.
453 * @param minHeight the minimum height to be set, in pixels
454 * @attr ref android.R.styleable#ProgressBar_minHeight
455 */
456 public void setMinHeight(@Px int minHeight) {
457 mMinHeight = minHeight;
458 requestLayout();
459 }
460
461 /**
462 * @return the minimum height the progress bar can have, in pixels
463 */
464 @Px public int getMinHeight() {
465 return mMinHeight;
466 }
467
468 /**
469 * Sets the maximum height the progress bar can have.
470 * @param maxHeight the maximum height to be set, in pixels
471 * @attr ref android.R.styleable#ProgressBar_maxHeight
472 */
473 public void setMaxHeight(@Px int maxHeight) {
474 mMaxHeight = maxHeight;
475 requestLayout();
476 }
477
478 /**
479 * @return the maximum height the progress bar can have, in pixels
480 */
481 @Px public int getMaxHeight() {
482 return mMaxHeight;
483 }
484
485 /**
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700486 * Returns {@code true} if the target drawable needs to be tileified.
487 *
488 * @param dr the drawable to check
489 * @return {@code true} if the target drawable needs to be tileified,
490 * {@code false} otherwise
491 */
492 private static boolean needsTileify(Drawable dr) {
493 if (dr instanceof LayerDrawable) {
494 final LayerDrawable orig = (LayerDrawable) dr;
495 final int N = orig.getNumberOfLayers();
496 for (int i = 0; i < N; i++) {
497 if (needsTileify(orig.getDrawable(i))) {
498 return true;
499 }
500 }
501 return false;
502 }
503
504 if (dr instanceof StateListDrawable) {
505 final StateListDrawable in = (StateListDrawable) dr;
506 final int N = in.getStateCount();
507 for (int i = 0; i < N; i++) {
508 if (needsTileify(in.getStateDrawable(i))) {
509 return true;
510 }
511 }
512 return false;
513 }
514
515 // If there's a bitmap that's not wrapped with a ClipDrawable or
516 // ScaleDrawable, we'll need to wrap it and apply tiling.
517 if (dr instanceof BitmapDrawable) {
518 return true;
519 }
520
521 return false;
522 }
523
524 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 * Converts a drawable to a tiled version of itself. It will recursively
526 * traverse layer and state list drawables.
527 */
Mathew Inwood978c6e22018-08-21 15:58:55 +0100528 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 private Drawable tileify(Drawable drawable, boolean clip) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800530 // TODO: This is a terrible idea that potentially destroys any drawable
531 // that extends any of these classes. We *really* need to remove this.
RoboErik5b071432015-02-11 13:52:05 -0800532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 if (drawable instanceof LayerDrawable) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800534 final LayerDrawable orig = (LayerDrawable) drawable;
535 final int N = orig.getNumberOfLayers();
536 final Drawable[] outDrawables = new Drawable[N];
RoboErik5b071432015-02-11 13:52:05 -0800537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 for (int i = 0; i < N; i++) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800539 final int id = orig.getId(i);
540 outDrawables[i] = tileify(orig.getDrawable(i),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 (id == R.id.progress || id == R.id.secondaryProgress));
542 }
543
Alan Viverette6a8253f2015-02-23 12:49:47 -0800544 final LayerDrawable clone = new LayerDrawable(outDrawables);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 for (int i = 0; i < N; i++) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800546 clone.setId(i, orig.getId(i));
547 clone.setLayerGravity(i, orig.getLayerGravity(i));
548 clone.setLayerWidth(i, orig.getLayerWidth(i));
549 clone.setLayerHeight(i, orig.getLayerHeight(i));
550 clone.setLayerInsetLeft(i, orig.getLayerInsetLeft(i));
551 clone.setLayerInsetRight(i, orig.getLayerInsetRight(i));
552 clone.setLayerInsetTop(i, orig.getLayerInsetTop(i));
553 clone.setLayerInsetBottom(i, orig.getLayerInsetBottom(i));
554 clone.setLayerInsetStart(i, orig.getLayerInsetStart(i));
555 clone.setLayerInsetEnd(i, orig.getLayerInsetEnd(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 }
RoboErik5b071432015-02-11 13:52:05 -0800557
Alan Viverette6a8253f2015-02-23 12:49:47 -0800558 return clone;
559 }
RoboErik5b071432015-02-11 13:52:05 -0800560
Alan Viverette6a8253f2015-02-23 12:49:47 -0800561 if (drawable instanceof StateListDrawable) {
562 final StateListDrawable in = (StateListDrawable) drawable;
563 final StateListDrawable out = new StateListDrawable();
564 final int N = in.getStateCount();
565 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
567 }
RoboErik5b071432015-02-11 13:52:05 -0800568
Alan Viverette6a8253f2015-02-23 12:49:47 -0800569 return out;
570 }
571
572 if (drawable instanceof BitmapDrawable) {
Alan Viverette0d2a46b2016-10-07 16:23:32 -0400573 final Drawable.ConstantState cs = drawable.getConstantState();
574 final BitmapDrawable clone = (BitmapDrawable) cs.newDrawable(getResources());
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700575 clone.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576
Alan Viverette0d2a46b2016-10-07 16:23:32 -0400577 if (mSampleWidth <= 0) {
578 mSampleWidth = clone.getIntrinsicWidth();
579 }
580
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700581 if (clip) {
582 return new ClipDrawable(clone, Gravity.LEFT, ClipDrawable.HORIZONTAL);
583 } else {
584 return clone;
585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 }
RoboErik5b071432015-02-11 13:52:05 -0800587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 return drawable;
589 }
590
591 Shape getDrawableShape() {
592 final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
593 return new RoundRectShape(roundedCorners, null, null);
594 }
RoboErik5b071432015-02-11 13:52:05 -0800595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 /**
597 * Convert a AnimationDrawable for use as a barberpole animation.
598 * Each frame of the animation is wrapped in a ClipDrawable and
599 * given a tiling BitmapShader.
600 */
601 private Drawable tileifyIndeterminate(Drawable drawable) {
602 if (drawable instanceof AnimationDrawable) {
603 AnimationDrawable background = (AnimationDrawable) drawable;
604 final int N = background.getNumberOfFrames();
605 AnimationDrawable newBg = new AnimationDrawable();
606 newBg.setOneShot(background.isOneShot());
RoboErik5b071432015-02-11 13:52:05 -0800607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 for (int i = 0; i < N; i++) {
609 Drawable frame = tileify(background.getFrame(i), true);
610 frame.setLevel(10000);
611 newBg.addFrame(frame, background.getDuration(i));
612 }
613 newBg.setLevel(10000);
614 drawable = newBg;
615 }
616 return drawable;
617 }
RoboErik5b071432015-02-11 13:52:05 -0800618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 /**
620 * <p>
621 * Initialize the progress bar's default values:
622 * </p>
623 * <ul>
624 * <li>progress = 0</li>
625 * <li>max = 100</li>
626 * <li>animation duration = 4000 ms</li>
627 * <li>indeterminate = false</li>
628 * <li>behavior = repeat</li>
629 * </ul>
630 */
631 private void initProgressBar() {
Keyvan Amiri86fb2a22016-09-29 17:53:24 -0700632 mMin = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 mMax = 100;
634 mProgress = 0;
635 mSecondaryProgress = 0;
636 mIndeterminate = false;
637 mOnlyIndeterminate = false;
638 mDuration = 4000;
639 mBehavior = AlphaAnimation.RESTART;
640 mMinWidth = 24;
641 mMaxWidth = 48;
642 mMinHeight = 24;
643 mMaxHeight = 48;
644 }
645
646 /**
647 * <p>Indicate whether this progress bar is in indeterminate mode.</p>
648 *
649 * @return true if the progress bar is in indeterminate mode
650 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500651 @InspectableProperty
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700652 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 public synchronized boolean isIndeterminate() {
654 return mIndeterminate;
655 }
656
657 /**
658 * <p>Change the indeterminate mode for this progress bar. In indeterminate
659 * mode, the progress is ignored and the progress bar shows an infinite
660 * animation instead.</p>
RoboErik5b071432015-02-11 13:52:05 -0800661 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 * If this progress bar's style only supports indeterminate mode (such as the circular
663 * progress bars), then this will be ignored.
664 *
665 * @param indeterminate true to enable the indeterminate mode
666 */
667 @android.view.RemotableViewMethod
668 public synchronized void setIndeterminate(boolean indeterminate) {
669 if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
670 mIndeterminate = indeterminate;
671
672 if (indeterminate) {
673 // swap between indeterminate and regular backgrounds
Adam Powellc1bba9b2016-03-03 16:51:17 -0800674 swapCurrentDrawable(mIndeterminateDrawable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 startAnimation();
676 } else {
Adam Powellc1bba9b2016-03-03 16:51:17 -0800677 swapCurrentDrawable(mProgressDrawable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 stopAnimation();
679 }
680 }
681 }
682
Adam Powellc1bba9b2016-03-03 16:51:17 -0800683 private void swapCurrentDrawable(Drawable newDrawable) {
684 final Drawable oldDrawable = mCurrentDrawable;
685 mCurrentDrawable = newDrawable;
Adam Powell9c146bf2016-03-15 17:35:00 -0700686
Adam Powellc1bba9b2016-03-03 16:51:17 -0800687 if (oldDrawable != mCurrentDrawable) {
688 if (oldDrawable != null) {
689 oldDrawable.setVisible(false, false);
690 }
691 if (mCurrentDrawable != null) {
Adam Powell41d96902016-03-15 14:43:19 -0700692 mCurrentDrawable.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
Adam Powellc1bba9b2016-03-03 16:51:17 -0800693 }
694 }
695 }
696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800697 /**
698 * <p>Get the drawable used to draw the progress bar in
699 * indeterminate mode.</p>
700 *
701 * @return a {@link android.graphics.drawable.Drawable} instance
702 *
703 * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable)
704 * @see #setIndeterminate(boolean)
705 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500706 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 public Drawable getIndeterminateDrawable() {
708 return mIndeterminateDrawable;
709 }
710
711 /**
Alan Viverettee785d022013-09-26 15:21:10 -0700712 * Define the drawable used to draw the progress bar in indeterminate mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 *
shepshapard3b070452019-02-08 16:54:55 -0800714 * <p>For the Drawable to animate, it must implement {@link Animatable}, or override
715 * {@link Drawable#onLevelChange(int)}. A Drawable that implements Animatable will be animated
716 * via that interface and therefore provides the greatest amount of customization. A Drawable
717 * that only overrides onLevelChange(int) is animated directly by ProgressBar and only the
718 * animation {@link android.R.styleable#ProgressBar_indeterminateDuration duration},
719 * {@link android.R.styleable#ProgressBar_indeterminateBehavior repeating behavior}, and
720 * {@link #setInterpolator(Interpolator) interpolator} can be modified, and only before the
721 * indeterminate animation begins.
722 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 * @param d the new drawable
shepshapard3b070452019-02-08 16:54:55 -0800724 * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 * @see #getIndeterminateDrawable()
726 * @see #setIndeterminate(boolean)
727 */
728 public void setIndeterminateDrawable(Drawable d) {
Alan Viverette91174362014-06-17 14:51:45 -0700729 if (mIndeterminateDrawable != d) {
730 if (mIndeterminateDrawable != null) {
731 mIndeterminateDrawable.setCallback(null);
732 unscheduleDrawable(mIndeterminateDrawable);
733 }
734
735 mIndeterminateDrawable = d;
736
737 if (d != null) {
738 d.setCallback(this);
739 d.setLayoutDirection(getLayoutDirection());
740 if (d.isStateful()) {
741 d.setState(getDrawableState());
742 }
743 applyIndeterminateTint();
744 }
745
746 if (mIndeterminate) {
Adam Powellc1bba9b2016-03-03 16:51:17 -0800747 swapCurrentDrawable(d);
Alan Viverette91174362014-06-17 14:51:45 -0700748 postInvalidate();
749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 }
Alan Viverette91174362014-06-17 14:51:45 -0700751 }
752
753 /**
Alan Viverette91174362014-06-17 14:51:45 -0700754 * Applies a tint to the indeterminate drawable. Does not modify the
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700755 * current tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -0700756 * <p>
757 * Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will
758 * automatically mutate the drawable and apply the specified tint and
759 * tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700760 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -0700761 *
762 * @param tint the tint to apply, may be {@code null} to clear tint
763 *
764 * @attr ref android.R.styleable#ProgressBar_indeterminateTint
Alan Viverettea4264452014-07-28 16:02:55 -0700765 * @see #getIndeterminateTintList()
766 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700767 */
Jorim Jaggief72a192014-08-26 21:57:46 +0200768 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -0700769 public void setIndeterminateTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700770 if (mProgressTintInfo == null) {
771 mProgressTintInfo = new ProgressTintInfo();
772 }
773 mProgressTintInfo.mIndeterminateTintList = tint;
774 mProgressTintInfo.mHasIndeterminateTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700775
776 applyIndeterminateTint();
Alan Viverette91174362014-06-17 14:51:45 -0700777 }
778
779 /**
780 * @return the tint applied to the indeterminate drawable
781 * @attr ref android.R.styleable#ProgressBar_indeterminateTint
Alan Viverettea4264452014-07-28 16:02:55 -0700782 * @see #setIndeterminateTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700783 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500784 @InspectableProperty(name = "indeterminateTint")
Alan Viverette91174362014-06-17 14:51:45 -0700785 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -0700786 public ColorStateList getIndeterminateTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700787 return mProgressTintInfo != null ? mProgressTintInfo.mIndeterminateTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -0700788 }
789
790 /**
791 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -0700792 * {@link #setIndeterminateTintList(ColorStateList)} to the indeterminate
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700793 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -0700794 *
795 * @param tintMode the blending mode used to apply the tint, may be
796 * {@code null} to clear tint
797 * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
Alan Viverettea4264452014-07-28 16:02:55 -0700798 * @see #setIndeterminateTintList(ColorStateList)
799 * @see Drawable#setTintMode(PorterDuff.Mode)
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700800 *
Alan Viverette91174362014-06-17 14:51:45 -0700801 */
802 public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700803 setIndeterminateTintBlendMode(tintMode != null
804 ? BlendMode.fromValue(tintMode.nativeInt) : null);
805 }
806
807 /**
808 * Specifies the blending mode used to apply the tint specified by
809 * {@link #setIndeterminateTintList(ColorStateList)} to the indeterminate
810 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
811 *
812 * @param blendMode the blending mode used to apply the tint, may be
813 * {@code null} to clear tint
814 * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
815 * @see #setIndeterminateTintList(ColorStateList)
816 * @see Drawable#setTintBlendMode(BlendMode)
817 */
818 public void setIndeterminateTintBlendMode(@Nullable BlendMode blendMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700819 if (mProgressTintInfo == null) {
820 mProgressTintInfo = new ProgressTintInfo();
821 }
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700822 mProgressTintInfo.mIndeterminateBlendMode = blendMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700823 mProgressTintInfo.mHasIndeterminateTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700824
825 applyIndeterminateTint();
Alan Viverette91174362014-06-17 14:51:45 -0700826 }
827
828 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700829 * Returns the blending mode used to apply the tint to the indeterminate
830 * drawable, if specified.
831 *
832 * @return the blending mode used to apply the tint to the indeterminate
833 * drawable
Alan Viverette91174362014-06-17 14:51:45 -0700834 * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700835 * @see #setIndeterminateTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700836 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500837 @InspectableProperty
Alan Viverette91174362014-06-17 14:51:45 -0700838 @Nullable
839 public PorterDuff.Mode getIndeterminateTintMode() {
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700840 BlendMode mode = getIndeterminateTintBlendMode();
841 return mode != null ? BlendMode.blendModeToPorterDuffMode(mode) : null;
842 }
843
844 /**
845 * Returns the blending mode used to apply the tint to the indeterminate
846 * drawable, if specified.
847 *
848 * @return the blending mode used to apply the tint to the indeterminate
849 * drawable
850 * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
851 * @see #setIndeterminateTintBlendMode(BlendMode)
852 */
853 @InspectableProperty(attributeId = R.styleable.ProgressBar_indeterminateTintMode)
854 @Nullable
855 public BlendMode getIndeterminateTintBlendMode() {
856 return mProgressTintInfo != null ? mProgressTintInfo.mIndeterminateBlendMode : null;
Alan Viverette91174362014-06-17 14:51:45 -0700857 }
858
859 private void applyIndeterminateTint() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700860 if (mIndeterminateDrawable != null && mProgressTintInfo != null) {
861 final ProgressTintInfo tintInfo = mProgressTintInfo;
862 if (tintInfo.mHasIndeterminateTint || tintInfo.mHasIndeterminateTintMode) {
863 mIndeterminateDrawable = mIndeterminateDrawable.mutate();
864
865 if (tintInfo.mHasIndeterminateTint) {
866 mIndeterminateDrawable.setTintList(tintInfo.mIndeterminateTintList);
867 }
868
869 if (tintInfo.mHasIndeterminateTintMode) {
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700870 mIndeterminateDrawable.setTintBlendMode(tintInfo.mIndeterminateBlendMode);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700871 }
Alan Viveretted5133792014-10-28 14:41:36 -0700872
873 // The drawable (or one of its children) may not have been
874 // stateful before applying the tint, so let's try again.
875 if (mIndeterminateDrawable.isStateful()) {
876 mIndeterminateDrawable.setState(getDrawableState());
877 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 }
880 }
Alan Viverettee785d022013-09-26 15:21:10 -0700881
882 /**
883 * Define the tileable drawable used to draw the progress bar in
884 * indeterminate mode.
885 * <p>
886 * If the drawable is a BitmapDrawable or contains BitmapDrawables, a
887 * tiled copy will be generated for display as a progress bar.
888 *
889 * @param d the new drawable
890 * @see #getIndeterminateDrawable()
891 * @see #setIndeterminate(boolean)
892 */
893 public void setIndeterminateDrawableTiled(Drawable d) {
894 if (d != null) {
895 d = tileifyIndeterminate(d);
896 }
897
898 setIndeterminateDrawable(d);
899 }
RoboErik5b071432015-02-11 13:52:05 -0800900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 /**
902 * <p>Get the drawable used to draw the progress bar in
903 * progress mode.</p>
904 *
905 * @return a {@link android.graphics.drawable.Drawable} instance
906 *
907 * @see #setProgressDrawable(android.graphics.drawable.Drawable)
908 * @see #setIndeterminate(boolean)
909 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500910 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 public Drawable getProgressDrawable() {
912 return mProgressDrawable;
913 }
914
915 /**
Alan Viverettee785d022013-09-26 15:21:10 -0700916 * Define the drawable used to draw the progress bar in progress mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 *
918 * @param d the new drawable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 * @see #getProgressDrawable()
920 * @see #setIndeterminate(boolean)
921 */
922 public void setProgressDrawable(Drawable d) {
Alan Viverette91174362014-06-17 14:51:45 -0700923 if (mProgressDrawable != d) {
924 if (mProgressDrawable != null) {
925 mProgressDrawable.setCallback(null);
926 unscheduleDrawable(mProgressDrawable);
927 }
Joe Onoratoaa072632010-12-08 15:31:28 -0800928
Alan Viverette91174362014-06-17 14:51:45 -0700929 mProgressDrawable = d;
930
931 if (d != null) {
932 d.setCallback(this);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700933 d.setLayoutDirection(getLayoutDirection());
Alan Viverette91174362014-06-17 14:51:45 -0700934 if (d.isStateful()) {
935 d.setState(getDrawableState());
936 }
937
938 // Make sure the ProgressBar is always tall enough
939 int drawableHeight = d.getMinimumHeight();
940 if (mMaxHeight < drawableHeight) {
941 mMaxHeight = drawableHeight;
942 requestLayout();
943 }
944
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700945 applyProgressTints();
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700946 }
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500947
Alan Viverette91174362014-06-17 14:51:45 -0700948 if (!mIndeterminate) {
Adam Powellc1bba9b2016-03-03 16:51:17 -0800949 swapCurrentDrawable(d);
Alan Viverette91174362014-06-17 14:51:45 -0700950 postInvalidate();
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500951 }
Joe Onoratoaa072632010-12-08 15:31:28 -0800952
Joe Onoratoaa072632010-12-08 15:31:28 -0800953 updateDrawableBounds(getWidth(), getHeight());
954 updateDrawableState();
Alan Viverette91174362014-06-17 14:51:45 -0700955
Alan Viverettea64ed3b2015-09-23 10:01:45 -0400956 doRefreshProgress(R.id.progress, mProgress, false, false, false);
957 doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false, false);
Joe Onoratoaa072632010-12-08 15:31:28 -0800958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
Alan Viverettee785d022013-09-26 15:21:10 -0700960
961 /**
Christine Franks6418d0b2017-02-13 09:48:00 -0800962 * @hide
963 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500964 @InspectableProperty
Christine Franks6418d0b2017-02-13 09:48:00 -0800965 public boolean getMirrorForRtl() {
966 return mMirrorForRtl;
967 }
968
969 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700970 * Applies the progress tints in order of increasing specificity.
971 */
972 private void applyProgressTints() {
973 if (mProgressDrawable != null && mProgressTintInfo != null) {
974 applyPrimaryProgressTint();
975 applyProgressBackgroundTint();
976 applySecondaryProgressTint();
977 }
978 }
979
980 /**
981 * Should only be called if we've already verified that mProgressDrawable
982 * and mProgressTintInfo are non-null.
983 */
984 private void applyPrimaryProgressTint() {
985 if (mProgressTintInfo.mHasProgressTint
986 || mProgressTintInfo.mHasProgressTintMode) {
987 final Drawable target = getTintTarget(R.id.progress, true);
988 if (target != null) {
989 if (mProgressTintInfo.mHasProgressTint) {
990 target.setTintList(mProgressTintInfo.mProgressTintList);
991 }
992 if (mProgressTintInfo.mHasProgressTintMode) {
Nader Jawad8e31c3e2019-04-14 21:58:04 -0700993 target.setTintBlendMode(mProgressTintInfo.mProgressBlendMode);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700994 }
Alan Viveretted5133792014-10-28 14:41:36 -0700995
996 // The drawable (or one of its children) may not have been
997 // stateful before applying the tint, so let's try again.
998 if (target.isStateful()) {
999 target.setState(getDrawableState());
1000 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001001 }
1002 }
1003 }
1004
1005 /**
1006 * Should only be called if we've already verified that mProgressDrawable
1007 * and mProgressTintInfo are non-null.
1008 */
1009 private void applyProgressBackgroundTint() {
1010 if (mProgressTintInfo.mHasProgressBackgroundTint
1011 || mProgressTintInfo.mHasProgressBackgroundTintMode) {
1012 final Drawable target = getTintTarget(R.id.background, false);
1013 if (target != null) {
1014 if (mProgressTintInfo.mHasProgressBackgroundTint) {
1015 target.setTintList(mProgressTintInfo.mProgressBackgroundTintList);
1016 }
1017 if (mProgressTintInfo.mHasProgressBackgroundTintMode) {
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001018 target.setTintBlendMode(mProgressTintInfo.mProgressBackgroundBlendMode);
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001019 }
Alan Viveretted5133792014-10-28 14:41:36 -07001020
1021 // The drawable (or one of its children) may not have been
1022 // stateful before applying the tint, so let's try again.
1023 if (target.isStateful()) {
1024 target.setState(getDrawableState());
1025 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001026 }
1027 }
1028 }
1029
1030 /**
1031 * Should only be called if we've already verified that mProgressDrawable
1032 * and mProgressTintInfo are non-null.
1033 */
1034 private void applySecondaryProgressTint() {
1035 if (mProgressTintInfo.mHasSecondaryProgressTint
1036 || mProgressTintInfo.mHasSecondaryProgressTintMode) {
1037 final Drawable target = getTintTarget(R.id.secondaryProgress, false);
1038 if (target != null) {
1039 if (mProgressTintInfo.mHasSecondaryProgressTint) {
1040 target.setTintList(mProgressTintInfo.mSecondaryProgressTintList);
1041 }
1042 if (mProgressTintInfo.mHasSecondaryProgressTintMode) {
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001043 target.setTintBlendMode(mProgressTintInfo.mSecondaryProgressBlendMode);
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001044 }
Alan Viveretted5133792014-10-28 14:41:36 -07001045
1046 // The drawable (or one of its children) may not have been
1047 // stateful before applying the tint, so let's try again.
1048 if (target.isStateful()) {
1049 target.setState(getDrawableState());
1050 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001051 }
1052 }
1053 }
1054
1055 /**
Alan Viverette91174362014-06-17 14:51:45 -07001056 * Applies a tint to the progress indicator, if one exists, or to the
Alan Viverette91174362014-06-17 14:51:45 -07001057 * entire progress drawable otherwise. Does not modify the current tint
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001058 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -07001059 * <p>
1060 * The progress indicator should be specified as a layer with
1061 * id {@link android.R.id#progress} in a {@link LayerDrawable}
1062 * used as the progress drawable.
1063 * <p>
1064 * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
1065 * automatically mutate the drawable and apply the specified tint and
1066 * tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -07001067 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -07001068 *
1069 * @param tint the tint to apply, may be {@code null} to clear tint
1070 *
1071 * @attr ref android.R.styleable#ProgressBar_progressTint
Alan Viverettea4264452014-07-28 16:02:55 -07001072 * @see #getProgressTintList()
1073 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001074 */
Jorim Jaggief72a192014-08-26 21:57:46 +02001075 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -07001076 public void setProgressTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001077 if (mProgressTintInfo == null) {
1078 mProgressTintInfo = new ProgressTintInfo();
1079 }
1080 mProgressTintInfo.mProgressTintList = tint;
1081 mProgressTintInfo.mHasProgressTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001082
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001083 if (mProgressDrawable != null) {
1084 applyPrimaryProgressTint();
1085 }
Alan Viverette91174362014-06-17 14:51:45 -07001086 }
1087
1088 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001089 * Returns the tint applied to the progress drawable, if specified.
1090 *
Alan Viverette91174362014-06-17 14:51:45 -07001091 * @return the tint applied to the progress drawable
1092 * @attr ref android.R.styleable#ProgressBar_progressTint
Alan Viverettea4264452014-07-28 16:02:55 -07001093 * @see #setProgressTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001094 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001095 @InspectableProperty(name = "progressTint")
Alan Viverette91174362014-06-17 14:51:45 -07001096 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -07001097 public ColorStateList getProgressTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001098 return mProgressTintInfo != null ? mProgressTintInfo.mProgressTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -07001099 }
1100
1101 /**
1102 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -07001103 * {@link #setProgressTintList(ColorStateList)}} to the progress
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001104 * indicator. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -07001105 *
1106 * @param tintMode the blending mode used to apply the tint, may be
1107 * {@code null} to clear tint
1108 * @attr ref android.R.styleable#ProgressBar_progressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -07001109 * @see #getProgressTintMode()
Alan Viverettea4264452014-07-28 16:02:55 -07001110 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001111 */
1112 public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001113 setProgressTintBlendMode(tintMode != null ? BlendMode.fromValue(tintMode.nativeInt) : null);
1114 }
1115
1116 /**
1117 * Specifies the blending mode used to apply the tint specified by
1118 * {@link #setProgressTintList(ColorStateList)}} to the progress
1119 * indicator. The default mode is {@link PorterDuff.Mode#SRC_IN}.
1120 *
1121 * @param blendMode the blending mode used to apply the tint, may be
1122 * {@code null} to clear tint
1123 * @attr ref android.R.styleable#ProgressBar_progressTintMode
1124 * @see #getProgressTintMode()
1125 * @see Drawable#setTintBlendMode(BlendMode)
1126 */
1127 public void setProgressTintBlendMode(@Nullable BlendMode blendMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001128 if (mProgressTintInfo == null) {
1129 mProgressTintInfo = new ProgressTintInfo();
1130 }
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001131 mProgressTintInfo.mProgressBlendMode = blendMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001132 mProgressTintInfo.mHasProgressTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001133
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001134 if (mProgressDrawable != null) {
1135 applyPrimaryProgressTint();
1136 }
Alan Viverette91174362014-06-17 14:51:45 -07001137 }
1138
1139 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001140 * Returns the blending mode used to apply the tint to the progress
1141 * drawable, if specified.
1142 *
1143 * @return the blending mode used to apply the tint to the progress
1144 * drawable
Alan Viverette91174362014-06-17 14:51:45 -07001145 * @attr ref android.R.styleable#ProgressBar_progressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -07001146 * @see #setProgressTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001147 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001148 @InspectableProperty
Alan Viverette91174362014-06-17 14:51:45 -07001149 @Nullable
1150 public PorterDuff.Mode getProgressTintMode() {
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001151 BlendMode mode = getProgressTintBlendMode();
1152 return mode != null ? BlendMode.blendModeToPorterDuffMode(mode) : null;
1153 }
1154
1155 /**
1156 * Returns the blending mode used to apply the tint to the progress
1157 * drawable, if specified.
1158 *
1159 * @return the blending mode used to apply the tint to the progress
1160 * drawable
1161 * @attr ref android.R.styleable#ProgressBar_progressTintMode
1162 * @see #setProgressTintBlendMode(BlendMode)
1163 */
1164 @InspectableProperty(attributeId = android.R.styleable.ProgressBar_progressTintMode)
1165 @Nullable
1166 public BlendMode getProgressTintBlendMode() {
1167 return mProgressTintInfo != null ? mProgressTintInfo.mProgressBlendMode : null;
Alan Viverette91174362014-06-17 14:51:45 -07001168 }
1169
1170 /**
Alan Viverette91174362014-06-17 14:51:45 -07001171 * Applies a tint to the progress background, if one exists. Does not
1172 * modify the current tint mode, which is
1173 * {@link PorterDuff.Mode#SRC_ATOP} by default.
1174 * <p>
1175 * The progress background must be specified as a layer with
1176 * id {@link android.R.id#background} in a {@link LayerDrawable}
1177 * used as the progress drawable.
1178 * <p>
1179 * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
1180 * drawable contains a progress background will automatically mutate the
1181 * drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -07001182 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -07001183 *
1184 * @param tint the tint to apply, may be {@code null} to clear tint
1185 *
1186 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
Alan Viverettea4264452014-07-28 16:02:55 -07001187 * @see #getProgressBackgroundTintList()
1188 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001189 */
Jorim Jaggief72a192014-08-26 21:57:46 +02001190 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -07001191 public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001192 if (mProgressTintInfo == null) {
1193 mProgressTintInfo = new ProgressTintInfo();
1194 }
1195 mProgressTintInfo.mProgressBackgroundTintList = tint;
1196 mProgressTintInfo.mHasProgressBackgroundTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001197
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001198 if (mProgressDrawable != null) {
1199 applyProgressBackgroundTint();
1200 }
Alan Viverette91174362014-06-17 14:51:45 -07001201 }
1202
1203 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001204 * Returns the tint applied to the progress background, if specified.
1205 *
Alan Viverette91174362014-06-17 14:51:45 -07001206 * @return the tint applied to the progress background
1207 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
Alan Viverettea4264452014-07-28 16:02:55 -07001208 * @see #setProgressBackgroundTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001209 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001210 @InspectableProperty(name = "progressBackgroundTint")
Alan Viverette91174362014-06-17 14:51:45 -07001211 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -07001212 public ColorStateList getProgressBackgroundTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001213 return mProgressTintInfo != null ? mProgressTintInfo.mProgressBackgroundTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -07001214 }
1215
1216 /**
1217 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -07001218 * {@link #setProgressBackgroundTintList(ColorStateList)}} to the progress
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001219 * background. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -07001220 *
1221 * @param tintMode the blending mode used to apply the tint, may be
1222 * {@code null} to clear tint
1223 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
Alan Viverettea4264452014-07-28 16:02:55 -07001224 * @see #setProgressBackgroundTintList(ColorStateList)
1225 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001226 */
1227 public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001228 setProgressBackgroundTintBlendMode(tintMode != null
1229 ? BlendMode.fromValue(tintMode.nativeInt) : null);
1230 }
1231
1232 /**
1233 * Specifies the blending mode used to apply the tint specified by
1234 * {@link #setProgressBackgroundTintList(ColorStateList)}} to the progress
1235 * background. The default mode is {@link BlendMode#SRC_IN}.
1236 *
1237 * @param blendMode the blending mode used to apply the tint, may be
1238 * {@code null} to clear tint
1239 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
1240 * @see #setProgressBackgroundTintList(ColorStateList)
1241 * @see Drawable#setTintBlendMode(BlendMode)
1242 */
1243 public void setProgressBackgroundTintBlendMode(@Nullable BlendMode blendMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001244 if (mProgressTintInfo == null) {
1245 mProgressTintInfo = new ProgressTintInfo();
1246 }
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001247 mProgressTintInfo.mProgressBackgroundBlendMode = blendMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001248 mProgressTintInfo.mHasProgressBackgroundTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001249
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001250 if (mProgressDrawable != null) {
1251 applyProgressBackgroundTint();
1252 }
Alan Viverette91174362014-06-17 14:51:45 -07001253 }
1254
1255 /**
1256 * @return the blending mode used to apply the tint to the progress
1257 * background
1258 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -07001259 * @see #setProgressBackgroundTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001260 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001261 @InspectableProperty
Alan Viverette91174362014-06-17 14:51:45 -07001262 @Nullable
1263 public PorterDuff.Mode getProgressBackgroundTintMode() {
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001264 BlendMode mode = getProgressBackgroundTintBlendMode();
1265 return mode != null ? BlendMode.blendModeToPorterDuffMode(mode) : null;
1266 }
1267
1268 /**
1269 * @return the blending mode used to apply the tint to the progress
1270 * background
1271 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
1272 * @see #setProgressBackgroundTintBlendMode(BlendMode)
1273 */
1274 @InspectableProperty(attributeId = R.styleable.ProgressBar_progressBackgroundTintMode)
1275 @Nullable
1276 public BlendMode getProgressBackgroundTintBlendMode() {
1277 return mProgressTintInfo != null ? mProgressTintInfo.mProgressBackgroundBlendMode : null;
Alan Viverette91174362014-06-17 14:51:45 -07001278 }
1279
1280 /**
1281 * Applies a tint to the secondary progress indicator, if one exists.
Alan Viverette91174362014-06-17 14:51:45 -07001282 * Does not modify the current tint mode, which is
1283 * {@link PorterDuff.Mode#SRC_ATOP} by default.
1284 * <p>
1285 * The secondary progress indicator must be specified as a layer with
1286 * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
1287 * used as the progress drawable.
1288 * <p>
1289 * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
1290 * drawable contains a secondary progress indicator will automatically
1291 * mutate the drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -07001292 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -07001293 *
1294 * @param tint the tint to apply, may be {@code null} to clear tint
1295 *
1296 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
Alan Viverettea4264452014-07-28 16:02:55 -07001297 * @see #getSecondaryProgressTintList()
1298 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001299 */
Alan Viverettea4264452014-07-28 16:02:55 -07001300 public void setSecondaryProgressTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001301 if (mProgressTintInfo == null) {
1302 mProgressTintInfo = new ProgressTintInfo();
1303 }
1304 mProgressTintInfo.mSecondaryProgressTintList = tint;
1305 mProgressTintInfo.mHasSecondaryProgressTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001306
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001307 if (mProgressDrawable != null) {
1308 applySecondaryProgressTint();
1309 }
Alan Viverette91174362014-06-17 14:51:45 -07001310 }
1311
1312 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001313 * Returns the tint applied to the secondary progress drawable, if
1314 * specified.
1315 *
Alan Viverette91174362014-06-17 14:51:45 -07001316 * @return the tint applied to the secondary progress drawable
1317 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
Alan Viverettea4264452014-07-28 16:02:55 -07001318 * @see #setSecondaryProgressTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001319 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001320 @InspectableProperty(name = "secondaryProgressTint")
Alan Viverette91174362014-06-17 14:51:45 -07001321 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -07001322 public ColorStateList getSecondaryProgressTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001323 return mProgressTintInfo != null ? mProgressTintInfo.mSecondaryProgressTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -07001324 }
1325
1326 /**
1327 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -07001328 * {@link #setSecondaryProgressTintList(ColorStateList)}} to the secondary
Alan Viverette91174362014-06-17 14:51:45 -07001329 * progress indicator. The default mode is
1330 * {@link PorterDuff.Mode#SRC_ATOP}.
1331 *
1332 * @param tintMode the blending mode used to apply the tint, may be
1333 * {@code null} to clear tint
1334 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
Alan Viverettea4264452014-07-28 16:02:55 -07001335 * @see #setSecondaryProgressTintList(ColorStateList)
1336 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001337 */
1338 public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001339 setSecondaryProgressTintBlendMode(tintMode != null
1340 ? BlendMode.fromValue(tintMode.nativeInt) : null);
1341 }
1342
1343 /**
1344 * Specifies the blending mode used to apply the tint specified by
1345 * {@link #setSecondaryProgressTintList(ColorStateList)}} to the secondary
1346 * progress indicator. The default mode is
1347 * {@link PorterDuff.Mode#SRC_ATOP}.
1348 *
1349 * @param blendMode the blending mode used to apply the tint, may be
1350 * {@code null} to clear tint
1351 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
1352 * @see #setSecondaryProgressTintList(ColorStateList)
1353 * @see Drawable#setTintBlendMode(BlendMode)
1354 */
1355 public void setSecondaryProgressTintBlendMode(@Nullable BlendMode blendMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001356 if (mProgressTintInfo == null) {
1357 mProgressTintInfo = new ProgressTintInfo();
1358 }
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001359 mProgressTintInfo.mSecondaryProgressBlendMode = blendMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001360 mProgressTintInfo.mHasSecondaryProgressTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001361
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001362 if (mProgressDrawable != null) {
1363 applySecondaryProgressTint();
1364 }
Alan Viverette91174362014-06-17 14:51:45 -07001365 }
1366
1367 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001368 * Returns the blending mode used to apply the tint to the secondary
1369 * progress drawable, if specified.
1370 *
Alan Viverette91174362014-06-17 14:51:45 -07001371 * @return the blending mode used to apply the tint to the secondary
1372 * progress drawable
1373 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -07001374 * @see #setSecondaryProgressTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001375 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001376 @InspectableProperty
Alan Viverette91174362014-06-17 14:51:45 -07001377 @Nullable
1378 public PorterDuff.Mode getSecondaryProgressTintMode() {
Nader Jawad8e31c3e2019-04-14 21:58:04 -07001379 BlendMode mode = getSecondaryProgressTintBlendMode();
1380 return mode != null ? BlendMode.blendModeToPorterDuffMode(mode) : null;
1381 }
1382
1383 /**
1384 * Returns the blending mode used to apply the tint to the secondary
1385 * progress drawable, if specified.
1386 *
1387 * @return the blending mode used to apply the tint to the secondary
1388 * progress drawable
1389 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
1390 * @see #setSecondaryProgressTintBlendMode(BlendMode)
1391 */
1392 @InspectableProperty(attributeId = android.R.styleable.ProgressBar_secondaryProgressTintMode)
1393 @Nullable
1394 public BlendMode getSecondaryProgressTintBlendMode() {
1395 return mProgressTintInfo != null ? mProgressTintInfo.mSecondaryProgressBlendMode : null;
Alan Viverette91174362014-06-17 14:51:45 -07001396 }
1397
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001398 /**
1399 * Returns the drawable to which a tint or tint mode should be applied.
1400 *
1401 * @param layerId id of the layer to modify
1402 * @param shouldFallback whether the base drawable should be returned
1403 * if the id does not exist
1404 * @return the drawable to modify
1405 */
1406 @Nullable
1407 private Drawable getTintTarget(int layerId, boolean shouldFallback) {
1408 Drawable layer = null;
1409
Alan Viverette91174362014-06-17 14:51:45 -07001410 final Drawable d = mProgressDrawable;
1411 if (d != null) {
1412 mProgressDrawable = d.mutate();
1413
Alan Viverette91174362014-06-17 14:51:45 -07001414 if (d instanceof LayerDrawable) {
1415 layer = ((LayerDrawable) d).findDrawableByLayerId(layerId);
1416 }
1417
1418 if (shouldFallback && layer == null) {
1419 layer = d;
1420 }
Alan Viverette91174362014-06-17 14:51:45 -07001421 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001422
1423 return layer;
Alan Viverette91174362014-06-17 14:51:45 -07001424 }
1425
1426 /**
Alan Viverettee785d022013-09-26 15:21:10 -07001427 * Define the tileable drawable used to draw the progress bar in
1428 * progress mode.
1429 * <p>
1430 * If the drawable is a BitmapDrawable or contains BitmapDrawables, a
1431 * tiled copy will be generated for display as a progress bar.
1432 *
1433 * @param d the new drawable
1434 * @see #getProgressDrawable()
1435 * @see #setIndeterminate(boolean)
1436 */
1437 public void setProgressDrawableTiled(Drawable d) {
1438 if (d != null) {
1439 d = tileify(d, false);
1440 }
1441
1442 setProgressDrawable(d);
1443 }
RoboErik5b071432015-02-11 13:52:05 -08001444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001445 /**
Mihai Popa3df49262019-02-06 12:35:29 +00001446 * Returns the drawable currently used to draw the progress bar. This will be
1447 * either {@link #getProgressDrawable()} or {@link #getIndeterminateDrawable()}
1448 * depending on whether the progress bar is in determinate or indeterminate mode.
1449 *
1450 * @return the drawable currently used to draw the progress bar
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 */
Mihai Popa3df49262019-02-06 12:35:29 +00001452 @Nullable
1453 public Drawable getCurrentDrawable() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 return mCurrentDrawable;
1455 }
1456
1457 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -05001458 protected boolean verifyDrawable(@NonNull Drawable who) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 return who == mProgressDrawable || who == mIndeterminateDrawable
1460 || super.verifyDrawable(who);
1461 }
1462
1463 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07001464 public void jumpDrawablesToCurrentState() {
1465 super.jumpDrawablesToCurrentState();
1466 if (mProgressDrawable != null) mProgressDrawable.jumpToCurrentState();
1467 if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState();
1468 }
1469
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07001470 /**
1471 * @hide
1472 */
Dianne Hackborne2136772010-11-04 15:08:59 -07001473 @Override
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -07001474 public void onResolveDrawables(int layoutDirection) {
1475 final Drawable d = mCurrentDrawable;
1476 if (d != null) {
1477 d.setLayoutDirection(layoutDirection);
1478 }
1479 if (mIndeterminateDrawable != null) {
1480 mIndeterminateDrawable.setLayoutDirection(layoutDirection);
1481 }
1482 if (mProgressDrawable != null) {
1483 mProgressDrawable.setLayoutDirection(layoutDirection);
1484 }
1485 }
1486
1487 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 public void postInvalidate() {
1489 if (!mNoInvalidate) {
1490 super.postInvalidate();
1491 }
1492 }
1493
1494 private class RefreshProgressRunnable implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 public void run() {
Adam Powella0506632012-04-10 17:19:20 -07001496 synchronized (ProgressBar.this) {
1497 final int count = mRefreshData.size();
1498 for (int i = 0; i < count; i++) {
1499 final RefreshData rd = mRefreshData.get(i);
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001500 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate);
Adam Powella0506632012-04-10 17:19:20 -07001501 rd.recycle();
1502 }
1503 mRefreshData.clear();
1504 mRefreshIsPosted = false;
1505 }
1506 }
1507 }
1508
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001509 private static class RefreshData {
1510 private static final int POOL_MAX = 24;
1511 private static final SynchronizedPool<RefreshData> sPool =
1512 new SynchronizedPool<RefreshData>(POOL_MAX);
1513
Adam Powella0506632012-04-10 17:19:20 -07001514 public int id;
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001515 public int progress;
Adam Powella0506632012-04-10 17:19:20 -07001516 public boolean fromUser;
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001517 public boolean animate;
Adam Powella0506632012-04-10 17:19:20 -07001518
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001519 public static RefreshData obtain(int id, int progress, boolean fromUser, boolean animate) {
Adam Powella0506632012-04-10 17:19:20 -07001520 RefreshData rd = sPool.acquire();
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001521 if (rd == null) {
1522 rd = new RefreshData();
1523 }
Adam Powella0506632012-04-10 17:19:20 -07001524 rd.id = id;
1525 rd.progress = progress;
1526 rd.fromUser = fromUser;
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001527 rd.animate = animate;
Adam Powella0506632012-04-10 17:19:20 -07001528 return rd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529 }
RoboErik5b071432015-02-11 13:52:05 -08001530
Adam Powella0506632012-04-10 17:19:20 -07001531 public void recycle() {
1532 sPool.release(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 }
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001535
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001536 private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001537 boolean callBackToApp, boolean animate) {
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001538 int range = mMax - mMin;
1539 final float scale = range > 0 ? (progress - mMin) / (float) range : 0;
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001540 final boolean isPrimary = id == R.id.progress;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001542 if (isPrimary && animate) {
1543 final ObjectAnimator animator = ObjectAnimator.ofFloat(this, VISUAL_PROGRESS, scale);
1544 animator.setAutoCancel(true);
1545 animator.setDuration(PROGRESS_ANIM_DURATION);
1546 animator.setInterpolator(PROGRESS_ANIM_INTERPOLATOR);
1547 animator.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 } else {
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001549 setVisualProgress(id, scale);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 }
RoboErik5b071432015-02-11 13:52:05 -08001551
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001552 if (isPrimary && callBackToApp) {
RoboErik5b071432015-02-11 13:52:05 -08001553 onProgressRefresh(scale, fromUser, progress);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 }
1555 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001556
yingleiw6ab02c12019-10-30 12:14:30 -07001557 private float getPercent(int progress) {
1558 final float maxProgress = getMax();
1559 final float minProgress = getMin();
1560 final float currentProgress = progress;
1561 final float diffProgress = maxProgress - minProgress;
1562 if (diffProgress <= 0.0f) {
1563 return 0.0f;
1564 }
1565 final float percent = (currentProgress - minProgress) / diffProgress;
1566 return Math.max(0.0f, Math.min(1.0f, percent));
1567 }
1568
1569 /**
1570 * Default percentage format of the state description based on progress, for example,
1571 * "50 percent".
1572 *
1573 * @param progress the progress value, between {@link #getMin()} and {@link #getMax()}
1574 * @return state description based on progress
1575 */
1576 private CharSequence formatStateDescription(int progress) {
1577 return NumberFormat.getPercentInstance(mContext.getResources().getConfiguration().locale)
1578 .format(getPercent(progress));
1579 }
1580
1581 /**
1582 * This function is called when an instance or subclass sets the state description. Once this
1583 * is called and the argument is not null, the app developer will be responsible for updating
1584 * state description when progress changes and the default state description will not be used.
1585 * App developers can restore the default behavior by setting the argument to null. If set
1586 * progress is called first and then setStateDescription is called, two state change events
1587 * will be merged by event throttling and we can still get the correct state description.
1588 *
1589 * @param stateDescription The state description.
1590 */
1591 @Override
1592 public void setStateDescription(@Nullable CharSequence stateDescription) {
1593 mCustomStateDescription = stateDescription;
1594 if (stateDescription == null) {
1595 super.setStateDescription(formatStateDescription(mProgress));
1596 } else {
1597 super.setStateDescription(stateDescription);
1598 }
1599 }
1600
RoboErik5b071432015-02-11 13:52:05 -08001601 void onProgressRefresh(float scale, boolean fromUser, int progress) {
yingleiw6ab02c12019-10-30 12:14:30 -07001602 if (AccessibilityManager.getInstance(mContext).isEnabled()
1603 && mCustomStateDescription == null) {
1604 super.setStateDescription(formatStateDescription(mProgress));
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 }
1607
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001608 /**
1609 * Sets the visual state of a progress indicator.
1610 *
1611 * @param id the identifier of the progress indicator
1612 * @param progress the visual progress in the range [0...1]
1613 */
1614 private void setVisualProgress(int id, float progress) {
1615 mVisualProgress = progress;
1616
1617 Drawable d = mCurrentDrawable;
1618
1619 if (d instanceof LayerDrawable) {
1620 d = ((LayerDrawable) d).findDrawableByLayerId(id);
Alan Viverette4d59b812016-04-12 17:17:55 -04001621 if (d == null) {
1622 // If we can't find the requested layer, fall back to setting
1623 // the level of the entire drawable. This will break if
1624 // progress is set on multiple elements, but the theme-default
1625 // drawable will always have all layer IDs present.
1626 d = mCurrentDrawable;
1627 }
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001628 }
1629
1630 if (d != null) {
1631 final int level = (int) (progress * MAX_LEVEL);
1632 d.setLevel(level);
1633 } else {
1634 invalidate();
1635 }
1636
1637 onVisualProgressChanged(id, progress);
1638 }
1639
1640 /**
1641 * Called when the visual state of a progress indicator changes.
1642 *
1643 * @param id the identifier of the progress indicator
1644 * @param progress the visual progress in the range [0...1]
1645 */
1646 void onVisualProgressChanged(int id, float progress) {
1647 // Stub method.
1648 }
1649
Mathew Inwood978c6e22018-08-21 15:58:55 +01001650 @UnsupportedAppUsage
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001651 private synchronized void refreshProgress(int id, int progress, boolean fromUser,
1652 boolean animate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 if (mUiThreadId == Thread.currentThread().getId()) {
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001654 doRefreshProgress(id, progress, fromUser, true, animate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001656 if (mRefreshProgressRunnable == null) {
1657 mRefreshProgressRunnable = new RefreshProgressRunnable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 }
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001659
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001660 final RefreshData rd = RefreshData.obtain(id, progress, fromUser, animate);
Adam Powella0506632012-04-10 17:19:20 -07001661 mRefreshData.add(rd);
1662 if (mAttached && !mRefreshIsPosted) {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001663 post(mRefreshProgressRunnable);
Adam Powella0506632012-04-10 17:19:20 -07001664 mRefreshIsPosted = true;
1665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 }
1667 }
RoboErik5b071432015-02-11 13:52:05 -08001668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 /**
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001670 * Sets the current progress to the specified value. Does not do anything
1671 * if the progress bar is in indeterminate mode.
Alan Viverettea1863cf2016-04-20 16:41:17 -04001672 * <p>
1673 * This method will immediately update the visual position of the progress
1674 * indicator. To animate the visual position to the target value, use
1675 * {@link #setProgress(int, boolean)}}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 *
Chet Haase25886a162018-03-28 18:26:53 -07001677 * @param progress the new progress, between {@link #getMin()} and {@link #getMax()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 *
1679 * @see #setIndeterminate(boolean)
1680 * @see #isIndeterminate()
1681 * @see #getProgress()
RoboErik5b071432015-02-11 13:52:05 -08001682 * @see #incrementProgressBy(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001683 */
1684 @android.view.RemotableViewMethod
1685 public synchronized void setProgress(int progress) {
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001686 setProgressInternal(progress, false, false);
1687 }
1688
1689 /**
1690 * Sets the current progress to the specified value, optionally animating
Alan Viverettea1863cf2016-04-20 16:41:17 -04001691 * the visual position between the current and target values.
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001692 * <p>
1693 * Animation does not affect the result of {@link #getProgress()}, which
1694 * will return the target value immediately after this method is called.
1695 *
Chet Haase25886a162018-03-28 18:26:53 -07001696 * @param progress the new progress value, between {@link #getMin()} and {@link #getMax()}
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001697 * @param animate {@code true} to animate between the current and target
1698 * values or {@code false} to not animate
1699 */
1700 public void setProgress(int progress, boolean animate) {
1701 setProgressInternal(progress, false, animate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 }
RoboErik5b071432015-02-11 13:52:05 -08001703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001704 @android.view.RemotableViewMethod
Mathew Inwood978c6e22018-08-21 15:58:55 +01001705 @UnsupportedAppUsage
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001706 synchronized boolean setProgressInternal(int progress, boolean fromUser, boolean animate) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 if (mIndeterminate) {
Alan Viverette12a44912015-04-16 13:06:00 -07001708 // Not applicable.
1709 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 }
1711
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001712 progress = MathUtils.constrain(progress, mMin, mMax);
Alan Viverette12a44912015-04-16 13:06:00 -07001713
1714 if (progress == mProgress) {
1715 // No change from current.
1716 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 }
1718
Alan Viverette12a44912015-04-16 13:06:00 -07001719 mProgress = progress;
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001720 refreshProgress(R.id.progress, mProgress, fromUser, animate);
Alan Viverette12a44912015-04-16 13:06:00 -07001721 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 }
1723
1724 /**
1725 * <p>
1726 * Set the current secondary progress to the specified value. Does not do
1727 * anything if the progress bar is in indeterminate mode.
1728 * </p>
RoboErik5b071432015-02-11 13:52:05 -08001729 *
Chet Haase25886a162018-03-28 18:26:53 -07001730 * @param secondaryProgress the new secondary progress, between {@link #getMin()} and
1731 * {@link #getMax()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001732 * @see #setIndeterminate(boolean)
1733 * @see #isIndeterminate()
1734 * @see #getSecondaryProgress()
1735 * @see #incrementSecondaryProgressBy(int)
1736 */
1737 @android.view.RemotableViewMethod
1738 public synchronized void setSecondaryProgress(int secondaryProgress) {
1739 if (mIndeterminate) {
1740 return;
1741 }
1742
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001743 if (secondaryProgress < mMin) {
1744 secondaryProgress = mMin;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 }
1746
1747 if (secondaryProgress > mMax) {
1748 secondaryProgress = mMax;
1749 }
1750
1751 if (secondaryProgress != mSecondaryProgress) {
1752 mSecondaryProgress = secondaryProgress;
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001753 refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 }
1755 }
1756
1757 /**
1758 * <p>Get the progress bar's current level of progress. Return 0 when the
1759 * progress bar is in indeterminate mode.</p>
1760 *
Chet Haase25886a162018-03-28 18:26:53 -07001761 * @return the current progress, between {@link #getMin()} and {@link #getMax()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 *
1763 * @see #setIndeterminate(boolean)
1764 * @see #isIndeterminate()
1765 * @see #setProgress(int)
1766 * @see #setMax(int)
1767 * @see #getMax()
1768 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001769 @ViewDebug.ExportedProperty(category = "progress")
Ashley Rose55f9f922019-01-28 19:29:36 -05001770 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 public synchronized int getProgress() {
1772 return mIndeterminate ? 0 : mProgress;
1773 }
1774
1775 /**
1776 * <p>Get the progress bar's current level of secondary progress. Return 0 when the
1777 * progress bar is in indeterminate mode.</p>
1778 *
Chet Haase25886a162018-03-28 18:26:53 -07001779 * @return the current secondary progress, between {@link #getMin()} and {@link #getMax()}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 *
1781 * @see #setIndeterminate(boolean)
1782 * @see #isIndeterminate()
1783 * @see #setSecondaryProgress(int)
1784 * @see #setMax(int)
1785 * @see #getMax()
1786 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001787 @ViewDebug.ExportedProperty(category = "progress")
Ashley Rose55f9f922019-01-28 19:29:36 -05001788 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 public synchronized int getSecondaryProgress() {
1790 return mIndeterminate ? 0 : mSecondaryProgress;
1791 }
1792
1793 /**
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001794 * <p>Return the lower limit of this progress bar's range.</p>
1795 *
1796 * @return a positive integer
1797 *
1798 * @see #setMin(int)
1799 * @see #getProgress()
1800 * @see #getSecondaryProgress()
1801 */
1802 @ViewDebug.ExportedProperty(category = "progress")
Ashley Rose55f9f922019-01-28 19:29:36 -05001803 @InspectableProperty
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001804 public synchronized int getMin() {
1805 return mMin;
1806 }
1807
1808 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 * <p>Return the upper limit of this progress bar's range.</p>
1810 *
1811 * @return a positive integer
1812 *
1813 * @see #setMax(int)
1814 * @see #getProgress()
1815 * @see #getSecondaryProgress()
1816 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001817 @ViewDebug.ExportedProperty(category = "progress")
Ashley Rose55f9f922019-01-28 19:29:36 -05001818 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 public synchronized int getMax() {
1820 return mMax;
1821 }
1822
1823 /**
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001824 * <p>Set the lower range of the progress bar to <tt>min</tt>.</p>
1825 *
1826 * @param min the lower range of this progress bar
1827 *
1828 * @see #getMin()
1829 * @see #setProgress(int)
1830 * @see #setSecondaryProgress(int)
1831 */
1832 @android.view.RemotableViewMethod
1833 public synchronized void setMin(int min) {
1834 if (mMaxInitialized) {
1835 if (min > mMax) {
1836 min = mMax;
1837 }
1838 }
1839 mMinInitialized = true;
1840 if (mMaxInitialized && min != mMin) {
1841 mMin = min;
1842 postInvalidate();
1843
1844 if (mProgress < min) {
1845 mProgress = min;
1846 }
1847 refreshProgress(R.id.progress, mProgress, false, false);
1848 } else {
1849 mMin = min;
1850 }
1851 }
1852
1853 /**
1854 * <p>Set the upper range of the progress bar <tt>max</tt>.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 *
1856 * @param max the upper range of this progress bar
1857 *
1858 * @see #getMax()
RoboErik5b071432015-02-11 13:52:05 -08001859 * @see #setProgress(int)
1860 * @see #setSecondaryProgress(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 */
1862 @android.view.RemotableViewMethod
1863 public synchronized void setMax(int max) {
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001864 if (mMinInitialized) {
1865 if (max < mMin) {
1866 max = mMin;
1867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001868 }
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001869 mMaxInitialized = true;
1870 if (mMinInitialized && max != mMax) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 mMax = max;
1872 postInvalidate();
1873
1874 if (mProgress > max) {
1875 mProgress = max;
1876 }
Alan Viverettea64ed3b2015-09-23 10:01:45 -04001877 refreshProgress(R.id.progress, mProgress, false, false);
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07001878 } else {
1879 mMax = max;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 }
1881 }
RoboErik5b071432015-02-11 13:52:05 -08001882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 /**
1884 * <p>Increase the progress bar's progress by the specified amount.</p>
1885 *
1886 * @param diff the amount by which the progress must be increased
1887 *
RoboErik5b071432015-02-11 13:52:05 -08001888 * @see #setProgress(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001889 */
1890 public synchronized final void incrementProgressBy(int diff) {
1891 setProgress(mProgress + diff);
1892 }
1893
1894 /**
1895 * <p>Increase the progress bar's secondary progress by the specified amount.</p>
1896 *
1897 * @param diff the amount by which the secondary progress must be increased
1898 *
RoboErik5b071432015-02-11 13:52:05 -08001899 * @see #setSecondaryProgress(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 */
1901 public synchronized final void incrementSecondaryProgressBy(int diff) {
1902 setSecondaryProgress(mSecondaryProgress + diff);
1903 }
1904
1905 /**
1906 * <p>Start the indeterminate progress animation.</p>
1907 */
Mathew Inwood978c6e22018-08-21 15:58:55 +01001908 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 void startAnimation() {
Adam Powellc1bba9b2016-03-03 16:51:17 -08001910 if (getVisibility() != VISIBLE || getWindowVisibility() != VISIBLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 return;
1912 }
1913
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001914 if (mIndeterminateDrawable instanceof Animatable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001915 mShouldStartAnimationDrawable = true;
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001916 mHasAnimation = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001918 mHasAnimation = true;
1919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 if (mInterpolator == null) {
1921 mInterpolator = new LinearInterpolator();
1922 }
RoboErik5b071432015-02-11 13:52:05 -08001923
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001924 if (mTransformation == null) {
1925 mTransformation = new Transformation();
1926 } else {
1927 mTransformation.clear();
1928 }
RoboErik5b071432015-02-11 13:52:05 -08001929
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001930 if (mAnimation == null) {
1931 mAnimation = new AlphaAnimation(0.0f, 1.0f);
1932 } else {
1933 mAnimation.reset();
1934 }
1935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 mAnimation.setRepeatMode(mBehavior);
1937 mAnimation.setRepeatCount(Animation.INFINITE);
1938 mAnimation.setDuration(mDuration);
1939 mAnimation.setInterpolator(mInterpolator);
1940 mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001941 }
Evan Charlton08e14732010-06-07 10:38:53 -07001942 postInvalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 }
1944
1945 /**
1946 * <p>Stop the indeterminate progress animation.</p>
1947 */
Mathew Inwood978c6e22018-08-21 15:58:55 +01001948 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001949 void stopAnimation() {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001950 mHasAnimation = false;
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001951 if (mIndeterminateDrawable instanceof Animatable) {
1952 ((Animatable) mIndeterminateDrawable).stop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 mShouldStartAnimationDrawable = false;
1954 }
Evan Charlton08e14732010-06-07 10:38:53 -07001955 postInvalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 }
1957
1958 /**
1959 * Sets the acceleration curve for the indeterminate animation.
shepshapard3b070452019-02-08 16:54:55 -08001960 *
1961 * <p>The interpolator is loaded as a resource from the specified context. Defaults to a linear
1962 * interpolation.
1963 *
1964 * <p>The interpolator only affects the indeterminate animation if the
1965 * {@link #setIndeterminateDrawable(Drawable) supplied indeterminate drawable} does not
1966 * implement {@link Animatable}.
1967 *
1968 * <p>This call must be made before the indeterminate animation starts for it to have an affect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 *
1970 * @param context The application environment
1971 * @param resID The resource identifier of the interpolator to load
shepshapard3b070452019-02-08 16:54:55 -08001972 * @attr ref android.R.styleable#ProgressBar_interpolator
1973 * @see #setInterpolator(Interpolator)
1974 * @see #getInterpolator()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001976 public void setInterpolator(Context context, @InterpolatorRes int resID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 setInterpolator(AnimationUtils.loadInterpolator(context, resID));
1978 }
1979
1980 /**
1981 * Sets the acceleration curve for the indeterminate animation.
1982 * Defaults to a linear interpolation.
1983 *
shepshapard3b070452019-02-08 16:54:55 -08001984 * <p>The interpolator only affects the indeterminate animation if the
1985 * {@link #setIndeterminateDrawable(Drawable) supplied indeterminate drawable} does not
1986 * implement {@link Animatable}.
1987 *
1988 * <p>This call must be made before the indeterminate animation starts for it to have
1989 * an affect.
1990 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001991 * @param interpolator The interpolator which defines the acceleration curve
shepshapard3b070452019-02-08 16:54:55 -08001992 * @attr ref android.R.styleable#ProgressBar_interpolator
1993 * @see #setInterpolator(Context, int)
1994 * @see #getInterpolator()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 */
1996 public void setInterpolator(Interpolator interpolator) {
1997 mInterpolator = interpolator;
1998 }
1999
2000 /**
2001 * Gets the acceleration curve type for the indeterminate animation.
2002 *
2003 * @return the {@link Interpolator} associated to this animation
shepshapard3b070452019-02-08 16:54:55 -08002004 * @attr ref android.R.styleable#ProgressBar_interpolator
2005 * @see #setInterpolator(Context, int)
2006 * @see #setInterpolator(Interpolator)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 */
Ashley Rose55f9f922019-01-28 19:29:36 -05002008 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 public Interpolator getInterpolator() {
2010 return mInterpolator;
2011 }
2012
2013 @Override
Adam Powell9c146bf2016-03-15 17:35:00 -07002014 public void onVisibilityAggregated(boolean isVisible) {
2015 super.onVisibilityAggregated(isVisible);
Adam Powell41d96902016-03-15 14:43:19 -07002016
Adam Powell41d96902016-03-15 14:43:19 -07002017 if (isVisible != mAggregatedIsVisible) {
2018 mAggregatedIsVisible = isVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019
2020 if (mIndeterminate) {
2021 // let's be nice with the UI thread
Adam Powell41d96902016-03-15 14:43:19 -07002022 if (isVisible) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002023 startAnimation();
Adam Powell41d96902016-03-15 14:43:19 -07002024 } else {
2025 stopAnimation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002026 }
2027 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028
Adam Powell41d96902016-03-15 14:43:19 -07002029 if (mCurrentDrawable != null) {
2030 mCurrentDrawable.setVisible(isVisible, false);
Romain Guya05e8a52010-02-25 14:32:39 -08002031 }
2032 }
2033 }
2034
2035 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -05002036 public void invalidateDrawable(@NonNull Drawable dr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 if (!mInDrawing) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07002038 if (verifyDrawable(dr)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002039 final Rect dirty = dr.getBounds();
Chris Craik7546a4b2013-10-30 19:49:37 -07002040 final int scrollX = mScrollX + mPaddingLeft;
2041 final int scrollY = mScrollY + mPaddingTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042
Chris Craik7546a4b2013-10-30 19:49:37 -07002043 invalidate(dirty.left + scrollX, dirty.top + scrollY,
2044 dirty.right + scrollX, dirty.bottom + scrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 } else {
2046 super.invalidateDrawable(dr);
2047 }
2048 }
2049 }
2050
2051 @Override
2052 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Joe Onoratoaa072632010-12-08 15:31:28 -08002053 updateDrawableBounds(w, h);
2054 }
2055
2056 private void updateDrawableBounds(int w, int h) {
Adam Powell6322af52012-08-08 15:59:12 -07002057 // onDraw will translate the canvas so we draw starting at 0,0.
2058 // Subtract out padding for the purposes of the calculations below.
2059 w -= mPaddingRight + mPaddingLeft;
2060 h -= mPaddingTop + mPaddingBottom;
2061
2062 int right = w;
2063 int bottom = h;
Adam Powella1b92c52011-09-02 15:05:15 -07002064 int top = 0;
2065 int left = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066
2067 if (mIndeterminateDrawable != null) {
Chet Haasea79803c2011-09-28 17:51:53 -07002068 // Aspect ratio logic does not apply to AnimationDrawables
2069 if (mOnlyIndeterminate && !(mIndeterminateDrawable instanceof AnimationDrawable)) {
Adam Powella1b92c52011-09-02 15:05:15 -07002070 // Maintain aspect ratio. Certain kinds of animated drawables
2071 // get very confused otherwise.
2072 final int intrinsicWidth = mIndeterminateDrawable.getIntrinsicWidth();
2073 final int intrinsicHeight = mIndeterminateDrawable.getIntrinsicHeight();
2074 final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight;
2075 final float boundAspect = (float) w / h;
2076 if (intrinsicAspect != boundAspect) {
2077 if (boundAspect > intrinsicAspect) {
2078 // New width is larger. Make it smaller to match height.
2079 final int width = (int) (h * intrinsicAspect);
2080 left = (w - width) / 2;
2081 right = left + width;
2082 } else {
2083 // New height is larger. Make it smaller to match width.
2084 final int height = (int) (w * (1 / intrinsicAspect));
2085 top = (h - height) / 2;
2086 bottom = top + height;
2087 }
2088 }
2089 }
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -08002090 if (isLayoutRtl() && mMirrorForRtl) {
Fabrice Di Meglio7fb98b32012-09-12 20:04:04 -07002091 int tempLeft = left;
2092 left = w - right;
2093 right = w - tempLeft;
2094 }
Adam Powella1b92c52011-09-02 15:05:15 -07002095 mIndeterminateDrawable.setBounds(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002096 }
RoboErik5b071432015-02-11 13:52:05 -08002097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 if (mProgressDrawable != null) {
2099 mProgressDrawable.setBounds(0, 0, right, bottom);
2100 }
2101 }
2102
2103 @Override
2104 protected synchronized void onDraw(Canvas canvas) {
2105 super.onDraw(canvas);
2106
Alan Viverette661e6362014-05-12 10:55:37 -07002107 drawTrack(canvas);
2108 }
2109
2110 /**
2111 * Draws the progress bar track.
2112 */
2113 void drawTrack(Canvas canvas) {
2114 final Drawable d = mCurrentDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002115 if (d != null) {
2116 // Translate canvas so a indeterminate circular progress bar with padding
2117 // rotates properly in its animation
Alan Viverette661e6362014-05-12 10:55:37 -07002118 final int saveCount = canvas.save();
2119
Alan Viverette6a8253f2015-02-23 12:49:47 -08002120 if (isLayoutRtl() && mMirrorForRtl) {
Fabrice Di Meglio7fb98b32012-09-12 20:04:04 -07002121 canvas.translate(getWidth() - mPaddingRight, mPaddingTop);
2122 canvas.scale(-1.0f, 1.0f);
2123 } else {
2124 canvas.translate(mPaddingLeft, mPaddingTop);
2125 }
Alan Viverette661e6362014-05-12 10:55:37 -07002126
2127 final long time = getDrawingTime();
Romain Guyab4c4f4f2012-05-06 13:11:24 -07002128 if (mHasAnimation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 mAnimation.getTransformation(time, mTransformation);
Alan Viverette661e6362014-05-12 10:55:37 -07002130 final float scale = mTransformation.getAlpha();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002131 try {
2132 mInDrawing = true;
2133 d.setLevel((int) (scale * MAX_LEVEL));
2134 } finally {
2135 mInDrawing = false;
2136 }
Jeff Brown6cb7b462012-03-05 13:21:17 -08002137 postInvalidateOnAnimation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002138 }
Alan Viverette661e6362014-05-12 10:55:37 -07002139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140 d.draw(canvas);
Alan Viverette661e6362014-05-12 10:55:37 -07002141 canvas.restoreToCount(saveCount);
2142
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07002143 if (mShouldStartAnimationDrawable && d instanceof Animatable) {
2144 ((Animatable) d).start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 mShouldStartAnimationDrawable = false;
2146 }
2147 }
2148 }
2149
2150 @Override
2151 protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 int dw = 0;
2153 int dh = 0;
Alan Viverette6a8253f2015-02-23 12:49:47 -08002154
2155 final Drawable d = mCurrentDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 if (d != null) {
2157 dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
2158 dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
2159 }
Alan Viverette6a8253f2015-02-23 12:49:47 -08002160
Joe Onoratoaa072632010-12-08 15:31:28 -08002161 updateDrawableState();
Alan Viverette6a8253f2015-02-23 12:49:47 -08002162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 dw += mPaddingLeft + mPaddingRight;
2164 dh += mPaddingTop + mPaddingBottom;
2165
Alan Viverette6a8253f2015-02-23 12:49:47 -08002166 final int measuredWidth = resolveSizeAndState(dw, widthMeasureSpec, 0);
2167 final int measuredHeight = resolveSizeAndState(dh, heightMeasureSpec, 0);
2168 setMeasuredDimension(measuredWidth, measuredHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002169 }
RoboErik5b071432015-02-11 13:52:05 -08002170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 @Override
2172 protected void drawableStateChanged() {
2173 super.drawableStateChanged();
Joe Onoratoaa072632010-12-08 15:31:28 -08002174 updateDrawableState();
2175 }
RoboErik5b071432015-02-11 13:52:05 -08002176
Joe Onoratoaa072632010-12-08 15:31:28 -08002177 private void updateDrawableState() {
Alan Viverette6a8253f2015-02-23 12:49:47 -08002178 final int[] state = getDrawableState();
Alan Viverettead0020f2015-09-04 10:10:42 -04002179 boolean changed = false;
RoboErik5b071432015-02-11 13:52:05 -08002180
Alan Viverettead0020f2015-09-04 10:10:42 -04002181 final Drawable progressDrawable = mProgressDrawable;
2182 if (progressDrawable != null && progressDrawable.isStateful()) {
2183 changed |= progressDrawable.setState(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 }
RoboErik5b071432015-02-11 13:52:05 -08002185
Alan Viverettead0020f2015-09-04 10:10:42 -04002186 final Drawable indeterminateDrawable = mIndeterminateDrawable;
2187 if (indeterminateDrawable != null && indeterminateDrawable.isStateful()) {
2188 changed |= indeterminateDrawable.setState(state);
2189 }
2190
2191 if (changed) {
2192 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002193 }
2194 }
2195
Alan Viverettecebc6ba2014-06-13 15:52:13 -07002196 @Override
Alan Viverette8de14942014-06-18 18:05:15 -07002197 public void drawableHotspotChanged(float x, float y) {
2198 super.drawableHotspotChanged(x, y);
Alan Viverettecebc6ba2014-06-13 15:52:13 -07002199
2200 if (mProgressDrawable != null) {
2201 mProgressDrawable.setHotspot(x, y);
2202 }
2203
2204 if (mIndeterminateDrawable != null) {
2205 mIndeterminateDrawable.setHotspot(x, y);
2206 }
2207 }
2208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 static class SavedState extends BaseSavedState {
2210 int progress;
2211 int secondaryProgress;
RoboErik5b071432015-02-11 13:52:05 -08002212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 /**
2214 * Constructor called from {@link ProgressBar#onSaveInstanceState()}
2215 */
2216 SavedState(Parcelable superState) {
2217 super(superState);
2218 }
RoboErik5b071432015-02-11 13:52:05 -08002219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002220 /**
2221 * Constructor called from {@link #CREATOR}
2222 */
2223 private SavedState(Parcel in) {
2224 super(in);
2225 progress = in.readInt();
2226 secondaryProgress = in.readInt();
2227 }
2228
2229 @Override
2230 public void writeToParcel(Parcel out, int flags) {
2231 super.writeToParcel(out, flags);
2232 out.writeInt(progress);
2233 out.writeInt(secondaryProgress);
2234 }
2235
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07002236 public static final @android.annotation.NonNull Parcelable.Creator<SavedState> CREATOR
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002237 = new Parcelable.Creator<SavedState>() {
2238 public SavedState createFromParcel(Parcel in) {
2239 return new SavedState(in);
2240 }
2241
2242 public SavedState[] newArray(int size) {
2243 return new SavedState[size];
2244 }
2245 };
2246 }
2247
2248 @Override
2249 public Parcelable onSaveInstanceState() {
2250 // Force our ancestor class to save its state
2251 Parcelable superState = super.onSaveInstanceState();
2252 SavedState ss = new SavedState(superState);
RoboErik5b071432015-02-11 13:52:05 -08002253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254 ss.progress = mProgress;
2255 ss.secondaryProgress = mSecondaryProgress;
RoboErik5b071432015-02-11 13:52:05 -08002256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002257 return ss;
2258 }
2259
2260 @Override
2261 public void onRestoreInstanceState(Parcelable state) {
2262 SavedState ss = (SavedState) state;
2263 super.onRestoreInstanceState(ss.getSuperState());
RoboErik5b071432015-02-11 13:52:05 -08002264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002265 setProgress(ss.progress);
2266 setSecondaryProgress(ss.secondaryProgress);
2267 }
David Sobreira Marques52a35432010-05-15 16:10:18 -03002268
2269 @Override
2270 protected void onAttachedToWindow() {
2271 super.onAttachedToWindow();
2272 if (mIndeterminate) {
2273 startAnimation();
2274 }
Adam Powella0506632012-04-10 17:19:20 -07002275 if (mRefreshData != null) {
2276 synchronized (this) {
2277 final int count = mRefreshData.size();
2278 for (int i = 0; i < count; i++) {
2279 final RefreshData rd = mRefreshData.get(i);
Alan Viverettea64ed3b2015-09-23 10:01:45 -04002280 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate);
Adam Powella0506632012-04-10 17:19:20 -07002281 rd.recycle();
2282 }
2283 mRefreshData.clear();
2284 }
2285 }
2286 mAttached = true;
David Sobreira Marques52a35432010-05-15 16:10:18 -03002287 }
2288
2289 @Override
2290 protected void onDetachedFromWindow() {
David Sobreira Marques52a35432010-05-15 16:10:18 -03002291 if (mIndeterminate) {
2292 stopAnimation();
2293 }
Adam Powella0506632012-04-10 17:19:20 -07002294 if (mRefreshProgressRunnable != null) {
2295 removeCallbacks(mRefreshProgressRunnable);
Bing Deng24a2bc72012-11-08 13:35:15 +08002296 mRefreshIsPosted = false;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07002297 }
Patrick Dubroyec84c3a2011-01-13 17:55:37 -08002298 // This should come after stopAnimation(), otherwise an invalidate message remains in the
2299 // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
2300 super.onDetachedFromWindow();
Adam Powella0506632012-04-10 17:19:20 -07002301 mAttached = false;
David Sobreira Marques52a35432010-05-15 16:10:18 -03002302 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07002303
2304 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08002305 public CharSequence getAccessibilityClassName() {
2306 return ProgressBar.class.getName();
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07002307 }
2308
Alan Viverettea54956a2015-01-07 16:05:02 -08002309 /** @hide */
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002310 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08002311 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
2312 super.onInitializeAccessibilityEventInternal(event);
Keyvan Amiri86fb2a22016-09-29 17:53:24 -07002313 event.setItemCount(mMax - mMin);
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08002314 event.setCurrentItemIndex(mProgress);
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002315 }
2316
Maxim Bogatov32e59d52015-04-30 16:57:33 -07002317 /** @hide */
2318 @Override
2319 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2320 super.onInitializeAccessibilityNodeInfoInternal(info);
2321
2322 if (!isIndeterminate()) {
2323 AccessibilityNodeInfo.RangeInfo rangeInfo = AccessibilityNodeInfo.RangeInfo.obtain(
Chet Haase25886a162018-03-28 18:26:53 -07002324 AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT, getMin(), getMax(),
2325 getProgress());
Maxim Bogatov32e59d52015-04-30 16:57:33 -07002326 info.setRangeInfo(rangeInfo);
2327 }
2328 }
2329
Siva Velusamy94a6d152015-05-05 15:07:00 -07002330 /** @hide */
2331 @Override
2332 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) {
2333 super.encodeProperties(stream);
2334
2335 stream.addProperty("progress:max", getMax());
2336 stream.addProperty("progress:progress", getProgress());
2337 stream.addProperty("progress:secondaryProgress", getSecondaryProgress());
2338 stream.addProperty("progress:indeterminate", isIndeterminate());
2339 }
2340
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07002341 /**
Chet Haaseb64e777f2016-12-09 07:17:10 -08002342 * Returns whether the ProgressBar is animating or not. This is essentially the same
2343 * as whether the ProgressBar is {@link #isIndeterminate() indeterminate} and visible,
2344 * as indeterminate ProgressBars are always animating, and non-indeterminate
2345 * ProgressBars are not animating.
2346 *
2347 * @return true if the ProgressBar is animating, false otherwise.
2348 */
2349 public boolean isAnimating() {
2350 return isIndeterminate() && getWindowVisibility() == VISIBLE && isShown();
2351 }
2352
Alan Viveretteb56f5d22014-09-14 15:48:50 -07002353 private static class ProgressTintInfo {
2354 ColorStateList mIndeterminateTintList;
Nader Jawad8e31c3e2019-04-14 21:58:04 -07002355 BlendMode mIndeterminateBlendMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -07002356 boolean mHasIndeterminateTint;
2357 boolean mHasIndeterminateTintMode;
2358
2359 ColorStateList mProgressTintList;
Nader Jawad8e31c3e2019-04-14 21:58:04 -07002360 BlendMode mProgressBlendMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -07002361 boolean mHasProgressTint;
2362 boolean mHasProgressTintMode;
2363
2364 ColorStateList mProgressBackgroundTintList;
Nader Jawad8e31c3e2019-04-14 21:58:04 -07002365 BlendMode mProgressBackgroundBlendMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -07002366 boolean mHasProgressBackgroundTint;
2367 boolean mHasProgressBackgroundTintMode;
2368
2369 ColorStateList mSecondaryProgressTintList;
Nader Jawad8e31c3e2019-04-14 21:58:04 -07002370 BlendMode mSecondaryProgressBlendMode;
Alan Viveretteb56f5d22014-09-14 15:48:50 -07002371 boolean mHasSecondaryProgressTint;
2372 boolean mHasSecondaryProgressTintMode;
2373 }
Alan Viverettea64ed3b2015-09-23 10:01:45 -04002374
2375 /**
2376 * Property wrapper around the visual state of the {@code progress} functionality
2377 * handled by the {@link ProgressBar#setProgress(int, boolean)} method. This does
2378 * not correspond directly to the actual progress -- only the visual state.
2379 */
2380 private final FloatProperty<ProgressBar> VISUAL_PROGRESS =
2381 new FloatProperty<ProgressBar>("visual_progress") {
2382 @Override
2383 public void setValue(ProgressBar object, float value) {
2384 object.setVisualProgress(R.id.progress, value);
2385 object.mVisualProgress = value;
2386 }
2387
2388 @Override
2389 public Float get(ProgressBar object) {
2390 return object.mVisualProgress;
2391 }
2392 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002393}