blob: 24e9cbef3091da11a278931c9a02c8a84fa5eef9 [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 Viverette91174362014-06-17 14:51:45 -070019import android.annotation.Nullable;
20import android.graphics.PorterDuff;
RoboErik5b071432015-02-11 13:52:05 -080021
Svetoslav Ganov6518ad72011-03-18 16:19:55 -070022import com.android.internal.R;
23
Tor Norbye7b9c9122013-05-30 16:48:33 -070024import android.annotation.InterpolatorRes;
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;
28import android.graphics.Bitmap;
29import android.graphics.BitmapShader;
30import android.graphics.Canvas;
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;
39import android.graphics.drawable.ShapeDrawable;
40import android.graphics.drawable.StateListDrawable;
41import android.graphics.drawable.shapes.RoundRectShape;
42import android.graphics.drawable.shapes.Shape;
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;
Svetoslav Ganovabae2a12012-11-27 16:59:37 -080046import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.view.Gravity;
Steve Howardb25ffff2010-08-20 17:39:26 -070048import android.view.RemotableViewMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.view.View;
Steve Zeigler7a367882010-02-23 16:39:08 -080050import android.view.ViewDebug;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -070051import android.view.accessibility.AccessibilityEvent;
52import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.view.animation.AlphaAnimation;
54import android.view.animation.Animation;
55import android.view.animation.AnimationUtils;
56import android.view.animation.Interpolator;
57import android.view.animation.LinearInterpolator;
58import android.view.animation.Transformation;
59import android.widget.RemoteViews.RemoteView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060
Adam Powella0506632012-04-10 17:19:20 -070061import java.util.ArrayList;
62
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063/**
64 * <p>
65 * Visual indicator of progress in some operation. Displays a bar to the user
RoboErik5b071432015-02-11 13:52:05 -080066 * representing how far the operation has progressed; the application can
67 * change the amount of progress (modifying the length of the bar) as it moves
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 * forward. There is also a secondary progress displayable on a progress bar
69 * which is useful for displaying intermediate progress, such as the buffer
70 * level during a streaming playback progress bar.
71 * </p>
72 *
73 * <p>
74 * A progress bar can also be made indeterminate. In indeterminate mode, the
Scott Main42f139c2011-04-29 10:31:10 -070075 * progress bar shows a cyclic animation without an indication of progress. This mode is used by
76 * applications when the length of the task is unknown. The indeterminate progress bar can be either
77 * a spinning wheel or a horizontal bar.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 * </p>
79 *
80 * <p>The following code example shows how a progress bar can be used from
81 * a worker thread to update the user interface to notify the user of progress:
82 * </p>
RoboErik5b071432015-02-11 13:52:05 -080083 *
Scott Main42f139c2011-04-29 10:31:10 -070084 * <pre>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 * public class MyActivity extends Activity {
86 * private static final int PROGRESS = 0x1;
87 *
88 * private ProgressBar mProgress;
89 * private int mProgressStatus = 0;
90 *
91 * private Handler mHandler = new Handler();
92 *
93 * protected void onCreate(Bundle icicle) {
94 * super.onCreate(icicle);
95 *
96 * setContentView(R.layout.progressbar_activity);
97 *
98 * mProgress = (ProgressBar) findViewById(R.id.progress_bar);
99 *
100 * // Start lengthy operation in a background thread
101 * new Thread(new Runnable() {
102 * public void run() {
Scott Main42f139c2011-04-29 10:31:10 -0700103 * while (mProgressStatus &lt; 100) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 * mProgressStatus = doWork();
105 *
106 * // Update the progress bar
107 * mHandler.post(new Runnable() {
108 * public void run() {
109 * mProgress.setProgress(mProgressStatus);
110 * }
111 * });
112 * }
113 * }
114 * }).start();
115 * }
Scott Main42f139c2011-04-29 10:31:10 -0700116 * }</pre>
117 *
118 * <p>To add a progress bar to a layout file, you can use the {@code &lt;ProgressBar&gt;} element.
119 * By default, the progress bar is a spinning wheel (an indeterminate indicator). To change to a
120 * horizontal progress bar, apply the {@link android.R.style#Widget_ProgressBar_Horizontal
121 * Widget.ProgressBar.Horizontal} style, like so:</p>
122 *
123 * <pre>
124 * &lt;ProgressBar
125 * style="@android:style/Widget.ProgressBar.Horizontal"
126 * ... /&gt;</pre>
127 *
128 * <p>If you will use the progress bar to show real progress, you must use the horizontal bar. You
129 * can then increment the progress with {@link #incrementProgressBy incrementProgressBy()} or
130 * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If
131 * necessary, you can adjust the maximum value (the value for a full bar) using the {@link
132 * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed
133 * below.</p>
134 *
135 * <p>Another common style to apply to the progress bar is {@link
136 * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller
137 * version of the spinning wheel&mdash;useful when waiting for content to load.
138 * For example, you can insert this kind of progress bar into your default layout for
139 * a view that will be populated by some content fetched from the Internet&mdash;the spinning wheel
140 * appears immediately and when your application receives the content, it replaces the progress bar
141 * with the loaded content. For example:</p>
142 *
143 * <pre>
144 * &lt;LinearLayout
145 * android:orientation="horizontal"
146 * ... &gt;
147 * &lt;ProgressBar
148 * android:layout_width="wrap_content"
149 * android:layout_height="wrap_content"
150 * style="@android:style/Widget.ProgressBar.Small"
151 * android:layout_marginRight="5dp" /&gt;
152 * &lt;TextView
153 * android:layout_width="wrap_content"
154 * android:layout_height="wrap_content"
155 * android:text="@string/loading" /&gt;
156 * &lt;/LinearLayout&gt;</pre>
157 *
158 * <p>Other progress bar styles provided by the system include:</p>
159 * <ul>
160 * <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li>
161 * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li>
162 * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li>
163 * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li>
164 * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse
165 * Widget.ProgressBar.Small.Inverse}</li>
166 * <li>{@link android.R.style#Widget_ProgressBar_Large_Inverse
167 * Widget.ProgressBar.Large.Inverse}</li>
168 * </ul>
169 * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
170 * if your application uses a light colored theme (a white background).</p>
RoboErik5b071432015-02-11 13:52:05 -0800171 *
172 * <p><strong>XML attributes</b></strong>
173 * <p>
174 * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 * {@link android.R.styleable#View View Attributes}
176 * </p>
RoboErik5b071432015-02-11 13:52:05 -0800177 *
Scott Main42f139c2011-04-29 10:31:10 -0700178 * @attr ref android.R.styleable#ProgressBar_animationResolution
179 * @attr ref android.R.styleable#ProgressBar_indeterminate
180 * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
181 * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
182 * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
183 * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
184 * @attr ref android.R.styleable#ProgressBar_interpolator
185 * @attr ref android.R.styleable#ProgressBar_max
186 * @attr ref android.R.styleable#ProgressBar_maxHeight
187 * @attr ref android.R.styleable#ProgressBar_maxWidth
188 * @attr ref android.R.styleable#ProgressBar_minHeight
189 * @attr ref android.R.styleable#ProgressBar_minWidth
Scott Mainb40c1fd2013-04-23 13:30:06 -0700190 * @attr ref android.R.styleable#ProgressBar_mirrorForRtl
Scott Main42f139c2011-04-29 10:31:10 -0700191 * @attr ref android.R.styleable#ProgressBar_progress
192 * @attr ref android.R.styleable#ProgressBar_progressDrawable
193 * @attr ref android.R.styleable#ProgressBar_secondaryProgress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 */
195@RemoteView
196public class ProgressBar extends View {
197 private static final int MAX_LEVEL = 10000;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700198 private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
200 int mMinWidth;
201 int mMaxWidth;
202 int mMinHeight;
203 int mMaxHeight;
204
205 private int mProgress;
206 private int mSecondaryProgress;
207 private int mMax;
208
209 private int mBehavior;
210 private int mDuration;
211 private boolean mIndeterminate;
212 private boolean mOnlyIndeterminate;
213 private Transformation mTransformation;
214 private AlphaAnimation mAnimation;
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700215 private boolean mHasAnimation;
Alan Viverette91174362014-06-17 14:51:45 -0700216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 private Drawable mIndeterminateDrawable;
218 private Drawable mProgressDrawable;
219 private Drawable mCurrentDrawable;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700220 private ProgressTintInfo mProgressTintInfo;
221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 Bitmap mSampleTile;
223 private boolean mNoInvalidate;
224 private Interpolator mInterpolator;
225 private RefreshProgressRunnable mRefreshProgressRunnable;
226 private long mUiThreadId;
227 private boolean mShouldStartAnimationDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228
229 private boolean mInDrawing;
Adam Powella0506632012-04-10 17:19:20 -0700230 private boolean mAttached;
231 private boolean mRefreshIsPosted;
232
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800233 boolean mMirrorForRtl = false;
234
Adam Powella0506632012-04-10 17:19:20 -0700235 private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700237 private AccessibilityEventSender mAccessibilityEventSender;
238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 /**
240 * Create a new progress bar with range 0...100 and initial progress of 0.
241 * @param context the application environment
242 */
243 public ProgressBar(Context context) {
244 this(context, null);
245 }
RoboErik5b071432015-02-11 13:52:05 -0800246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 public ProgressBar(Context context, AttributeSet attrs) {
248 this(context, attrs, com.android.internal.R.attr.progressBarStyle);
249 }
250
Alan Viverette617feb92013-09-09 18:09:13 -0700251 public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
252 this(context, attrs, defStyleAttr, 0);
Adam Powell6af97e12010-11-11 21:11:53 -0800253 }
254
Alan Viverette617feb92013-09-09 18:09:13 -0700255 public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
256 super(context, attrs, defStyleAttr, defStyleRes);
257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 mUiThreadId = Thread.currentThread().getId();
259 initProgressBar();
260
Alan Viverette617feb92013-09-09 18:09:13 -0700261 final TypedArray a = context.obtainStyledAttributes(
262 attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
RoboErik5b071432015-02-11 13:52:05 -0800263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 mNoInvalidate = true;
RoboErik5b071432015-02-11 13:52:05 -0800265
Alan Viverette91174362014-06-17 14:51:45 -0700266 final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
267 if (progressDrawable != null) {
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700268 // Calling setProgressDrawable can set mMaxHeight, so make sure the
269 // corresponding XML attribute for mMaxHeight is read after calling
270 // this method.
271 if (needsTileify(progressDrawable)) {
272 setProgressDrawableTiled(progressDrawable);
273 } else {
274 setProgressDrawable(progressDrawable);
275 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 }
277
278
279 mDuration = a.getInt(R.styleable.ProgressBar_indeterminateDuration, mDuration);
280
281 mMinWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_minWidth, mMinWidth);
282 mMaxWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_maxWidth, mMaxWidth);
283 mMinHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_minHeight, mMinHeight);
284 mMaxHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_maxHeight, mMaxHeight);
285
286 mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);
287
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700288 final int resID = a.getResourceId(
RoboErik5b071432015-02-11 13:52:05 -0800289 com.android.internal.R.styleable.ProgressBar_interpolator,
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700290 android.R.anim.linear_interpolator); // default to linear interpolator
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 if (resID > 0) {
292 setInterpolator(context, resID);
RoboErik5b071432015-02-11 13:52:05 -0800293 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294
295 setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
296
297 setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
298
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700299 setSecondaryProgress(a.getInt(
300 R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301
Alan Viverette91174362014-06-17 14:51:45 -0700302 final Drawable indeterminateDrawable = a.getDrawable(
303 R.styleable.ProgressBar_indeterminateDrawable);
304 if (indeterminateDrawable != null) {
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700305 if (needsTileify(indeterminateDrawable)) {
306 setIndeterminateDrawableTiled(indeterminateDrawable);
307 } else {
308 setIndeterminateDrawable(indeterminateDrawable);
309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 }
311
312 mOnlyIndeterminate = a.getBoolean(
313 R.styleable.ProgressBar_indeterminateOnly, mOnlyIndeterminate);
314
315 mNoInvalidate = false;
316
317 setIndeterminate(mOnlyIndeterminate || a.getBoolean(
318 R.styleable.ProgressBar_indeterminate, mIndeterminate));
319
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800320 mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);
321
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700322 if (a.hasValue(R.styleable.ProgressBar_progressTintMode)) {
323 if (mProgressTintInfo == null) {
324 mProgressTintInfo = new ProgressTintInfo();
325 }
326 mProgressTintInfo.mProgressTintMode = Drawable.parseTintMode(a.getInt(
Alan Viverettedbc40182015-04-06 15:01:23 -0700327 R.styleable.ProgressBar_progressTintMode, -1), null);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700328 mProgressTintInfo.mHasProgressTintMode = true;
329 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700330
Alan Viverette91174362014-06-17 14:51:45 -0700331 if (a.hasValue(R.styleable.ProgressBar_progressTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700332 if (mProgressTintInfo == null) {
333 mProgressTintInfo = new ProgressTintInfo();
334 }
335 mProgressTintInfo.mProgressTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700336 R.styleable.ProgressBar_progressTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700337 mProgressTintInfo.mHasProgressTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700338 }
339
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700340 if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTintMode)) {
341 if (mProgressTintInfo == null) {
342 mProgressTintInfo = new ProgressTintInfo();
343 }
344 mProgressTintInfo.mProgressBackgroundTintMode = Drawable.parseTintMode(a.getInt(
Alan Viverettedbc40182015-04-06 15:01:23 -0700345 R.styleable.ProgressBar_progressBackgroundTintMode, -1), null);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700346 mProgressTintInfo.mHasProgressBackgroundTintMode = true;
347 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700348
Alan Viverette91174362014-06-17 14:51:45 -0700349 if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700350 if (mProgressTintInfo == null) {
351 mProgressTintInfo = new ProgressTintInfo();
352 }
353 mProgressTintInfo.mProgressBackgroundTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700354 R.styleable.ProgressBar_progressBackgroundTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700355 mProgressTintInfo.mHasProgressBackgroundTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700356 }
357
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700358 if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTintMode)) {
359 if (mProgressTintInfo == null) {
360 mProgressTintInfo = new ProgressTintInfo();
361 }
362 mProgressTintInfo.mSecondaryProgressTintMode = Drawable.parseTintMode(
363 a.getInt(R.styleable.ProgressBar_secondaryProgressTintMode, -1), null);
364 mProgressTintInfo.mHasSecondaryProgressTintMode = true;
365 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700366
Alan Viverette91174362014-06-17 14:51:45 -0700367 if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700368 if (mProgressTintInfo == null) {
369 mProgressTintInfo = new ProgressTintInfo();
370 }
371 mProgressTintInfo.mSecondaryProgressTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700372 R.styleable.ProgressBar_secondaryProgressTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700373 mProgressTintInfo.mHasSecondaryProgressTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700374 }
375
Alan Viverettedbc40182015-04-06 15:01:23 -0700376 if (a.hasValue(R.styleable.ProgressBar_indeterminateTintMode)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700377 if (mProgressTintInfo == null) {
378 mProgressTintInfo = new ProgressTintInfo();
379 }
380 mProgressTintInfo.mIndeterminateTintMode = Drawable.parseTintMode(a.getInt(
381 R.styleable.ProgressBar_indeterminateTintMode, -1), null);
382 mProgressTintInfo.mHasIndeterminateTintMode = true;
383 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700384
Alan Viverette91174362014-06-17 14:51:45 -0700385 if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700386 if (mProgressTintInfo == null) {
387 mProgressTintInfo = new ProgressTintInfo();
388 }
389 mProgressTintInfo.mIndeterminateTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700390 R.styleable.ProgressBar_indeterminateTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700391 mProgressTintInfo.mHasIndeterminateTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700392 }
393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 a.recycle();
Svetoslav7face752014-01-13 15:25:58 -0800395
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700396 applyProgressTints();
397 applyIndeterminateTint();
398
Svetoslav7face752014-01-13 15:25:58 -0800399 // If not explicitly specified this view is important for accessibility.
400 if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
401 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
402 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 }
404
405 /**
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700406 * Returns {@code true} if the target drawable needs to be tileified.
407 *
408 * @param dr the drawable to check
409 * @return {@code true} if the target drawable needs to be tileified,
410 * {@code false} otherwise
411 */
412 private static boolean needsTileify(Drawable dr) {
413 if (dr instanceof LayerDrawable) {
414 final LayerDrawable orig = (LayerDrawable) dr;
415 final int N = orig.getNumberOfLayers();
416 for (int i = 0; i < N; i++) {
417 if (needsTileify(orig.getDrawable(i))) {
418 return true;
419 }
420 }
421 return false;
422 }
423
424 if (dr instanceof StateListDrawable) {
425 final StateListDrawable in = (StateListDrawable) dr;
426 final int N = in.getStateCount();
427 for (int i = 0; i < N; i++) {
428 if (needsTileify(in.getStateDrawable(i))) {
429 return true;
430 }
431 }
432 return false;
433 }
434
435 // If there's a bitmap that's not wrapped with a ClipDrawable or
436 // ScaleDrawable, we'll need to wrap it and apply tiling.
437 if (dr instanceof BitmapDrawable) {
438 return true;
439 }
440
441 return false;
442 }
443
444 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 * Converts a drawable to a tiled version of itself. It will recursively
446 * traverse layer and state list drawables.
447 */
448 private Drawable tileify(Drawable drawable, boolean clip) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800449 // TODO: This is a terrible idea that potentially destroys any drawable
450 // that extends any of these classes. We *really* need to remove this.
RoboErik5b071432015-02-11 13:52:05 -0800451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 if (drawable instanceof LayerDrawable) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800453 final LayerDrawable orig = (LayerDrawable) drawable;
454 final int N = orig.getNumberOfLayers();
455 final Drawable[] outDrawables = new Drawable[N];
RoboErik5b071432015-02-11 13:52:05 -0800456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 for (int i = 0; i < N; i++) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800458 final int id = orig.getId(i);
459 outDrawables[i] = tileify(orig.getDrawable(i),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 (id == R.id.progress || id == R.id.secondaryProgress));
461 }
462
Alan Viverette6a8253f2015-02-23 12:49:47 -0800463 final LayerDrawable clone = new LayerDrawable(outDrawables);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 for (int i = 0; i < N; i++) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800465 clone.setId(i, orig.getId(i));
466 clone.setLayerGravity(i, orig.getLayerGravity(i));
467 clone.setLayerWidth(i, orig.getLayerWidth(i));
468 clone.setLayerHeight(i, orig.getLayerHeight(i));
469 clone.setLayerInsetLeft(i, orig.getLayerInsetLeft(i));
470 clone.setLayerInsetRight(i, orig.getLayerInsetRight(i));
471 clone.setLayerInsetTop(i, orig.getLayerInsetTop(i));
472 clone.setLayerInsetBottom(i, orig.getLayerInsetBottom(i));
473 clone.setLayerInsetStart(i, orig.getLayerInsetStart(i));
474 clone.setLayerInsetEnd(i, orig.getLayerInsetEnd(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 }
RoboErik5b071432015-02-11 13:52:05 -0800476
Alan Viverette6a8253f2015-02-23 12:49:47 -0800477 return clone;
478 }
RoboErik5b071432015-02-11 13:52:05 -0800479
Alan Viverette6a8253f2015-02-23 12:49:47 -0800480 if (drawable instanceof StateListDrawable) {
481 final StateListDrawable in = (StateListDrawable) drawable;
482 final StateListDrawable out = new StateListDrawable();
483 final int N = in.getStateCount();
484 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
486 }
RoboErik5b071432015-02-11 13:52:05 -0800487
Alan Viverette6a8253f2015-02-23 12:49:47 -0800488 return out;
489 }
490
491 if (drawable instanceof BitmapDrawable) {
Alan Viverette813d85b2014-02-26 15:38:51 -0800492 final BitmapDrawable bitmap = (BitmapDrawable) drawable;
493 final Bitmap tileBitmap = bitmap.getBitmap();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 if (mSampleTile == null) {
495 mSampleTile = tileBitmap;
496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700498 final BitmapDrawable clone = (BitmapDrawable) bitmap.getConstantState().newDrawable();
499 clone.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700501 if (clip) {
502 return new ClipDrawable(clone, Gravity.LEFT, ClipDrawable.HORIZONTAL);
503 } else {
504 return clone;
505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 }
RoboErik5b071432015-02-11 13:52:05 -0800507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 return drawable;
509 }
510
511 Shape getDrawableShape() {
512 final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
513 return new RoundRectShape(roundedCorners, null, null);
514 }
RoboErik5b071432015-02-11 13:52:05 -0800515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 /**
517 * Convert a AnimationDrawable for use as a barberpole animation.
518 * Each frame of the animation is wrapped in a ClipDrawable and
519 * given a tiling BitmapShader.
520 */
521 private Drawable tileifyIndeterminate(Drawable drawable) {
522 if (drawable instanceof AnimationDrawable) {
523 AnimationDrawable background = (AnimationDrawable) drawable;
524 final int N = background.getNumberOfFrames();
525 AnimationDrawable newBg = new AnimationDrawable();
526 newBg.setOneShot(background.isOneShot());
RoboErik5b071432015-02-11 13:52:05 -0800527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 for (int i = 0; i < N; i++) {
529 Drawable frame = tileify(background.getFrame(i), true);
530 frame.setLevel(10000);
531 newBg.addFrame(frame, background.getDuration(i));
532 }
533 newBg.setLevel(10000);
534 drawable = newBg;
535 }
536 return drawable;
537 }
RoboErik5b071432015-02-11 13:52:05 -0800538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 /**
540 * <p>
541 * Initialize the progress bar's default values:
542 * </p>
543 * <ul>
544 * <li>progress = 0</li>
545 * <li>max = 100</li>
546 * <li>animation duration = 4000 ms</li>
547 * <li>indeterminate = false</li>
548 * <li>behavior = repeat</li>
549 * </ul>
550 */
551 private void initProgressBar() {
552 mMax = 100;
553 mProgress = 0;
554 mSecondaryProgress = 0;
555 mIndeterminate = false;
556 mOnlyIndeterminate = false;
557 mDuration = 4000;
558 mBehavior = AlphaAnimation.RESTART;
559 mMinWidth = 24;
560 mMaxWidth = 48;
561 mMinHeight = 24;
562 mMaxHeight = 48;
563 }
564
565 /**
566 * <p>Indicate whether this progress bar is in indeterminate mode.</p>
567 *
568 * @return true if the progress bar is in indeterminate mode
569 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700570 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 public synchronized boolean isIndeterminate() {
572 return mIndeterminate;
573 }
574
575 /**
576 * <p>Change the indeterminate mode for this progress bar. In indeterminate
577 * mode, the progress is ignored and the progress bar shows an infinite
578 * animation instead.</p>
RoboErik5b071432015-02-11 13:52:05 -0800579 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 * If this progress bar's style only supports indeterminate mode (such as the circular
581 * progress bars), then this will be ignored.
582 *
583 * @param indeterminate true to enable the indeterminate mode
584 */
585 @android.view.RemotableViewMethod
586 public synchronized void setIndeterminate(boolean indeterminate) {
587 if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
588 mIndeterminate = indeterminate;
589
590 if (indeterminate) {
591 // swap between indeterminate and regular backgrounds
592 mCurrentDrawable = mIndeterminateDrawable;
593 startAnimation();
594 } else {
595 mCurrentDrawable = mProgressDrawable;
596 stopAnimation();
597 }
598 }
599 }
600
601 /**
602 * <p>Get the drawable used to draw the progress bar in
603 * indeterminate mode.</p>
604 *
605 * @return a {@link android.graphics.drawable.Drawable} instance
606 *
607 * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable)
608 * @see #setIndeterminate(boolean)
609 */
610 public Drawable getIndeterminateDrawable() {
611 return mIndeterminateDrawable;
612 }
613
614 /**
Alan Viverettee785d022013-09-26 15:21:10 -0700615 * Define the drawable used to draw the progress bar in indeterminate mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 *
617 * @param d the new drawable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 * @see #getIndeterminateDrawable()
619 * @see #setIndeterminate(boolean)
620 */
621 public void setIndeterminateDrawable(Drawable d) {
Alan Viverette91174362014-06-17 14:51:45 -0700622 if (mIndeterminateDrawable != d) {
623 if (mIndeterminateDrawable != null) {
624 mIndeterminateDrawable.setCallback(null);
625 unscheduleDrawable(mIndeterminateDrawable);
626 }
627
628 mIndeterminateDrawable = d;
629
630 if (d != null) {
631 d.setCallback(this);
632 d.setLayoutDirection(getLayoutDirection());
633 if (d.isStateful()) {
634 d.setState(getDrawableState());
635 }
636 applyIndeterminateTint();
637 }
638
639 if (mIndeterminate) {
640 mCurrentDrawable = d;
641 postInvalidate();
642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 }
Alan Viverette91174362014-06-17 14:51:45 -0700644 }
645
646 /**
Alan Viverette91174362014-06-17 14:51:45 -0700647 * Applies a tint to the indeterminate drawable. Does not modify the
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700648 * current tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -0700649 * <p>
650 * Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will
651 * automatically mutate the drawable and apply the specified tint and
652 * tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700653 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -0700654 *
655 * @param tint the tint to apply, may be {@code null} to clear tint
656 *
657 * @attr ref android.R.styleable#ProgressBar_indeterminateTint
Alan Viverettea4264452014-07-28 16:02:55 -0700658 * @see #getIndeterminateTintList()
659 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700660 */
Jorim Jaggief72a192014-08-26 21:57:46 +0200661 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -0700662 public void setIndeterminateTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700663 if (mProgressTintInfo == null) {
664 mProgressTintInfo = new ProgressTintInfo();
665 }
666 mProgressTintInfo.mIndeterminateTintList = tint;
667 mProgressTintInfo.mHasIndeterminateTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700668
669 applyIndeterminateTint();
Alan Viverette91174362014-06-17 14:51:45 -0700670 }
671
672 /**
673 * @return the tint applied to the indeterminate drawable
674 * @attr ref android.R.styleable#ProgressBar_indeterminateTint
Alan Viverettea4264452014-07-28 16:02:55 -0700675 * @see #setIndeterminateTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700676 */
677 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -0700678 public ColorStateList getIndeterminateTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700679 return mProgressTintInfo != null ? mProgressTintInfo.mIndeterminateTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -0700680 }
681
682 /**
683 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -0700684 * {@link #setIndeterminateTintList(ColorStateList)} to the indeterminate
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700685 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -0700686 *
687 * @param tintMode the blending mode used to apply the tint, may be
688 * {@code null} to clear tint
689 * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
Alan Viverettea4264452014-07-28 16:02:55 -0700690 * @see #setIndeterminateTintList(ColorStateList)
691 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700692 */
693 public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700694 if (mProgressTintInfo == null) {
695 mProgressTintInfo = new ProgressTintInfo();
696 }
697 mProgressTintInfo.mIndeterminateTintMode = tintMode;
698 mProgressTintInfo.mHasIndeterminateTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700699
700 applyIndeterminateTint();
Alan Viverette91174362014-06-17 14:51:45 -0700701 }
702
703 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700704 * Returns the blending mode used to apply the tint to the indeterminate
705 * drawable, if specified.
706 *
707 * @return the blending mode used to apply the tint to the indeterminate
708 * drawable
Alan Viverette91174362014-06-17 14:51:45 -0700709 * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700710 * @see #setIndeterminateTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700711 */
712 @Nullable
713 public PorterDuff.Mode getIndeterminateTintMode() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700714 return mProgressTintInfo != null ? mProgressTintInfo.mIndeterminateTintMode : null;
Alan Viverette91174362014-06-17 14:51:45 -0700715 }
716
717 private void applyIndeterminateTint() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700718 if (mIndeterminateDrawable != null && mProgressTintInfo != null) {
719 final ProgressTintInfo tintInfo = mProgressTintInfo;
720 if (tintInfo.mHasIndeterminateTint || tintInfo.mHasIndeterminateTintMode) {
721 mIndeterminateDrawable = mIndeterminateDrawable.mutate();
722
723 if (tintInfo.mHasIndeterminateTint) {
724 mIndeterminateDrawable.setTintList(tintInfo.mIndeterminateTintList);
725 }
726
727 if (tintInfo.mHasIndeterminateTintMode) {
728 mIndeterminateDrawable.setTintMode(tintInfo.mIndeterminateTintMode);
729 }
Alan Viveretted5133792014-10-28 14:41:36 -0700730
731 // The drawable (or one of its children) may not have been
732 // stateful before applying the tint, so let's try again.
733 if (mIndeterminateDrawable.isStateful()) {
734 mIndeterminateDrawable.setState(getDrawableState());
735 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700736 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 }
738 }
Alan Viverettee785d022013-09-26 15:21:10 -0700739
740 /**
741 * Define the tileable drawable used to draw the progress bar in
742 * indeterminate mode.
743 * <p>
744 * If the drawable is a BitmapDrawable or contains BitmapDrawables, a
745 * tiled copy will be generated for display as a progress bar.
746 *
747 * @param d the new drawable
748 * @see #getIndeterminateDrawable()
749 * @see #setIndeterminate(boolean)
750 */
751 public void setIndeterminateDrawableTiled(Drawable d) {
752 if (d != null) {
753 d = tileifyIndeterminate(d);
754 }
755
756 setIndeterminateDrawable(d);
757 }
RoboErik5b071432015-02-11 13:52:05 -0800758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 /**
760 * <p>Get the drawable used to draw the progress bar in
761 * progress mode.</p>
762 *
763 * @return a {@link android.graphics.drawable.Drawable} instance
764 *
765 * @see #setProgressDrawable(android.graphics.drawable.Drawable)
766 * @see #setIndeterminate(boolean)
767 */
768 public Drawable getProgressDrawable() {
769 return mProgressDrawable;
770 }
771
772 /**
Alan Viverettee785d022013-09-26 15:21:10 -0700773 * Define the drawable used to draw the progress bar in progress mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 *
775 * @param d the new drawable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 * @see #getProgressDrawable()
777 * @see #setIndeterminate(boolean)
778 */
779 public void setProgressDrawable(Drawable d) {
Alan Viverette91174362014-06-17 14:51:45 -0700780 if (mProgressDrawable != d) {
781 if (mProgressDrawable != null) {
782 mProgressDrawable.setCallback(null);
783 unscheduleDrawable(mProgressDrawable);
784 }
Joe Onoratoaa072632010-12-08 15:31:28 -0800785
Alan Viverette91174362014-06-17 14:51:45 -0700786 mProgressDrawable = d;
787
788 if (d != null) {
789 d.setCallback(this);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700790 d.setLayoutDirection(getLayoutDirection());
Alan Viverette91174362014-06-17 14:51:45 -0700791 if (d.isStateful()) {
792 d.setState(getDrawableState());
793 }
794
795 // Make sure the ProgressBar is always tall enough
796 int drawableHeight = d.getMinimumHeight();
797 if (mMaxHeight < drawableHeight) {
798 mMaxHeight = drawableHeight;
799 requestLayout();
800 }
801
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700802 applyProgressTints();
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700803 }
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500804
Alan Viverette91174362014-06-17 14:51:45 -0700805 if (!mIndeterminate) {
806 mCurrentDrawable = d;
807 postInvalidate();
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500808 }
Joe Onoratoaa072632010-12-08 15:31:28 -0800809
Joe Onoratoaa072632010-12-08 15:31:28 -0800810 updateDrawableBounds(getWidth(), getHeight());
811 updateDrawableState();
Alan Viverette91174362014-06-17 14:51:45 -0700812
Joe Onoratoaa072632010-12-08 15:31:28 -0800813 doRefreshProgress(R.id.progress, mProgress, false, false);
814 doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
815 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 }
Alan Viverettee785d022013-09-26 15:21:10 -0700817
818 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700819 * Applies the progress tints in order of increasing specificity.
820 */
821 private void applyProgressTints() {
822 if (mProgressDrawable != null && mProgressTintInfo != null) {
823 applyPrimaryProgressTint();
824 applyProgressBackgroundTint();
825 applySecondaryProgressTint();
826 }
827 }
828
829 /**
830 * Should only be called if we've already verified that mProgressDrawable
831 * and mProgressTintInfo are non-null.
832 */
833 private void applyPrimaryProgressTint() {
834 if (mProgressTintInfo.mHasProgressTint
835 || mProgressTintInfo.mHasProgressTintMode) {
836 final Drawable target = getTintTarget(R.id.progress, true);
837 if (target != null) {
838 if (mProgressTintInfo.mHasProgressTint) {
839 target.setTintList(mProgressTintInfo.mProgressTintList);
840 }
841 if (mProgressTintInfo.mHasProgressTintMode) {
842 target.setTintMode(mProgressTintInfo.mProgressTintMode);
843 }
Alan Viveretted5133792014-10-28 14:41:36 -0700844
845 // The drawable (or one of its children) may not have been
846 // stateful before applying the tint, so let's try again.
847 if (target.isStateful()) {
848 target.setState(getDrawableState());
849 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700850 }
851 }
852 }
853
854 /**
855 * Should only be called if we've already verified that mProgressDrawable
856 * and mProgressTintInfo are non-null.
857 */
858 private void applyProgressBackgroundTint() {
859 if (mProgressTintInfo.mHasProgressBackgroundTint
860 || mProgressTintInfo.mHasProgressBackgroundTintMode) {
861 final Drawable target = getTintTarget(R.id.background, false);
862 if (target != null) {
863 if (mProgressTintInfo.mHasProgressBackgroundTint) {
864 target.setTintList(mProgressTintInfo.mProgressBackgroundTintList);
865 }
866 if (mProgressTintInfo.mHasProgressBackgroundTintMode) {
867 target.setTintMode(mProgressTintInfo.mProgressBackgroundTintMode);
868 }
Alan Viveretted5133792014-10-28 14:41:36 -0700869
870 // The drawable (or one of its children) may not have been
871 // stateful before applying the tint, so let's try again.
872 if (target.isStateful()) {
873 target.setState(getDrawableState());
874 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700875 }
876 }
877 }
878
879 /**
880 * Should only be called if we've already verified that mProgressDrawable
881 * and mProgressTintInfo are non-null.
882 */
883 private void applySecondaryProgressTint() {
884 if (mProgressTintInfo.mHasSecondaryProgressTint
885 || mProgressTintInfo.mHasSecondaryProgressTintMode) {
886 final Drawable target = getTintTarget(R.id.secondaryProgress, false);
887 if (target != null) {
888 if (mProgressTintInfo.mHasSecondaryProgressTint) {
889 target.setTintList(mProgressTintInfo.mSecondaryProgressTintList);
890 }
891 if (mProgressTintInfo.mHasSecondaryProgressTintMode) {
892 target.setTintMode(mProgressTintInfo.mSecondaryProgressTintMode);
893 }
Alan Viveretted5133792014-10-28 14:41:36 -0700894
895 // The drawable (or one of its children) may not have been
896 // stateful before applying the tint, so let's try again.
897 if (target.isStateful()) {
898 target.setState(getDrawableState());
899 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700900 }
901 }
902 }
903
904 /**
Alan Viverette91174362014-06-17 14:51:45 -0700905 * Applies a tint to the progress indicator, if one exists, or to the
Alan Viverette91174362014-06-17 14:51:45 -0700906 * entire progress drawable otherwise. Does not modify the current tint
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700907 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -0700908 * <p>
909 * The progress indicator should be specified as a layer with
910 * id {@link android.R.id#progress} in a {@link LayerDrawable}
911 * used as the progress drawable.
912 * <p>
913 * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
914 * automatically mutate the drawable and apply the specified tint and
915 * tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700916 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -0700917 *
918 * @param tint the tint to apply, may be {@code null} to clear tint
919 *
920 * @attr ref android.R.styleable#ProgressBar_progressTint
Alan Viverettea4264452014-07-28 16:02:55 -0700921 * @see #getProgressTintList()
922 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700923 */
Jorim Jaggief72a192014-08-26 21:57:46 +0200924 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -0700925 public void setProgressTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700926 if (mProgressTintInfo == null) {
927 mProgressTintInfo = new ProgressTintInfo();
928 }
929 mProgressTintInfo.mProgressTintList = tint;
930 mProgressTintInfo.mHasProgressTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700931
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700932 if (mProgressDrawable != null) {
933 applyPrimaryProgressTint();
934 }
Alan Viverette91174362014-06-17 14:51:45 -0700935 }
936
937 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700938 * Returns the tint applied to the progress drawable, if specified.
939 *
Alan Viverette91174362014-06-17 14:51:45 -0700940 * @return the tint applied to the progress drawable
941 * @attr ref android.R.styleable#ProgressBar_progressTint
Alan Viverettea4264452014-07-28 16:02:55 -0700942 * @see #setProgressTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700943 */
944 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -0700945 public ColorStateList getProgressTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700946 return mProgressTintInfo != null ? mProgressTintInfo.mProgressTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -0700947 }
948
949 /**
950 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -0700951 * {@link #setProgressTintList(ColorStateList)}} to the progress
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700952 * indicator. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -0700953 *
954 * @param tintMode the blending mode used to apply the tint, may be
955 * {@code null} to clear tint
956 * @attr ref android.R.styleable#ProgressBar_progressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700957 * @see #getProgressTintMode()
Alan Viverettea4264452014-07-28 16:02:55 -0700958 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700959 */
960 public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700961 if (mProgressTintInfo == null) {
962 mProgressTintInfo = new ProgressTintInfo();
963 }
964 mProgressTintInfo.mProgressTintMode = tintMode;
965 mProgressTintInfo.mHasProgressTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700966
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700967 if (mProgressDrawable != null) {
968 applyPrimaryProgressTint();
969 }
Alan Viverette91174362014-06-17 14:51:45 -0700970 }
971
972 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700973 * Returns the blending mode used to apply the tint to the progress
974 * drawable, if specified.
975 *
976 * @return the blending mode used to apply the tint to the progress
977 * drawable
Alan Viverette91174362014-06-17 14:51:45 -0700978 * @attr ref android.R.styleable#ProgressBar_progressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700979 * @see #setProgressTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700980 */
981 @Nullable
982 public PorterDuff.Mode getProgressTintMode() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700983 return mProgressTintInfo != null ? mProgressTintInfo.mProgressTintMode : null;
Alan Viverette91174362014-06-17 14:51:45 -0700984 }
985
986 /**
Alan Viverette91174362014-06-17 14:51:45 -0700987 * Applies a tint to the progress background, if one exists. Does not
988 * modify the current tint mode, which is
989 * {@link PorterDuff.Mode#SRC_ATOP} by default.
990 * <p>
991 * The progress background must be specified as a layer with
992 * id {@link android.R.id#background} in a {@link LayerDrawable}
993 * used as the progress drawable.
994 * <p>
995 * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
996 * drawable contains a progress background will automatically mutate the
997 * drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700998 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -0700999 *
1000 * @param tint the tint to apply, may be {@code null} to clear tint
1001 *
1002 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
Alan Viverettea4264452014-07-28 16:02:55 -07001003 * @see #getProgressBackgroundTintList()
1004 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001005 */
Jorim Jaggief72a192014-08-26 21:57:46 +02001006 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -07001007 public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001008 if (mProgressTintInfo == null) {
1009 mProgressTintInfo = new ProgressTintInfo();
1010 }
1011 mProgressTintInfo.mProgressBackgroundTintList = tint;
1012 mProgressTintInfo.mHasProgressBackgroundTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001013
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001014 if (mProgressDrawable != null) {
1015 applyProgressBackgroundTint();
1016 }
Alan Viverette91174362014-06-17 14:51:45 -07001017 }
1018
1019 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001020 * Returns the tint applied to the progress background, if specified.
1021 *
Alan Viverette91174362014-06-17 14:51:45 -07001022 * @return the tint applied to the progress background
1023 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
Alan Viverettea4264452014-07-28 16:02:55 -07001024 * @see #setProgressBackgroundTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001025 */
1026 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -07001027 public ColorStateList getProgressBackgroundTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001028 return mProgressTintInfo != null ? mProgressTintInfo.mProgressBackgroundTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -07001029 }
1030
1031 /**
1032 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -07001033 * {@link #setProgressBackgroundTintList(ColorStateList)}} to the progress
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001034 * background. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -07001035 *
1036 * @param tintMode the blending mode used to apply the tint, may be
1037 * {@code null} to clear tint
1038 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
Alan Viverettea4264452014-07-28 16:02:55 -07001039 * @see #setProgressBackgroundTintList(ColorStateList)
1040 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001041 */
1042 public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001043 if (mProgressTintInfo == null) {
1044 mProgressTintInfo = new ProgressTintInfo();
1045 }
1046 mProgressTintInfo.mProgressBackgroundTintMode = tintMode;
1047 mProgressTintInfo.mHasProgressBackgroundTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001048
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001049 if (mProgressDrawable != null) {
1050 applyProgressBackgroundTint();
1051 }
Alan Viverette91174362014-06-17 14:51:45 -07001052 }
1053
1054 /**
1055 * @return the blending mode used to apply the tint to the progress
1056 * background
1057 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -07001058 * @see #setProgressBackgroundTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001059 */
1060 @Nullable
1061 public PorterDuff.Mode getProgressBackgroundTintMode() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001062 return mProgressTintInfo != null ? mProgressTintInfo.mProgressBackgroundTintMode : null;
Alan Viverette91174362014-06-17 14:51:45 -07001063 }
1064
1065 /**
1066 * Applies a tint to the secondary progress indicator, if one exists.
Alan Viverette91174362014-06-17 14:51:45 -07001067 * Does not modify the current tint mode, which is
1068 * {@link PorterDuff.Mode#SRC_ATOP} by default.
1069 * <p>
1070 * The secondary progress indicator must be specified as a layer with
1071 * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
1072 * used as the progress drawable.
1073 * <p>
1074 * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
1075 * drawable contains a secondary progress indicator will automatically
1076 * mutate the drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -07001077 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -07001078 *
1079 * @param tint the tint to apply, may be {@code null} to clear tint
1080 *
1081 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
Alan Viverettea4264452014-07-28 16:02:55 -07001082 * @see #getSecondaryProgressTintList()
1083 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001084 */
Alan Viverettea4264452014-07-28 16:02:55 -07001085 public void setSecondaryProgressTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001086 if (mProgressTintInfo == null) {
1087 mProgressTintInfo = new ProgressTintInfo();
1088 }
1089 mProgressTintInfo.mSecondaryProgressTintList = tint;
1090 mProgressTintInfo.mHasSecondaryProgressTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001091
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001092 if (mProgressDrawable != null) {
1093 applySecondaryProgressTint();
1094 }
Alan Viverette91174362014-06-17 14:51:45 -07001095 }
1096
1097 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001098 * Returns the tint applied to the secondary progress drawable, if
1099 * specified.
1100 *
Alan Viverette91174362014-06-17 14:51:45 -07001101 * @return the tint applied to the secondary progress drawable
1102 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
Alan Viverettea4264452014-07-28 16:02:55 -07001103 * @see #setSecondaryProgressTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001104 */
1105 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -07001106 public ColorStateList getSecondaryProgressTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001107 return mProgressTintInfo != null ? mProgressTintInfo.mSecondaryProgressTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -07001108 }
1109
1110 /**
1111 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -07001112 * {@link #setSecondaryProgressTintList(ColorStateList)}} to the secondary
Alan Viverette91174362014-06-17 14:51:45 -07001113 * progress indicator. The default mode is
1114 * {@link PorterDuff.Mode#SRC_ATOP}.
1115 *
1116 * @param tintMode the blending mode used to apply the tint, may be
1117 * {@code null} to clear tint
1118 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
Alan Viverettea4264452014-07-28 16:02:55 -07001119 * @see #setSecondaryProgressTintList(ColorStateList)
1120 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001121 */
1122 public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001123 if (mProgressTintInfo == null) {
1124 mProgressTintInfo = new ProgressTintInfo();
1125 }
1126 mProgressTintInfo.mSecondaryProgressTintMode = tintMode;
1127 mProgressTintInfo.mHasSecondaryProgressTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001128
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001129 if (mProgressDrawable != null) {
1130 applySecondaryProgressTint();
1131 }
Alan Viverette91174362014-06-17 14:51:45 -07001132 }
1133
1134 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001135 * Returns the blending mode used to apply the tint to the secondary
1136 * progress drawable, if specified.
1137 *
Alan Viverette91174362014-06-17 14:51:45 -07001138 * @return the blending mode used to apply the tint to the secondary
1139 * progress drawable
1140 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -07001141 * @see #setSecondaryProgressTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001142 */
1143 @Nullable
1144 public PorterDuff.Mode getSecondaryProgressTintMode() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001145 return mProgressTintInfo != null ? mProgressTintInfo.mSecondaryProgressTintMode : null;
Alan Viverette91174362014-06-17 14:51:45 -07001146 }
1147
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001148 /**
1149 * Returns the drawable to which a tint or tint mode should be applied.
1150 *
1151 * @param layerId id of the layer to modify
1152 * @param shouldFallback whether the base drawable should be returned
1153 * if the id does not exist
1154 * @return the drawable to modify
1155 */
1156 @Nullable
1157 private Drawable getTintTarget(int layerId, boolean shouldFallback) {
1158 Drawable layer = null;
1159
Alan Viverette91174362014-06-17 14:51:45 -07001160 final Drawable d = mProgressDrawable;
1161 if (d != null) {
1162 mProgressDrawable = d.mutate();
1163
Alan Viverette91174362014-06-17 14:51:45 -07001164 if (d instanceof LayerDrawable) {
1165 layer = ((LayerDrawable) d).findDrawableByLayerId(layerId);
1166 }
1167
1168 if (shouldFallback && layer == null) {
1169 layer = d;
1170 }
Alan Viverette91174362014-06-17 14:51:45 -07001171 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001172
1173 return layer;
Alan Viverette91174362014-06-17 14:51:45 -07001174 }
1175
1176 /**
Alan Viverettee785d022013-09-26 15:21:10 -07001177 * Define the tileable drawable used to draw the progress bar in
1178 * progress mode.
1179 * <p>
1180 * If the drawable is a BitmapDrawable or contains BitmapDrawables, a
1181 * tiled copy will be generated for display as a progress bar.
1182 *
1183 * @param d the new drawable
1184 * @see #getProgressDrawable()
1185 * @see #setIndeterminate(boolean)
1186 */
1187 public void setProgressDrawableTiled(Drawable d) {
1188 if (d != null) {
1189 d = tileify(d, false);
1190 }
1191
1192 setProgressDrawable(d);
1193 }
RoboErik5b071432015-02-11 13:52:05 -08001194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 /**
1196 * @return The drawable currently used to draw the progress bar
1197 */
1198 Drawable getCurrentDrawable() {
1199 return mCurrentDrawable;
1200 }
1201
1202 @Override
1203 protected boolean verifyDrawable(Drawable who) {
1204 return who == mProgressDrawable || who == mIndeterminateDrawable
1205 || super.verifyDrawable(who);
1206 }
1207
1208 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07001209 public void jumpDrawablesToCurrentState() {
1210 super.jumpDrawablesToCurrentState();
1211 if (mProgressDrawable != null) mProgressDrawable.jumpToCurrentState();
1212 if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState();
1213 }
1214
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07001215 /**
1216 * @hide
1217 */
Dianne Hackborne2136772010-11-04 15:08:59 -07001218 @Override
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -07001219 public void onResolveDrawables(int layoutDirection) {
1220 final Drawable d = mCurrentDrawable;
1221 if (d != null) {
1222 d.setLayoutDirection(layoutDirection);
1223 }
1224 if (mIndeterminateDrawable != null) {
1225 mIndeterminateDrawable.setLayoutDirection(layoutDirection);
1226 }
1227 if (mProgressDrawable != null) {
1228 mProgressDrawable.setLayoutDirection(layoutDirection);
1229 }
1230 }
1231
1232 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 public void postInvalidate() {
1234 if (!mNoInvalidate) {
1235 super.postInvalidate();
1236 }
1237 }
1238
1239 private class RefreshProgressRunnable implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 public void run() {
Adam Powella0506632012-04-10 17:19:20 -07001241 synchronized (ProgressBar.this) {
1242 final int count = mRefreshData.size();
1243 for (int i = 0; i < count; i++) {
1244 final RefreshData rd = mRefreshData.get(i);
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001245 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
Adam Powella0506632012-04-10 17:19:20 -07001246 rd.recycle();
1247 }
1248 mRefreshData.clear();
1249 mRefreshIsPosted = false;
1250 }
1251 }
1252 }
1253
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001254 private static class RefreshData {
1255 private static final int POOL_MAX = 24;
1256 private static final SynchronizedPool<RefreshData> sPool =
1257 new SynchronizedPool<RefreshData>(POOL_MAX);
1258
Adam Powella0506632012-04-10 17:19:20 -07001259 public int id;
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001260 public int progress;
Adam Powella0506632012-04-10 17:19:20 -07001261 public boolean fromUser;
Adam Powella0506632012-04-10 17:19:20 -07001262
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001263 public static RefreshData obtain(int id, int progress, boolean fromUser) {
Adam Powella0506632012-04-10 17:19:20 -07001264 RefreshData rd = sPool.acquire();
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001265 if (rd == null) {
1266 rd = new RefreshData();
1267 }
Adam Powella0506632012-04-10 17:19:20 -07001268 rd.id = id;
1269 rd.progress = progress;
1270 rd.fromUser = fromUser;
1271 return rd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 }
RoboErik5b071432015-02-11 13:52:05 -08001273
Adam Powella0506632012-04-10 17:19:20 -07001274 public void recycle() {
1275 sPool.release(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 }
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001278
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001279 private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
Joe Onoratoaa072632010-12-08 15:31:28 -08001280 boolean callBackToApp) {
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001281 float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
Alan Viverettebac8e122015-02-04 17:15:01 -08001282 final Drawable d = mCurrentDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 if (d != null) {
1284 Drawable progressDrawable = null;
1285
1286 if (d instanceof LayerDrawable) {
1287 progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -07001288 if (progressDrawable != null && canResolveLayoutDirection()) {
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001289 progressDrawable.setLayoutDirection(getLayoutDirection());
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -07001290 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 }
1292
1293 final int level = (int) (scale * MAX_LEVEL);
1294 (progressDrawable != null ? progressDrawable : d).setLevel(level);
1295 } else {
1296 invalidate();
1297 }
RoboErik5b071432015-02-11 13:52:05 -08001298
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001299 if (callBackToApp && id == R.id.progress) {
RoboErik5b071432015-02-11 13:52:05 -08001300 onProgressRefresh(scale, fromUser, progress);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 }
1302 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001303
RoboErik5b071432015-02-11 13:52:05 -08001304 void onProgressRefresh(float scale, boolean fromUser, int progress) {
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001305 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
1306 scheduleAccessibilityEventSender();
1307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 }
1309
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001310 private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 if (mUiThreadId == Thread.currentThread().getId()) {
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001312 doRefreshProgress(id, progress, fromUser, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001314 if (mRefreshProgressRunnable == null) {
1315 mRefreshProgressRunnable = new RefreshProgressRunnable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 }
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001317
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001318 final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
Adam Powella0506632012-04-10 17:19:20 -07001319 mRefreshData.add(rd);
1320 if (mAttached && !mRefreshIsPosted) {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001321 post(mRefreshProgressRunnable);
Adam Powella0506632012-04-10 17:19:20 -07001322 mRefreshIsPosted = true;
1323 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 }
1325 }
RoboErik5b071432015-02-11 13:52:05 -08001326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 /**
1328 * <p>Set the current progress to the specified value. Does not do anything
1329 * if the progress bar is in indeterminate mode.</p>
1330 *
1331 * @param progress the new progress, between 0 and {@link #getMax()}
1332 *
1333 * @see #setIndeterminate(boolean)
1334 * @see #isIndeterminate()
1335 * @see #getProgress()
RoboErik5b071432015-02-11 13:52:05 -08001336 * @see #incrementProgressBy(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 */
1338 @android.view.RemotableViewMethod
1339 public synchronized void setProgress(int progress) {
1340 setProgress(progress, false);
1341 }
RoboErik5b071432015-02-11 13:52:05 -08001342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 @android.view.RemotableViewMethod
1344 synchronized void setProgress(int progress, boolean fromUser) {
1345 if (mIndeterminate) {
1346 return;
1347 }
1348
1349 if (progress < 0) {
1350 progress = 0;
1351 }
1352
1353 if (progress > mMax) {
1354 progress = mMax;
1355 }
1356
1357 if (progress != mProgress) {
1358 mProgress = progress;
1359 refreshProgress(R.id.progress, mProgress, fromUser);
1360 }
1361 }
1362
1363 /**
1364 * <p>
1365 * Set the current secondary progress to the specified value. Does not do
1366 * anything if the progress bar is in indeterminate mode.
1367 * </p>
RoboErik5b071432015-02-11 13:52:05 -08001368 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
1370 * @see #setIndeterminate(boolean)
1371 * @see #isIndeterminate()
1372 * @see #getSecondaryProgress()
1373 * @see #incrementSecondaryProgressBy(int)
1374 */
1375 @android.view.RemotableViewMethod
1376 public synchronized void setSecondaryProgress(int secondaryProgress) {
1377 if (mIndeterminate) {
1378 return;
1379 }
1380
1381 if (secondaryProgress < 0) {
1382 secondaryProgress = 0;
1383 }
1384
1385 if (secondaryProgress > mMax) {
1386 secondaryProgress = mMax;
1387 }
1388
1389 if (secondaryProgress != mSecondaryProgress) {
1390 mSecondaryProgress = secondaryProgress;
1391 refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false);
1392 }
1393 }
1394
1395 /**
1396 * <p>Get the progress bar's current level of progress. Return 0 when the
1397 * progress bar is in indeterminate mode.</p>
1398 *
1399 * @return the current progress, between 0 and {@link #getMax()}
1400 *
1401 * @see #setIndeterminate(boolean)
1402 * @see #isIndeterminate()
1403 * @see #setProgress(int)
1404 * @see #setMax(int)
1405 * @see #getMax()
1406 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001407 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 public synchronized int getProgress() {
1409 return mIndeterminate ? 0 : mProgress;
1410 }
1411
1412 /**
1413 * <p>Get the progress bar's current level of secondary progress. Return 0 when the
1414 * progress bar is in indeterminate mode.</p>
1415 *
1416 * @return the current secondary progress, between 0 and {@link #getMax()}
1417 *
1418 * @see #setIndeterminate(boolean)
1419 * @see #isIndeterminate()
1420 * @see #setSecondaryProgress(int)
1421 * @see #setMax(int)
1422 * @see #getMax()
1423 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001424 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 public synchronized int getSecondaryProgress() {
1426 return mIndeterminate ? 0 : mSecondaryProgress;
1427 }
1428
1429 /**
1430 * <p>Return the upper limit of this progress bar's range.</p>
1431 *
1432 * @return a positive integer
1433 *
1434 * @see #setMax(int)
1435 * @see #getProgress()
1436 * @see #getSecondaryProgress()
1437 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07001438 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 public synchronized int getMax() {
1440 return mMax;
1441 }
1442
1443 /**
1444 * <p>Set the range of the progress bar to 0...<tt>max</tt>.</p>
1445 *
1446 * @param max the upper range of this progress bar
1447 *
1448 * @see #getMax()
RoboErik5b071432015-02-11 13:52:05 -08001449 * @see #setProgress(int)
1450 * @see #setSecondaryProgress(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 */
1452 @android.view.RemotableViewMethod
1453 public synchronized void setMax(int max) {
1454 if (max < 0) {
1455 max = 0;
1456 }
1457 if (max != mMax) {
1458 mMax = max;
1459 postInvalidate();
1460
1461 if (mProgress > max) {
1462 mProgress = max;
1463 }
Michael Krehan58e38222011-02-17 20:04:27 -08001464 refreshProgress(R.id.progress, mProgress, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 }
1466 }
RoboErik5b071432015-02-11 13:52:05 -08001467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 /**
1469 * <p>Increase the progress bar's progress by the specified amount.</p>
1470 *
1471 * @param diff the amount by which the progress must be increased
1472 *
RoboErik5b071432015-02-11 13:52:05 -08001473 * @see #setProgress(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 */
1475 public synchronized final void incrementProgressBy(int diff) {
1476 setProgress(mProgress + diff);
1477 }
1478
1479 /**
1480 * <p>Increase the progress bar's secondary progress by the specified amount.</p>
1481 *
1482 * @param diff the amount by which the secondary progress must be increased
1483 *
RoboErik5b071432015-02-11 13:52:05 -08001484 * @see #setSecondaryProgress(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 */
1486 public synchronized final void incrementSecondaryProgressBy(int diff) {
1487 setSecondaryProgress(mSecondaryProgress + diff);
1488 }
1489
1490 /**
1491 * <p>Start the indeterminate progress animation.</p>
1492 */
1493 void startAnimation() {
Romain Guya05e8a52010-02-25 14:32:39 -08001494 if (getVisibility() != VISIBLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 return;
1496 }
1497
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001498 if (mIndeterminateDrawable instanceof Animatable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 mShouldStartAnimationDrawable = true;
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001500 mHasAnimation = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001502 mHasAnimation = true;
1503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 if (mInterpolator == null) {
1505 mInterpolator = new LinearInterpolator();
1506 }
RoboErik5b071432015-02-11 13:52:05 -08001507
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001508 if (mTransformation == null) {
1509 mTransformation = new Transformation();
1510 } else {
1511 mTransformation.clear();
1512 }
RoboErik5b071432015-02-11 13:52:05 -08001513
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001514 if (mAnimation == null) {
1515 mAnimation = new AlphaAnimation(0.0f, 1.0f);
1516 } else {
1517 mAnimation.reset();
1518 }
1519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001520 mAnimation.setRepeatMode(mBehavior);
1521 mAnimation.setRepeatCount(Animation.INFINITE);
1522 mAnimation.setDuration(mDuration);
1523 mAnimation.setInterpolator(mInterpolator);
1524 mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 }
Evan Charlton08e14732010-06-07 10:38:53 -07001526 postInvalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 }
1528
1529 /**
1530 * <p>Stop the indeterminate progress animation.</p>
1531 */
1532 void stopAnimation() {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001533 mHasAnimation = false;
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001534 if (mIndeterminateDrawable instanceof Animatable) {
1535 ((Animatable) mIndeterminateDrawable).stop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 mShouldStartAnimationDrawable = false;
1537 }
Evan Charlton08e14732010-06-07 10:38:53 -07001538 postInvalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 }
1540
1541 /**
1542 * Sets the acceleration curve for the indeterminate animation.
1543 * The interpolator is loaded as a resource from the specified context.
1544 *
1545 * @param context The application environment
1546 * @param resID The resource identifier of the interpolator to load
1547 */
Tor Norbye7b9c9122013-05-30 16:48:33 -07001548 public void setInterpolator(Context context, @InterpolatorRes int resID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 setInterpolator(AnimationUtils.loadInterpolator(context, resID));
1550 }
1551
1552 /**
1553 * Sets the acceleration curve for the indeterminate animation.
1554 * Defaults to a linear interpolation.
1555 *
1556 * @param interpolator The interpolator which defines the acceleration curve
1557 */
1558 public void setInterpolator(Interpolator interpolator) {
1559 mInterpolator = interpolator;
1560 }
1561
1562 /**
1563 * Gets the acceleration curve type for the indeterminate animation.
1564 *
1565 * @return the {@link Interpolator} associated to this animation
1566 */
1567 public Interpolator getInterpolator() {
1568 return mInterpolator;
1569 }
1570
1571 @Override
Steve Howardb25ffff2010-08-20 17:39:26 -07001572 @RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573 public void setVisibility(int v) {
1574 if (getVisibility() != v) {
1575 super.setVisibility(v);
1576
1577 if (mIndeterminate) {
1578 // let's be nice with the UI thread
1579 if (v == GONE || v == INVISIBLE) {
1580 stopAnimation();
Romain Guya05e8a52010-02-25 14:32:39 -08001581 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 startAnimation();
1583 }
1584 }
1585 }
1586 }
1587
1588 @Override
Romain Guya05e8a52010-02-25 14:32:39 -08001589 protected void onVisibilityChanged(View changedView, int visibility) {
1590 super.onVisibilityChanged(changedView, visibility);
1591
1592 if (mIndeterminate) {
1593 // let's be nice with the UI thread
1594 if (visibility == GONE || visibility == INVISIBLE) {
1595 stopAnimation();
1596 } else {
1597 startAnimation();
1598 }
1599 }
1600 }
1601
1602 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 public void invalidateDrawable(Drawable dr) {
1604 if (!mInDrawing) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -07001605 if (verifyDrawable(dr)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 final Rect dirty = dr.getBounds();
Chris Craik7546a4b2013-10-30 19:49:37 -07001607 final int scrollX = mScrollX + mPaddingLeft;
1608 final int scrollY = mScrollY + mPaddingTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609
Chris Craik7546a4b2013-10-30 19:49:37 -07001610 invalidate(dirty.left + scrollX, dirty.top + scrollY,
1611 dirty.right + scrollX, dirty.bottom + scrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 } else {
1613 super.invalidateDrawable(dr);
1614 }
1615 }
1616 }
1617
1618 @Override
1619 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Joe Onoratoaa072632010-12-08 15:31:28 -08001620 updateDrawableBounds(w, h);
1621 }
1622
1623 private void updateDrawableBounds(int w, int h) {
Adam Powell6322af52012-08-08 15:59:12 -07001624 // onDraw will translate the canvas so we draw starting at 0,0.
1625 // Subtract out padding for the purposes of the calculations below.
1626 w -= mPaddingRight + mPaddingLeft;
1627 h -= mPaddingTop + mPaddingBottom;
1628
1629 int right = w;
1630 int bottom = h;
Adam Powella1b92c52011-09-02 15:05:15 -07001631 int top = 0;
1632 int left = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633
1634 if (mIndeterminateDrawable != null) {
Chet Haasea79803c2011-09-28 17:51:53 -07001635 // Aspect ratio logic does not apply to AnimationDrawables
1636 if (mOnlyIndeterminate && !(mIndeterminateDrawable instanceof AnimationDrawable)) {
Adam Powella1b92c52011-09-02 15:05:15 -07001637 // Maintain aspect ratio. Certain kinds of animated drawables
1638 // get very confused otherwise.
1639 final int intrinsicWidth = mIndeterminateDrawable.getIntrinsicWidth();
1640 final int intrinsicHeight = mIndeterminateDrawable.getIntrinsicHeight();
1641 final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight;
1642 final float boundAspect = (float) w / h;
1643 if (intrinsicAspect != boundAspect) {
1644 if (boundAspect > intrinsicAspect) {
1645 // New width is larger. Make it smaller to match height.
1646 final int width = (int) (h * intrinsicAspect);
1647 left = (w - width) / 2;
1648 right = left + width;
1649 } else {
1650 // New height is larger. Make it smaller to match width.
1651 final int height = (int) (w * (1 / intrinsicAspect));
1652 top = (h - height) / 2;
1653 bottom = top + height;
1654 }
1655 }
1656 }
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -08001657 if (isLayoutRtl() && mMirrorForRtl) {
Fabrice Di Meglio7fb98b32012-09-12 20:04:04 -07001658 int tempLeft = left;
1659 left = w - right;
1660 right = w - tempLeft;
1661 }
Adam Powella1b92c52011-09-02 15:05:15 -07001662 mIndeterminateDrawable.setBounds(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 }
RoboErik5b071432015-02-11 13:52:05 -08001664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 if (mProgressDrawable != null) {
1666 mProgressDrawable.setBounds(0, 0, right, bottom);
1667 }
1668 }
1669
1670 @Override
1671 protected synchronized void onDraw(Canvas canvas) {
1672 super.onDraw(canvas);
1673
Alan Viverette661e6362014-05-12 10:55:37 -07001674 drawTrack(canvas);
1675 }
1676
1677 /**
1678 * Draws the progress bar track.
1679 */
1680 void drawTrack(Canvas canvas) {
1681 final Drawable d = mCurrentDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 if (d != null) {
1683 // Translate canvas so a indeterminate circular progress bar with padding
1684 // rotates properly in its animation
Alan Viverette661e6362014-05-12 10:55:37 -07001685 final int saveCount = canvas.save();
1686
Alan Viverette6a8253f2015-02-23 12:49:47 -08001687 if (isLayoutRtl() && mMirrorForRtl) {
Fabrice Di Meglio7fb98b32012-09-12 20:04:04 -07001688 canvas.translate(getWidth() - mPaddingRight, mPaddingTop);
1689 canvas.scale(-1.0f, 1.0f);
1690 } else {
1691 canvas.translate(mPaddingLeft, mPaddingTop);
1692 }
Alan Viverette661e6362014-05-12 10:55:37 -07001693
1694 final long time = getDrawingTime();
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001695 if (mHasAnimation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 mAnimation.getTransformation(time, mTransformation);
Alan Viverette661e6362014-05-12 10:55:37 -07001697 final float scale = mTransformation.getAlpha();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 try {
1699 mInDrawing = true;
1700 d.setLevel((int) (scale * MAX_LEVEL));
1701 } finally {
1702 mInDrawing = false;
1703 }
Jeff Brown6cb7b462012-03-05 13:21:17 -08001704 postInvalidateOnAnimation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 }
Alan Viverette661e6362014-05-12 10:55:37 -07001706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001707 d.draw(canvas);
Alan Viverette661e6362014-05-12 10:55:37 -07001708 canvas.restoreToCount(saveCount);
1709
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001710 if (mShouldStartAnimationDrawable && d instanceof Animatable) {
1711 ((Animatable) d).start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 mShouldStartAnimationDrawable = false;
1713 }
1714 }
1715 }
1716
1717 @Override
1718 protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 int dw = 0;
1720 int dh = 0;
Alan Viverette6a8253f2015-02-23 12:49:47 -08001721
1722 final Drawable d = mCurrentDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 if (d != null) {
1724 dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
1725 dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
1726 }
Alan Viverette6a8253f2015-02-23 12:49:47 -08001727
Joe Onoratoaa072632010-12-08 15:31:28 -08001728 updateDrawableState();
Alan Viverette6a8253f2015-02-23 12:49:47 -08001729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 dw += mPaddingLeft + mPaddingRight;
1731 dh += mPaddingTop + mPaddingBottom;
1732
Alan Viverette6a8253f2015-02-23 12:49:47 -08001733 final int measuredWidth = resolveSizeAndState(dw, widthMeasureSpec, 0);
1734 final int measuredHeight = resolveSizeAndState(dh, heightMeasureSpec, 0);
1735 setMeasuredDimension(measuredWidth, measuredHeight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001736 }
RoboErik5b071432015-02-11 13:52:05 -08001737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 @Override
1739 protected void drawableStateChanged() {
1740 super.drawableStateChanged();
Joe Onoratoaa072632010-12-08 15:31:28 -08001741 updateDrawableState();
1742 }
RoboErik5b071432015-02-11 13:52:05 -08001743
Joe Onoratoaa072632010-12-08 15:31:28 -08001744 private void updateDrawableState() {
Alan Viverette6a8253f2015-02-23 12:49:47 -08001745 final int[] state = getDrawableState();
RoboErik5b071432015-02-11 13:52:05 -08001746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
1748 mProgressDrawable.setState(state);
1749 }
RoboErik5b071432015-02-11 13:52:05 -08001750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
1752 mIndeterminateDrawable.setState(state);
1753 }
1754 }
1755
Alan Viverettecebc6ba2014-06-13 15:52:13 -07001756 @Override
Alan Viverette8de14942014-06-18 18:05:15 -07001757 public void drawableHotspotChanged(float x, float y) {
1758 super.drawableHotspotChanged(x, y);
Alan Viverettecebc6ba2014-06-13 15:52:13 -07001759
1760 if (mProgressDrawable != null) {
1761 mProgressDrawable.setHotspot(x, y);
1762 }
1763
1764 if (mIndeterminateDrawable != null) {
1765 mIndeterminateDrawable.setHotspot(x, y);
1766 }
1767 }
1768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 static class SavedState extends BaseSavedState {
1770 int progress;
1771 int secondaryProgress;
RoboErik5b071432015-02-11 13:52:05 -08001772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 /**
1774 * Constructor called from {@link ProgressBar#onSaveInstanceState()}
1775 */
1776 SavedState(Parcelable superState) {
1777 super(superState);
1778 }
RoboErik5b071432015-02-11 13:52:05 -08001779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 /**
1781 * Constructor called from {@link #CREATOR}
1782 */
1783 private SavedState(Parcel in) {
1784 super(in);
1785 progress = in.readInt();
1786 secondaryProgress = in.readInt();
1787 }
1788
1789 @Override
1790 public void writeToParcel(Parcel out, int flags) {
1791 super.writeToParcel(out, flags);
1792 out.writeInt(progress);
1793 out.writeInt(secondaryProgress);
1794 }
1795
1796 public static final Parcelable.Creator<SavedState> CREATOR
1797 = new Parcelable.Creator<SavedState>() {
1798 public SavedState createFromParcel(Parcel in) {
1799 return new SavedState(in);
1800 }
1801
1802 public SavedState[] newArray(int size) {
1803 return new SavedState[size];
1804 }
1805 };
1806 }
1807
1808 @Override
1809 public Parcelable onSaveInstanceState() {
1810 // Force our ancestor class to save its state
1811 Parcelable superState = super.onSaveInstanceState();
1812 SavedState ss = new SavedState(superState);
RoboErik5b071432015-02-11 13:52:05 -08001813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 ss.progress = mProgress;
1815 ss.secondaryProgress = mSecondaryProgress;
RoboErik5b071432015-02-11 13:52:05 -08001816
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 return ss;
1818 }
1819
1820 @Override
1821 public void onRestoreInstanceState(Parcelable state) {
1822 SavedState ss = (SavedState) state;
1823 super.onRestoreInstanceState(ss.getSuperState());
RoboErik5b071432015-02-11 13:52:05 -08001824
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 setProgress(ss.progress);
1826 setSecondaryProgress(ss.secondaryProgress);
1827 }
David Sobreira Marques52a35432010-05-15 16:10:18 -03001828
1829 @Override
1830 protected void onAttachedToWindow() {
1831 super.onAttachedToWindow();
1832 if (mIndeterminate) {
1833 startAnimation();
1834 }
Adam Powella0506632012-04-10 17:19:20 -07001835 if (mRefreshData != null) {
1836 synchronized (this) {
1837 final int count = mRefreshData.size();
1838 for (int i = 0; i < count; i++) {
1839 final RefreshData rd = mRefreshData.get(i);
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001840 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
Adam Powella0506632012-04-10 17:19:20 -07001841 rd.recycle();
1842 }
1843 mRefreshData.clear();
1844 }
1845 }
1846 mAttached = true;
David Sobreira Marques52a35432010-05-15 16:10:18 -03001847 }
1848
1849 @Override
1850 protected void onDetachedFromWindow() {
David Sobreira Marques52a35432010-05-15 16:10:18 -03001851 if (mIndeterminate) {
1852 stopAnimation();
1853 }
Adam Powella0506632012-04-10 17:19:20 -07001854 if (mRefreshProgressRunnable != null) {
1855 removeCallbacks(mRefreshProgressRunnable);
Bing Deng24a2bc72012-11-08 13:35:15 +08001856 mRefreshIsPosted = false;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001857 }
1858 if (mAccessibilityEventSender != null) {
1859 removeCallbacks(mAccessibilityEventSender);
1860 }
Patrick Dubroyec84c3a2011-01-13 17:55:37 -08001861 // This should come after stopAnimation(), otherwise an invalidate message remains in the
1862 // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
1863 super.onDetachedFromWindow();
Adam Powella0506632012-04-10 17:19:20 -07001864 mAttached = false;
David Sobreira Marques52a35432010-05-15 16:10:18 -03001865 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001866
1867 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08001868 public CharSequence getAccessibilityClassName() {
1869 return ProgressBar.class.getName();
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001870 }
1871
Alan Viverettea54956a2015-01-07 16:05:02 -08001872 /** @hide */
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001873 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08001874 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
1875 super.onInitializeAccessibilityEventInternal(event);
1876 event.setItemCount(mMax);
1877 event.setCurrentItemIndex(mProgress);
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001878 }
1879
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001880 /**
1881 * Schedule a command for sending an accessibility event.
1882 * </br>
1883 * Note: A command is used to ensure that accessibility events
1884 * are sent at most one in a given time frame to save
1885 * system resources while the progress changes quickly.
1886 */
1887 private void scheduleAccessibilityEventSender() {
1888 if (mAccessibilityEventSender == null) {
1889 mAccessibilityEventSender = new AccessibilityEventSender();
1890 } else {
1891 removeCallbacks(mAccessibilityEventSender);
1892 }
1893 postDelayed(mAccessibilityEventSender, TIMEOUT_SEND_ACCESSIBILITY_EVENT);
1894 }
1895
1896 /**
1897 * Command for sending an accessibility event.
1898 */
1899 private class AccessibilityEventSender implements Runnable {
1900 public void run() {
1901 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
1902 }
1903 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001904
1905 private static class ProgressTintInfo {
1906 ColorStateList mIndeterminateTintList;
1907 PorterDuff.Mode mIndeterminateTintMode;
1908 boolean mHasIndeterminateTint;
1909 boolean mHasIndeterminateTintMode;
1910
1911 ColorStateList mProgressTintList;
1912 PorterDuff.Mode mProgressTintMode;
1913 boolean mHasProgressTint;
1914 boolean mHasProgressTintMode;
1915
1916 ColorStateList mProgressBackgroundTintList;
1917 PorterDuff.Mode mProgressBackgroundTintMode;
1918 boolean mHasProgressBackgroundTint;
1919 boolean mHasProgressBackgroundTintMode;
1920
1921 ColorStateList mSecondaryProgressTintList;
1922 PorterDuff.Mode mSecondaryProgressTintMode;
1923 boolean mHasSecondaryProgressTint;
1924 boolean mHasSecondaryProgressTintMode;
1925 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926}