blob: b59ae17ebceaaec82e28b4b883661d8bc7b645af [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;
Alan Viverette12a44912015-04-16 13:06:00 -070046import android.util.MathUtils;
Svetoslav Ganovabae2a12012-11-27 16:59:37 -080047import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.view.Gravity;
Steve Howardb25ffff2010-08-20 17:39:26 -070049import android.view.RemotableViewMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.view.View;
Steve Zeigler7a367882010-02-23 16:39:08 -080051import android.view.ViewDebug;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -070052import android.view.accessibility.AccessibilityEvent;
53import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.view.animation.AlphaAnimation;
55import android.view.animation.Animation;
56import android.view.animation.AnimationUtils;
57import android.view.animation.Interpolator;
58import android.view.animation.LinearInterpolator;
59import android.view.animation.Transformation;
60import android.widget.RemoteViews.RemoteView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Adam Powella0506632012-04-10 17:19:20 -070062import java.util.ArrayList;
63
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064/**
65 * <p>
66 * Visual indicator of progress in some operation. Displays a bar to the user
RoboErik5b071432015-02-11 13:52:05 -080067 * representing how far the operation has progressed; the application can
68 * change the amount of progress (modifying the length of the bar) as it moves
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 * forward. There is also a secondary progress displayable on a progress bar
70 * which is useful for displaying intermediate progress, such as the buffer
71 * level during a streaming playback progress bar.
72 * </p>
73 *
74 * <p>
75 * A progress bar can also be made indeterminate. In indeterminate mode, the
Scott Main42f139c2011-04-29 10:31:10 -070076 * progress bar shows a cyclic animation without an indication of progress. This mode is used by
77 * applications when the length of the task is unknown. The indeterminate progress bar can be either
78 * a spinning wheel or a horizontal bar.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079 * </p>
80 *
81 * <p>The following code example shows how a progress bar can be used from
82 * a worker thread to update the user interface to notify the user of progress:
83 * </p>
RoboErik5b071432015-02-11 13:52:05 -080084 *
Scott Main42f139c2011-04-29 10:31:10 -070085 * <pre>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086 * public class MyActivity extends Activity {
87 * private static final int PROGRESS = 0x1;
88 *
89 * private ProgressBar mProgress;
90 * private int mProgressStatus = 0;
91 *
92 * private Handler mHandler = new Handler();
93 *
94 * protected void onCreate(Bundle icicle) {
95 * super.onCreate(icicle);
96 *
97 * setContentView(R.layout.progressbar_activity);
98 *
99 * mProgress = (ProgressBar) findViewById(R.id.progress_bar);
100 *
101 * // Start lengthy operation in a background thread
102 * new Thread(new Runnable() {
103 * public void run() {
Scott Main42f139c2011-04-29 10:31:10 -0700104 * while (mProgressStatus &lt; 100) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 * mProgressStatus = doWork();
106 *
107 * // Update the progress bar
108 * mHandler.post(new Runnable() {
109 * public void run() {
110 * mProgress.setProgress(mProgressStatus);
111 * }
112 * });
113 * }
114 * }
115 * }).start();
116 * }
Scott Main42f139c2011-04-29 10:31:10 -0700117 * }</pre>
118 *
119 * <p>To add a progress bar to a layout file, you can use the {@code &lt;ProgressBar&gt;} element.
120 * By default, the progress bar is a spinning wheel (an indeterminate indicator). To change to a
121 * horizontal progress bar, apply the {@link android.R.style#Widget_ProgressBar_Horizontal
122 * Widget.ProgressBar.Horizontal} style, like so:</p>
123 *
124 * <pre>
125 * &lt;ProgressBar
126 * style="@android:style/Widget.ProgressBar.Horizontal"
127 * ... /&gt;</pre>
128 *
129 * <p>If you will use the progress bar to show real progress, you must use the horizontal bar. You
130 * can then increment the progress with {@link #incrementProgressBy incrementProgressBy()} or
131 * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If
132 * necessary, you can adjust the maximum value (the value for a full bar) using the {@link
133 * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed
134 * below.</p>
135 *
136 * <p>Another common style to apply to the progress bar is {@link
137 * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller
138 * version of the spinning wheel&mdash;useful when waiting for content to load.
139 * For example, you can insert this kind of progress bar into your default layout for
140 * a view that will be populated by some content fetched from the Internet&mdash;the spinning wheel
141 * appears immediately and when your application receives the content, it replaces the progress bar
142 * with the loaded content. For example:</p>
143 *
144 * <pre>
145 * &lt;LinearLayout
146 * android:orientation="horizontal"
147 * ... &gt;
148 * &lt;ProgressBar
149 * android:layout_width="wrap_content"
150 * android:layout_height="wrap_content"
151 * style="@android:style/Widget.ProgressBar.Small"
152 * android:layout_marginRight="5dp" /&gt;
153 * &lt;TextView
154 * android:layout_width="wrap_content"
155 * android:layout_height="wrap_content"
156 * android:text="@string/loading" /&gt;
157 * &lt;/LinearLayout&gt;</pre>
158 *
159 * <p>Other progress bar styles provided by the system include:</p>
160 * <ul>
161 * <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li>
162 * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li>
163 * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li>
164 * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li>
165 * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse
166 * Widget.ProgressBar.Small.Inverse}</li>
167 * <li>{@link android.R.style#Widget_ProgressBar_Large_Inverse
168 * Widget.ProgressBar.Large.Inverse}</li>
169 * </ul>
170 * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
171 * if your application uses a light colored theme (a white background).</p>
RoboErik5b071432015-02-11 13:52:05 -0800172 *
173 * <p><strong>XML attributes</b></strong>
174 * <p>
175 * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 * {@link android.R.styleable#View View Attributes}
177 * </p>
RoboErik5b071432015-02-11 13:52:05 -0800178 *
Scott Main42f139c2011-04-29 10:31:10 -0700179 * @attr ref android.R.styleable#ProgressBar_animationResolution
180 * @attr ref android.R.styleable#ProgressBar_indeterminate
181 * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
182 * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
183 * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
184 * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
185 * @attr ref android.R.styleable#ProgressBar_interpolator
186 * @attr ref android.R.styleable#ProgressBar_max
187 * @attr ref android.R.styleable#ProgressBar_maxHeight
188 * @attr ref android.R.styleable#ProgressBar_maxWidth
189 * @attr ref android.R.styleable#ProgressBar_minHeight
190 * @attr ref android.R.styleable#ProgressBar_minWidth
Scott Mainb40c1fd2013-04-23 13:30:06 -0700191 * @attr ref android.R.styleable#ProgressBar_mirrorForRtl
Scott Main42f139c2011-04-29 10:31:10 -0700192 * @attr ref android.R.styleable#ProgressBar_progress
193 * @attr ref android.R.styleable#ProgressBar_progressDrawable
194 * @attr ref android.R.styleable#ProgressBar_secondaryProgress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 */
196@RemoteView
197public class ProgressBar extends View {
198 private static final int MAX_LEVEL = 10000;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700199 private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200
201 int mMinWidth;
202 int mMaxWidth;
203 int mMinHeight;
204 int mMaxHeight;
205
206 private int mProgress;
207 private int mSecondaryProgress;
208 private int mMax;
209
210 private int mBehavior;
211 private int mDuration;
212 private boolean mIndeterminate;
213 private boolean mOnlyIndeterminate;
214 private Transformation mTransformation;
215 private AlphaAnimation mAnimation;
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700216 private boolean mHasAnimation;
Alan Viverette91174362014-06-17 14:51:45 -0700217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 private Drawable mIndeterminateDrawable;
219 private Drawable mProgressDrawable;
220 private Drawable mCurrentDrawable;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700221 private ProgressTintInfo mProgressTintInfo;
222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 Bitmap mSampleTile;
224 private boolean mNoInvalidate;
225 private Interpolator mInterpolator;
226 private RefreshProgressRunnable mRefreshProgressRunnable;
227 private long mUiThreadId;
228 private boolean mShouldStartAnimationDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229
230 private boolean mInDrawing;
Adam Powella0506632012-04-10 17:19:20 -0700231 private boolean mAttached;
232 private boolean mRefreshIsPosted;
233
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800234 boolean mMirrorForRtl = false;
235
Adam Powella0506632012-04-10 17:19:20 -0700236 private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700238 private AccessibilityEventSender mAccessibilityEventSender;
239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 /**
241 * Create a new progress bar with range 0...100 and initial progress of 0.
242 * @param context the application environment
243 */
244 public ProgressBar(Context context) {
245 this(context, null);
246 }
RoboErik5b071432015-02-11 13:52:05 -0800247
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 public ProgressBar(Context context, AttributeSet attrs) {
249 this(context, attrs, com.android.internal.R.attr.progressBarStyle);
250 }
251
Alan Viverette617feb92013-09-09 18:09:13 -0700252 public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
253 this(context, attrs, defStyleAttr, 0);
Adam Powell6af97e12010-11-11 21:11:53 -0800254 }
255
Alan Viverette617feb92013-09-09 18:09:13 -0700256 public ProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
257 super(context, attrs, defStyleAttr, defStyleRes);
258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 mUiThreadId = Thread.currentThread().getId();
260 initProgressBar();
261
Alan Viverette617feb92013-09-09 18:09:13 -0700262 final TypedArray a = context.obtainStyledAttributes(
263 attrs, R.styleable.ProgressBar, defStyleAttr, defStyleRes);
RoboErik5b071432015-02-11 13:52:05 -0800264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 mNoInvalidate = true;
RoboErik5b071432015-02-11 13:52:05 -0800266
Alan Viverette91174362014-06-17 14:51:45 -0700267 final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
268 if (progressDrawable != null) {
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700269 // Calling setProgressDrawable can set mMaxHeight, so make sure the
270 // corresponding XML attribute for mMaxHeight is read after calling
271 // this method.
272 if (needsTileify(progressDrawable)) {
273 setProgressDrawableTiled(progressDrawable);
274 } else {
275 setProgressDrawable(progressDrawable);
276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277 }
278
279
280 mDuration = a.getInt(R.styleable.ProgressBar_indeterminateDuration, mDuration);
281
282 mMinWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_minWidth, mMinWidth);
283 mMaxWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_maxWidth, mMaxWidth);
284 mMinHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_minHeight, mMinHeight);
285 mMaxHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_maxHeight, mMaxHeight);
286
287 mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);
288
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700289 final int resID = a.getResourceId(
RoboErik5b071432015-02-11 13:52:05 -0800290 com.android.internal.R.styleable.ProgressBar_interpolator,
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700291 android.R.anim.linear_interpolator); // default to linear interpolator
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 if (resID > 0) {
293 setInterpolator(context, resID);
RoboErik5b071432015-02-11 13:52:05 -0800294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295
296 setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
297
298 setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
299
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700300 setSecondaryProgress(a.getInt(
301 R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302
Alan Viverette91174362014-06-17 14:51:45 -0700303 final Drawable indeterminateDrawable = a.getDrawable(
304 R.styleable.ProgressBar_indeterminateDrawable);
305 if (indeterminateDrawable != null) {
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700306 if (needsTileify(indeterminateDrawable)) {
307 setIndeterminateDrawableTiled(indeterminateDrawable);
308 } else {
309 setIndeterminateDrawable(indeterminateDrawable);
310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 }
312
313 mOnlyIndeterminate = a.getBoolean(
314 R.styleable.ProgressBar_indeterminateOnly, mOnlyIndeterminate);
315
316 mNoInvalidate = false;
317
318 setIndeterminate(mOnlyIndeterminate || a.getBoolean(
319 R.styleable.ProgressBar_indeterminate, mIndeterminate));
320
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800321 mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);
322
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700323 if (a.hasValue(R.styleable.ProgressBar_progressTintMode)) {
324 if (mProgressTintInfo == null) {
325 mProgressTintInfo = new ProgressTintInfo();
326 }
327 mProgressTintInfo.mProgressTintMode = Drawable.parseTintMode(a.getInt(
Alan Viverettedbc40182015-04-06 15:01:23 -0700328 R.styleable.ProgressBar_progressTintMode, -1), null);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700329 mProgressTintInfo.mHasProgressTintMode = true;
330 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700331
Alan Viverette91174362014-06-17 14:51:45 -0700332 if (a.hasValue(R.styleable.ProgressBar_progressTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700333 if (mProgressTintInfo == null) {
334 mProgressTintInfo = new ProgressTintInfo();
335 }
336 mProgressTintInfo.mProgressTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700337 R.styleable.ProgressBar_progressTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700338 mProgressTintInfo.mHasProgressTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700339 }
340
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700341 if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTintMode)) {
342 if (mProgressTintInfo == null) {
343 mProgressTintInfo = new ProgressTintInfo();
344 }
345 mProgressTintInfo.mProgressBackgroundTintMode = Drawable.parseTintMode(a.getInt(
Alan Viverettedbc40182015-04-06 15:01:23 -0700346 R.styleable.ProgressBar_progressBackgroundTintMode, -1), null);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700347 mProgressTintInfo.mHasProgressBackgroundTintMode = true;
348 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700349
Alan Viverette91174362014-06-17 14:51:45 -0700350 if (a.hasValue(R.styleable.ProgressBar_progressBackgroundTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700351 if (mProgressTintInfo == null) {
352 mProgressTintInfo = new ProgressTintInfo();
353 }
354 mProgressTintInfo.mProgressBackgroundTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700355 R.styleable.ProgressBar_progressBackgroundTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700356 mProgressTintInfo.mHasProgressBackgroundTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700357 }
358
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700359 if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTintMode)) {
360 if (mProgressTintInfo == null) {
361 mProgressTintInfo = new ProgressTintInfo();
362 }
363 mProgressTintInfo.mSecondaryProgressTintMode = Drawable.parseTintMode(
364 a.getInt(R.styleable.ProgressBar_secondaryProgressTintMode, -1), null);
365 mProgressTintInfo.mHasSecondaryProgressTintMode = true;
366 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700367
Alan Viverette91174362014-06-17 14:51:45 -0700368 if (a.hasValue(R.styleable.ProgressBar_secondaryProgressTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700369 if (mProgressTintInfo == null) {
370 mProgressTintInfo = new ProgressTintInfo();
371 }
372 mProgressTintInfo.mSecondaryProgressTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700373 R.styleable.ProgressBar_secondaryProgressTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700374 mProgressTintInfo.mHasSecondaryProgressTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700375 }
376
Alan Viverettedbc40182015-04-06 15:01:23 -0700377 if (a.hasValue(R.styleable.ProgressBar_indeterminateTintMode)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700378 if (mProgressTintInfo == null) {
379 mProgressTintInfo = new ProgressTintInfo();
380 }
381 mProgressTintInfo.mIndeterminateTintMode = Drawable.parseTintMode(a.getInt(
382 R.styleable.ProgressBar_indeterminateTintMode, -1), null);
383 mProgressTintInfo.mHasIndeterminateTintMode = true;
384 }
Alan Viverette4f64c042014-07-21 17:49:13 -0700385
Alan Viverette91174362014-06-17 14:51:45 -0700386 if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700387 if (mProgressTintInfo == null) {
388 mProgressTintInfo = new ProgressTintInfo();
389 }
390 mProgressTintInfo.mIndeterminateTintList = a.getColorStateList(
Alan Viverette91174362014-06-17 14:51:45 -0700391 R.styleable.ProgressBar_indeterminateTint);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700392 mProgressTintInfo.mHasIndeterminateTint = true;
Alan Viverette91174362014-06-17 14:51:45 -0700393 }
394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 a.recycle();
Svetoslav7face752014-01-13 15:25:58 -0800396
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700397 applyProgressTints();
398 applyIndeterminateTint();
399
Svetoslav7face752014-01-13 15:25:58 -0800400 // If not explicitly specified this view is important for accessibility.
401 if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
402 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 }
405
406 /**
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700407 * Returns {@code true} if the target drawable needs to be tileified.
408 *
409 * @param dr the drawable to check
410 * @return {@code true} if the target drawable needs to be tileified,
411 * {@code false} otherwise
412 */
413 private static boolean needsTileify(Drawable dr) {
414 if (dr instanceof LayerDrawable) {
415 final LayerDrawable orig = (LayerDrawable) dr;
416 final int N = orig.getNumberOfLayers();
417 for (int i = 0; i < N; i++) {
418 if (needsTileify(orig.getDrawable(i))) {
419 return true;
420 }
421 }
422 return false;
423 }
424
425 if (dr instanceof StateListDrawable) {
426 final StateListDrawable in = (StateListDrawable) dr;
427 final int N = in.getStateCount();
428 for (int i = 0; i < N; i++) {
429 if (needsTileify(in.getStateDrawable(i))) {
430 return true;
431 }
432 }
433 return false;
434 }
435
436 // If there's a bitmap that's not wrapped with a ClipDrawable or
437 // ScaleDrawable, we'll need to wrap it and apply tiling.
438 if (dr instanceof BitmapDrawable) {
439 return true;
440 }
441
442 return false;
443 }
444
445 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 * Converts a drawable to a tiled version of itself. It will recursively
447 * traverse layer and state list drawables.
448 */
449 private Drawable tileify(Drawable drawable, boolean clip) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800450 // TODO: This is a terrible idea that potentially destroys any drawable
451 // that extends any of these classes. We *really* need to remove this.
RoboErik5b071432015-02-11 13:52:05 -0800452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 if (drawable instanceof LayerDrawable) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800454 final LayerDrawable orig = (LayerDrawable) drawable;
455 final int N = orig.getNumberOfLayers();
456 final Drawable[] outDrawables = new Drawable[N];
RoboErik5b071432015-02-11 13:52:05 -0800457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 for (int i = 0; i < N; i++) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800459 final int id = orig.getId(i);
460 outDrawables[i] = tileify(orig.getDrawable(i),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 (id == R.id.progress || id == R.id.secondaryProgress));
462 }
463
Alan Viverette6a8253f2015-02-23 12:49:47 -0800464 final LayerDrawable clone = new LayerDrawable(outDrawables);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 for (int i = 0; i < N; i++) {
Alan Viverette6a8253f2015-02-23 12:49:47 -0800466 clone.setId(i, orig.getId(i));
467 clone.setLayerGravity(i, orig.getLayerGravity(i));
468 clone.setLayerWidth(i, orig.getLayerWidth(i));
469 clone.setLayerHeight(i, orig.getLayerHeight(i));
470 clone.setLayerInsetLeft(i, orig.getLayerInsetLeft(i));
471 clone.setLayerInsetRight(i, orig.getLayerInsetRight(i));
472 clone.setLayerInsetTop(i, orig.getLayerInsetTop(i));
473 clone.setLayerInsetBottom(i, orig.getLayerInsetBottom(i));
474 clone.setLayerInsetStart(i, orig.getLayerInsetStart(i));
475 clone.setLayerInsetEnd(i, orig.getLayerInsetEnd(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 }
RoboErik5b071432015-02-11 13:52:05 -0800477
Alan Viverette6a8253f2015-02-23 12:49:47 -0800478 return clone;
479 }
RoboErik5b071432015-02-11 13:52:05 -0800480
Alan Viverette6a8253f2015-02-23 12:49:47 -0800481 if (drawable instanceof StateListDrawable) {
482 final StateListDrawable in = (StateListDrawable) drawable;
483 final StateListDrawable out = new StateListDrawable();
484 final int N = in.getStateCount();
485 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
487 }
RoboErik5b071432015-02-11 13:52:05 -0800488
Alan Viverette6a8253f2015-02-23 12:49:47 -0800489 return out;
490 }
491
492 if (drawable instanceof BitmapDrawable) {
Alan Viverette813d85b2014-02-26 15:38:51 -0800493 final BitmapDrawable bitmap = (BitmapDrawable) drawable;
494 final Bitmap tileBitmap = bitmap.getBitmap();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 if (mSampleTile == null) {
496 mSampleTile = tileBitmap;
497 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700499 final BitmapDrawable clone = (BitmapDrawable) bitmap.getConstantState().newDrawable();
500 clone.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501
Alan Viveretteff9f7b962015-04-08 10:49:26 -0700502 if (clip) {
503 return new ClipDrawable(clone, Gravity.LEFT, ClipDrawable.HORIZONTAL);
504 } else {
505 return clone;
506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 }
RoboErik5b071432015-02-11 13:52:05 -0800508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 return drawable;
510 }
511
512 Shape getDrawableShape() {
513 final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
514 return new RoundRectShape(roundedCorners, null, null);
515 }
RoboErik5b071432015-02-11 13:52:05 -0800516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 /**
518 * Convert a AnimationDrawable for use as a barberpole animation.
519 * Each frame of the animation is wrapped in a ClipDrawable and
520 * given a tiling BitmapShader.
521 */
522 private Drawable tileifyIndeterminate(Drawable drawable) {
523 if (drawable instanceof AnimationDrawable) {
524 AnimationDrawable background = (AnimationDrawable) drawable;
525 final int N = background.getNumberOfFrames();
526 AnimationDrawable newBg = new AnimationDrawable();
527 newBg.setOneShot(background.isOneShot());
RoboErik5b071432015-02-11 13:52:05 -0800528
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529 for (int i = 0; i < N; i++) {
530 Drawable frame = tileify(background.getFrame(i), true);
531 frame.setLevel(10000);
532 newBg.addFrame(frame, background.getDuration(i));
533 }
534 newBg.setLevel(10000);
535 drawable = newBg;
536 }
537 return drawable;
538 }
RoboErik5b071432015-02-11 13:52:05 -0800539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 /**
541 * <p>
542 * Initialize the progress bar's default values:
543 * </p>
544 * <ul>
545 * <li>progress = 0</li>
546 * <li>max = 100</li>
547 * <li>animation duration = 4000 ms</li>
548 * <li>indeterminate = false</li>
549 * <li>behavior = repeat</li>
550 * </ul>
551 */
552 private void initProgressBar() {
553 mMax = 100;
554 mProgress = 0;
555 mSecondaryProgress = 0;
556 mIndeterminate = false;
557 mOnlyIndeterminate = false;
558 mDuration = 4000;
559 mBehavior = AlphaAnimation.RESTART;
560 mMinWidth = 24;
561 mMaxWidth = 48;
562 mMinHeight = 24;
563 mMaxHeight = 48;
564 }
565
566 /**
567 * <p>Indicate whether this progress bar is in indeterminate mode.</p>
568 *
569 * @return true if the progress bar is in indeterminate mode
570 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700571 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 public synchronized boolean isIndeterminate() {
573 return mIndeterminate;
574 }
575
576 /**
577 * <p>Change the indeterminate mode for this progress bar. In indeterminate
578 * mode, the progress is ignored and the progress bar shows an infinite
579 * animation instead.</p>
RoboErik5b071432015-02-11 13:52:05 -0800580 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 * If this progress bar's style only supports indeterminate mode (such as the circular
582 * progress bars), then this will be ignored.
583 *
584 * @param indeterminate true to enable the indeterminate mode
585 */
586 @android.view.RemotableViewMethod
587 public synchronized void setIndeterminate(boolean indeterminate) {
588 if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
589 mIndeterminate = indeterminate;
590
591 if (indeterminate) {
592 // swap between indeterminate and regular backgrounds
593 mCurrentDrawable = mIndeterminateDrawable;
594 startAnimation();
595 } else {
596 mCurrentDrawable = mProgressDrawable;
597 stopAnimation();
598 }
599 }
600 }
601
602 /**
603 * <p>Get the drawable used to draw the progress bar in
604 * indeterminate mode.</p>
605 *
606 * @return a {@link android.graphics.drawable.Drawable} instance
607 *
608 * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable)
609 * @see #setIndeterminate(boolean)
610 */
611 public Drawable getIndeterminateDrawable() {
612 return mIndeterminateDrawable;
613 }
614
615 /**
Alan Viverettee785d022013-09-26 15:21:10 -0700616 * Define the drawable used to draw the progress bar in indeterminate mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 *
618 * @param d the new drawable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 * @see #getIndeterminateDrawable()
620 * @see #setIndeterminate(boolean)
621 */
622 public void setIndeterminateDrawable(Drawable d) {
Alan Viverette91174362014-06-17 14:51:45 -0700623 if (mIndeterminateDrawable != d) {
624 if (mIndeterminateDrawable != null) {
625 mIndeterminateDrawable.setCallback(null);
626 unscheduleDrawable(mIndeterminateDrawable);
627 }
628
629 mIndeterminateDrawable = d;
630
631 if (d != null) {
632 d.setCallback(this);
633 d.setLayoutDirection(getLayoutDirection());
634 if (d.isStateful()) {
635 d.setState(getDrawableState());
636 }
637 applyIndeterminateTint();
638 }
639
640 if (mIndeterminate) {
641 mCurrentDrawable = d;
642 postInvalidate();
643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 }
Alan Viverette91174362014-06-17 14:51:45 -0700645 }
646
647 /**
Alan Viverette91174362014-06-17 14:51:45 -0700648 * Applies a tint to the indeterminate drawable. Does not modify the
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700649 * current tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -0700650 * <p>
651 * Subsequent calls to {@link #setIndeterminateDrawable(Drawable)} will
652 * automatically mutate the drawable and apply the specified tint and
653 * tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700654 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -0700655 *
656 * @param tint the tint to apply, may be {@code null} to clear tint
657 *
658 * @attr ref android.R.styleable#ProgressBar_indeterminateTint
Alan Viverettea4264452014-07-28 16:02:55 -0700659 * @see #getIndeterminateTintList()
660 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700661 */
Jorim Jaggief72a192014-08-26 21:57:46 +0200662 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -0700663 public void setIndeterminateTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700664 if (mProgressTintInfo == null) {
665 mProgressTintInfo = new ProgressTintInfo();
666 }
667 mProgressTintInfo.mIndeterminateTintList = tint;
668 mProgressTintInfo.mHasIndeterminateTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700669
670 applyIndeterminateTint();
Alan Viverette91174362014-06-17 14:51:45 -0700671 }
672
673 /**
674 * @return the tint applied to the indeterminate drawable
675 * @attr ref android.R.styleable#ProgressBar_indeterminateTint
Alan Viverettea4264452014-07-28 16:02:55 -0700676 * @see #setIndeterminateTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700677 */
678 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -0700679 public ColorStateList getIndeterminateTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700680 return mProgressTintInfo != null ? mProgressTintInfo.mIndeterminateTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -0700681 }
682
683 /**
684 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -0700685 * {@link #setIndeterminateTintList(ColorStateList)} to the indeterminate
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700686 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -0700687 *
688 * @param tintMode the blending mode used to apply the tint, may be
689 * {@code null} to clear tint
690 * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
Alan Viverettea4264452014-07-28 16:02:55 -0700691 * @see #setIndeterminateTintList(ColorStateList)
692 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700693 */
694 public void setIndeterminateTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700695 if (mProgressTintInfo == null) {
696 mProgressTintInfo = new ProgressTintInfo();
697 }
698 mProgressTintInfo.mIndeterminateTintMode = tintMode;
699 mProgressTintInfo.mHasIndeterminateTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700700
701 applyIndeterminateTint();
Alan Viverette91174362014-06-17 14:51:45 -0700702 }
703
704 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700705 * Returns the blending mode used to apply the tint to the indeterminate
706 * drawable, if specified.
707 *
708 * @return the blending mode used to apply the tint to the indeterminate
709 * drawable
Alan Viverette91174362014-06-17 14:51:45 -0700710 * @attr ref android.R.styleable#ProgressBar_indeterminateTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700711 * @see #setIndeterminateTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700712 */
713 @Nullable
714 public PorterDuff.Mode getIndeterminateTintMode() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700715 return mProgressTintInfo != null ? mProgressTintInfo.mIndeterminateTintMode : null;
Alan Viverette91174362014-06-17 14:51:45 -0700716 }
717
718 private void applyIndeterminateTint() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700719 if (mIndeterminateDrawable != null && mProgressTintInfo != null) {
720 final ProgressTintInfo tintInfo = mProgressTintInfo;
721 if (tintInfo.mHasIndeterminateTint || tintInfo.mHasIndeterminateTintMode) {
722 mIndeterminateDrawable = mIndeterminateDrawable.mutate();
723
724 if (tintInfo.mHasIndeterminateTint) {
725 mIndeterminateDrawable.setTintList(tintInfo.mIndeterminateTintList);
726 }
727
728 if (tintInfo.mHasIndeterminateTintMode) {
729 mIndeterminateDrawable.setTintMode(tintInfo.mIndeterminateTintMode);
730 }
Alan Viveretted5133792014-10-28 14:41:36 -0700731
732 // The drawable (or one of its children) may not have been
733 // stateful before applying the tint, so let's try again.
734 if (mIndeterminateDrawable.isStateful()) {
735 mIndeterminateDrawable.setState(getDrawableState());
736 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 }
739 }
Alan Viverettee785d022013-09-26 15:21:10 -0700740
741 /**
742 * Define the tileable drawable used to draw the progress bar in
743 * indeterminate mode.
744 * <p>
745 * If the drawable is a BitmapDrawable or contains BitmapDrawables, a
746 * tiled copy will be generated for display as a progress bar.
747 *
748 * @param d the new drawable
749 * @see #getIndeterminateDrawable()
750 * @see #setIndeterminate(boolean)
751 */
752 public void setIndeterminateDrawableTiled(Drawable d) {
753 if (d != null) {
754 d = tileifyIndeterminate(d);
755 }
756
757 setIndeterminateDrawable(d);
758 }
RoboErik5b071432015-02-11 13:52:05 -0800759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 /**
761 * <p>Get the drawable used to draw the progress bar in
762 * progress mode.</p>
763 *
764 * @return a {@link android.graphics.drawable.Drawable} instance
765 *
766 * @see #setProgressDrawable(android.graphics.drawable.Drawable)
767 * @see #setIndeterminate(boolean)
768 */
769 public Drawable getProgressDrawable() {
770 return mProgressDrawable;
771 }
772
773 /**
Alan Viverettee785d022013-09-26 15:21:10 -0700774 * Define the drawable used to draw the progress bar in progress mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 *
776 * @param d the new drawable
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * @see #getProgressDrawable()
778 * @see #setIndeterminate(boolean)
779 */
780 public void setProgressDrawable(Drawable d) {
Alan Viverette91174362014-06-17 14:51:45 -0700781 if (mProgressDrawable != d) {
782 if (mProgressDrawable != null) {
783 mProgressDrawable.setCallback(null);
784 unscheduleDrawable(mProgressDrawable);
785 }
Joe Onoratoaa072632010-12-08 15:31:28 -0800786
Alan Viverette91174362014-06-17 14:51:45 -0700787 mProgressDrawable = d;
788
789 if (d != null) {
790 d.setCallback(this);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700791 d.setLayoutDirection(getLayoutDirection());
Alan Viverette91174362014-06-17 14:51:45 -0700792 if (d.isStateful()) {
793 d.setState(getDrawableState());
794 }
795
796 // Make sure the ProgressBar is always tall enough
797 int drawableHeight = d.getMinimumHeight();
798 if (mMaxHeight < drawableHeight) {
799 mMaxHeight = drawableHeight;
800 requestLayout();
801 }
802
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700803 applyProgressTints();
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700804 }
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500805
Alan Viverette91174362014-06-17 14:51:45 -0700806 if (!mIndeterminate) {
807 mCurrentDrawable = d;
808 postInvalidate();
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500809 }
Joe Onoratoaa072632010-12-08 15:31:28 -0800810
Joe Onoratoaa072632010-12-08 15:31:28 -0800811 updateDrawableBounds(getWidth(), getHeight());
812 updateDrawableState();
Alan Viverette91174362014-06-17 14:51:45 -0700813
Joe Onoratoaa072632010-12-08 15:31:28 -0800814 doRefreshProgress(R.id.progress, mProgress, false, false);
815 doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
816 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 }
Alan Viverettee785d022013-09-26 15:21:10 -0700818
819 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700820 * Applies the progress tints in order of increasing specificity.
821 */
822 private void applyProgressTints() {
823 if (mProgressDrawable != null && mProgressTintInfo != null) {
824 applyPrimaryProgressTint();
825 applyProgressBackgroundTint();
826 applySecondaryProgressTint();
827 }
828 }
829
830 /**
831 * Should only be called if we've already verified that mProgressDrawable
832 * and mProgressTintInfo are non-null.
833 */
834 private void applyPrimaryProgressTint() {
835 if (mProgressTintInfo.mHasProgressTint
836 || mProgressTintInfo.mHasProgressTintMode) {
837 final Drawable target = getTintTarget(R.id.progress, true);
838 if (target != null) {
839 if (mProgressTintInfo.mHasProgressTint) {
840 target.setTintList(mProgressTintInfo.mProgressTintList);
841 }
842 if (mProgressTintInfo.mHasProgressTintMode) {
843 target.setTintMode(mProgressTintInfo.mProgressTintMode);
844 }
Alan Viveretted5133792014-10-28 14:41:36 -0700845
846 // The drawable (or one of its children) may not have been
847 // stateful before applying the tint, so let's try again.
848 if (target.isStateful()) {
849 target.setState(getDrawableState());
850 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700851 }
852 }
853 }
854
855 /**
856 * Should only be called if we've already verified that mProgressDrawable
857 * and mProgressTintInfo are non-null.
858 */
859 private void applyProgressBackgroundTint() {
860 if (mProgressTintInfo.mHasProgressBackgroundTint
861 || mProgressTintInfo.mHasProgressBackgroundTintMode) {
862 final Drawable target = getTintTarget(R.id.background, false);
863 if (target != null) {
864 if (mProgressTintInfo.mHasProgressBackgroundTint) {
865 target.setTintList(mProgressTintInfo.mProgressBackgroundTintList);
866 }
867 if (mProgressTintInfo.mHasProgressBackgroundTintMode) {
868 target.setTintMode(mProgressTintInfo.mProgressBackgroundTintMode);
869 }
Alan Viveretted5133792014-10-28 14:41:36 -0700870
871 // The drawable (or one of its children) may not have been
872 // stateful before applying the tint, so let's try again.
873 if (target.isStateful()) {
874 target.setState(getDrawableState());
875 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700876 }
877 }
878 }
879
880 /**
881 * Should only be called if we've already verified that mProgressDrawable
882 * and mProgressTintInfo are non-null.
883 */
884 private void applySecondaryProgressTint() {
885 if (mProgressTintInfo.mHasSecondaryProgressTint
886 || mProgressTintInfo.mHasSecondaryProgressTintMode) {
887 final Drawable target = getTintTarget(R.id.secondaryProgress, false);
888 if (target != null) {
889 if (mProgressTintInfo.mHasSecondaryProgressTint) {
890 target.setTintList(mProgressTintInfo.mSecondaryProgressTintList);
891 }
892 if (mProgressTintInfo.mHasSecondaryProgressTintMode) {
893 target.setTintMode(mProgressTintInfo.mSecondaryProgressTintMode);
894 }
Alan Viveretted5133792014-10-28 14:41:36 -0700895
896 // The drawable (or one of its children) may not have been
897 // stateful before applying the tint, so let's try again.
898 if (target.isStateful()) {
899 target.setState(getDrawableState());
900 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700901 }
902 }
903 }
904
905 /**
Alan Viverette91174362014-06-17 14:51:45 -0700906 * Applies a tint to the progress indicator, if one exists, or to the
Alan Viverette91174362014-06-17 14:51:45 -0700907 * entire progress drawable otherwise. Does not modify the current tint
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700908 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -0700909 * <p>
910 * The progress indicator should be specified as a layer with
911 * id {@link android.R.id#progress} in a {@link LayerDrawable}
912 * used as the progress drawable.
913 * <p>
914 * Subsequent calls to {@link #setProgressDrawable(Drawable)} will
915 * automatically mutate the drawable and apply the specified tint and
916 * tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700917 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -0700918 *
919 * @param tint the tint to apply, may be {@code null} to clear tint
920 *
921 * @attr ref android.R.styleable#ProgressBar_progressTint
Alan Viverettea4264452014-07-28 16:02:55 -0700922 * @see #getProgressTintList()
923 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700924 */
Jorim Jaggief72a192014-08-26 21:57:46 +0200925 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -0700926 public void setProgressTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700927 if (mProgressTintInfo == null) {
928 mProgressTintInfo = new ProgressTintInfo();
929 }
930 mProgressTintInfo.mProgressTintList = tint;
931 mProgressTintInfo.mHasProgressTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700932
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700933 if (mProgressDrawable != null) {
934 applyPrimaryProgressTint();
935 }
Alan Viverette91174362014-06-17 14:51:45 -0700936 }
937
938 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700939 * Returns the tint applied to the progress drawable, if specified.
940 *
Alan Viverette91174362014-06-17 14:51:45 -0700941 * @return the tint applied to the progress drawable
942 * @attr ref android.R.styleable#ProgressBar_progressTint
Alan Viverettea4264452014-07-28 16:02:55 -0700943 * @see #setProgressTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700944 */
945 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -0700946 public ColorStateList getProgressTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700947 return mProgressTintInfo != null ? mProgressTintInfo.mProgressTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -0700948 }
949
950 /**
951 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -0700952 * {@link #setProgressTintList(ColorStateList)}} to the progress
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700953 * indicator. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -0700954 *
955 * @param tintMode the blending mode used to apply the tint, may be
956 * {@code null} to clear tint
957 * @attr ref android.R.styleable#ProgressBar_progressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700958 * @see #getProgressTintMode()
Alan Viverettea4264452014-07-28 16:02:55 -0700959 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700960 */
961 public void setProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700962 if (mProgressTintInfo == null) {
963 mProgressTintInfo = new ProgressTintInfo();
964 }
965 mProgressTintInfo.mProgressTintMode = tintMode;
966 mProgressTintInfo.mHasProgressTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700967
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700968 if (mProgressDrawable != null) {
969 applyPrimaryProgressTint();
970 }
Alan Viverette91174362014-06-17 14:51:45 -0700971 }
972
973 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700974 * Returns the blending mode used to apply the tint to the progress
975 * drawable, if specified.
976 *
977 * @return the blending mode used to apply the tint to the progress
978 * drawable
Alan Viverette91174362014-06-17 14:51:45 -0700979 * @attr ref android.R.styleable#ProgressBar_progressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -0700980 * @see #setProgressTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700981 */
982 @Nullable
983 public PorterDuff.Mode getProgressTintMode() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700984 return mProgressTintInfo != null ? mProgressTintInfo.mProgressTintMode : null;
Alan Viverette91174362014-06-17 14:51:45 -0700985 }
986
987 /**
Alan Viverette91174362014-06-17 14:51:45 -0700988 * Applies a tint to the progress background, if one exists. Does not
989 * modify the current tint mode, which is
990 * {@link PorterDuff.Mode#SRC_ATOP} by default.
991 * <p>
992 * The progress background must be specified as a layer with
993 * id {@link android.R.id#background} in a {@link LayerDrawable}
994 * used as the progress drawable.
995 * <p>
996 * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
997 * drawable contains a progress background will automatically mutate the
998 * drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700999 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -07001000 *
1001 * @param tint the tint to apply, may be {@code null} to clear tint
1002 *
1003 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
Alan Viverettea4264452014-07-28 16:02:55 -07001004 * @see #getProgressBackgroundTintList()
1005 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001006 */
Jorim Jaggief72a192014-08-26 21:57:46 +02001007 @RemotableViewMethod
Alan Viverettea4264452014-07-28 16:02:55 -07001008 public void setProgressBackgroundTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001009 if (mProgressTintInfo == null) {
1010 mProgressTintInfo = new ProgressTintInfo();
1011 }
1012 mProgressTintInfo.mProgressBackgroundTintList = tint;
1013 mProgressTintInfo.mHasProgressBackgroundTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001014
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001015 if (mProgressDrawable != null) {
1016 applyProgressBackgroundTint();
1017 }
Alan Viverette91174362014-06-17 14:51:45 -07001018 }
1019
1020 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001021 * Returns the tint applied to the progress background, if specified.
1022 *
Alan Viverette91174362014-06-17 14:51:45 -07001023 * @return the tint applied to the progress background
1024 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTint
Alan Viverettea4264452014-07-28 16:02:55 -07001025 * @see #setProgressBackgroundTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001026 */
1027 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -07001028 public ColorStateList getProgressBackgroundTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001029 return mProgressTintInfo != null ? mProgressTintInfo.mProgressBackgroundTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -07001030 }
1031
1032 /**
1033 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -07001034 * {@link #setProgressBackgroundTintList(ColorStateList)}} to the progress
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001035 * background. The default mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -07001036 *
1037 * @param tintMode the blending mode used to apply the tint, may be
1038 * {@code null} to clear tint
1039 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
Alan Viverettea4264452014-07-28 16:02:55 -07001040 * @see #setProgressBackgroundTintList(ColorStateList)
1041 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001042 */
1043 public void setProgressBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001044 if (mProgressTintInfo == null) {
1045 mProgressTintInfo = new ProgressTintInfo();
1046 }
1047 mProgressTintInfo.mProgressBackgroundTintMode = tintMode;
1048 mProgressTintInfo.mHasProgressBackgroundTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001049
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001050 if (mProgressDrawable != null) {
1051 applyProgressBackgroundTint();
1052 }
Alan Viverette91174362014-06-17 14:51:45 -07001053 }
1054
1055 /**
1056 * @return the blending mode used to apply the tint to the progress
1057 * background
1058 * @attr ref android.R.styleable#ProgressBar_progressBackgroundTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -07001059 * @see #setProgressBackgroundTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001060 */
1061 @Nullable
1062 public PorterDuff.Mode getProgressBackgroundTintMode() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001063 return mProgressTintInfo != null ? mProgressTintInfo.mProgressBackgroundTintMode : null;
Alan Viverette91174362014-06-17 14:51:45 -07001064 }
1065
1066 /**
1067 * Applies a tint to the secondary progress indicator, if one exists.
Alan Viverette91174362014-06-17 14:51:45 -07001068 * Does not modify the current tint mode, which is
1069 * {@link PorterDuff.Mode#SRC_ATOP} by default.
1070 * <p>
1071 * The secondary progress indicator must be specified as a layer with
1072 * id {@link android.R.id#secondaryProgress} in a {@link LayerDrawable}
1073 * used as the progress drawable.
1074 * <p>
1075 * Subsequent calls to {@link #setProgressDrawable(Drawable)} where the
1076 * drawable contains a secondary progress indicator will automatically
1077 * mutate the drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -07001078 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette91174362014-06-17 14:51:45 -07001079 *
1080 * @param tint the tint to apply, may be {@code null} to clear tint
1081 *
1082 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
Alan Viverettea4264452014-07-28 16:02:55 -07001083 * @see #getSecondaryProgressTintList()
1084 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001085 */
Alan Viverettea4264452014-07-28 16:02:55 -07001086 public void setSecondaryProgressTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001087 if (mProgressTintInfo == null) {
1088 mProgressTintInfo = new ProgressTintInfo();
1089 }
1090 mProgressTintInfo.mSecondaryProgressTintList = tint;
1091 mProgressTintInfo.mHasSecondaryProgressTint = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001092
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001093 if (mProgressDrawable != null) {
1094 applySecondaryProgressTint();
1095 }
Alan Viverette91174362014-06-17 14:51:45 -07001096 }
1097
1098 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001099 * Returns the tint applied to the secondary progress drawable, if
1100 * specified.
1101 *
Alan Viverette91174362014-06-17 14:51:45 -07001102 * @return the tint applied to the secondary progress drawable
1103 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTint
Alan Viverettea4264452014-07-28 16:02:55 -07001104 * @see #setSecondaryProgressTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -07001105 */
1106 @Nullable
Alan Viverettea4264452014-07-28 16:02:55 -07001107 public ColorStateList getSecondaryProgressTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001108 return mProgressTintInfo != null ? mProgressTintInfo.mSecondaryProgressTintList : null;
Alan Viverette91174362014-06-17 14:51:45 -07001109 }
1110
1111 /**
1112 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -07001113 * {@link #setSecondaryProgressTintList(ColorStateList)}} to the secondary
Alan Viverette91174362014-06-17 14:51:45 -07001114 * progress indicator. The default mode is
1115 * {@link PorterDuff.Mode#SRC_ATOP}.
1116 *
1117 * @param tintMode the blending mode used to apply the tint, may be
1118 * {@code null} to clear tint
1119 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
Alan Viverettea4264452014-07-28 16:02:55 -07001120 * @see #setSecondaryProgressTintList(ColorStateList)
1121 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001122 */
1123 public void setSecondaryProgressTintMode(@Nullable PorterDuff.Mode tintMode) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001124 if (mProgressTintInfo == null) {
1125 mProgressTintInfo = new ProgressTintInfo();
1126 }
1127 mProgressTintInfo.mSecondaryProgressTintMode = tintMode;
1128 mProgressTintInfo.mHasSecondaryProgressTintMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -07001129
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001130 if (mProgressDrawable != null) {
1131 applySecondaryProgressTint();
1132 }
Alan Viverette91174362014-06-17 14:51:45 -07001133 }
1134
1135 /**
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001136 * Returns the blending mode used to apply the tint to the secondary
1137 * progress drawable, if specified.
1138 *
Alan Viverette91174362014-06-17 14:51:45 -07001139 * @return the blending mode used to apply the tint to the secondary
1140 * progress drawable
1141 * @attr ref android.R.styleable#ProgressBar_secondaryProgressTintMode
Alan Viverette4f64c042014-07-21 17:49:13 -07001142 * @see #setSecondaryProgressTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -07001143 */
1144 @Nullable
1145 public PorterDuff.Mode getSecondaryProgressTintMode() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001146 return mProgressTintInfo != null ? mProgressTintInfo.mSecondaryProgressTintMode : null;
Alan Viverette91174362014-06-17 14:51:45 -07001147 }
1148
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001149 /**
1150 * Returns the drawable to which a tint or tint mode should be applied.
1151 *
1152 * @param layerId id of the layer to modify
1153 * @param shouldFallback whether the base drawable should be returned
1154 * if the id does not exist
1155 * @return the drawable to modify
1156 */
1157 @Nullable
1158 private Drawable getTintTarget(int layerId, boolean shouldFallback) {
1159 Drawable layer = null;
1160
Alan Viverette91174362014-06-17 14:51:45 -07001161 final Drawable d = mProgressDrawable;
1162 if (d != null) {
1163 mProgressDrawable = d.mutate();
1164
Alan Viverette91174362014-06-17 14:51:45 -07001165 if (d instanceof LayerDrawable) {
1166 layer = ((LayerDrawable) d).findDrawableByLayerId(layerId);
1167 }
1168
1169 if (shouldFallback && layer == null) {
1170 layer = d;
1171 }
Alan Viverette91174362014-06-17 14:51:45 -07001172 }
Alan Viveretteb56f5d22014-09-14 15:48:50 -07001173
1174 return layer;
Alan Viverette91174362014-06-17 14:51:45 -07001175 }
1176
1177 /**
Alan Viverettee785d022013-09-26 15:21:10 -07001178 * Define the tileable drawable used to draw the progress bar in
1179 * progress mode.
1180 * <p>
1181 * If the drawable is a BitmapDrawable or contains BitmapDrawables, a
1182 * tiled copy will be generated for display as a progress bar.
1183 *
1184 * @param d the new drawable
1185 * @see #getProgressDrawable()
1186 * @see #setIndeterminate(boolean)
1187 */
1188 public void setProgressDrawableTiled(Drawable d) {
1189 if (d != null) {
1190 d = tileify(d, false);
1191 }
1192
1193 setProgressDrawable(d);
1194 }
RoboErik5b071432015-02-11 13:52:05 -08001195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 /**
1197 * @return The drawable currently used to draw the progress bar
1198 */
1199 Drawable getCurrentDrawable() {
1200 return mCurrentDrawable;
1201 }
1202
1203 @Override
1204 protected boolean verifyDrawable(Drawable who) {
1205 return who == mProgressDrawable || who == mIndeterminateDrawable
1206 || super.verifyDrawable(who);
1207 }
1208
1209 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07001210 public void jumpDrawablesToCurrentState() {
1211 super.jumpDrawablesToCurrentState();
1212 if (mProgressDrawable != null) mProgressDrawable.jumpToCurrentState();
1213 if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState();
1214 }
1215
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07001216 /**
1217 * @hide
1218 */
Dianne Hackborne2136772010-11-04 15:08:59 -07001219 @Override
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -07001220 public void onResolveDrawables(int layoutDirection) {
1221 final Drawable d = mCurrentDrawable;
1222 if (d != null) {
1223 d.setLayoutDirection(layoutDirection);
1224 }
1225 if (mIndeterminateDrawable != null) {
1226 mIndeterminateDrawable.setLayoutDirection(layoutDirection);
1227 }
1228 if (mProgressDrawable != null) {
1229 mProgressDrawable.setLayoutDirection(layoutDirection);
1230 }
1231 }
1232
1233 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 public void postInvalidate() {
1235 if (!mNoInvalidate) {
1236 super.postInvalidate();
1237 }
1238 }
1239
1240 private class RefreshProgressRunnable implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 public void run() {
Adam Powella0506632012-04-10 17:19:20 -07001242 synchronized (ProgressBar.this) {
1243 final int count = mRefreshData.size();
1244 for (int i = 0; i < count; i++) {
1245 final RefreshData rd = mRefreshData.get(i);
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001246 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
Adam Powella0506632012-04-10 17:19:20 -07001247 rd.recycle();
1248 }
1249 mRefreshData.clear();
1250 mRefreshIsPosted = false;
1251 }
1252 }
1253 }
1254
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001255 private static class RefreshData {
1256 private static final int POOL_MAX = 24;
1257 private static final SynchronizedPool<RefreshData> sPool =
1258 new SynchronizedPool<RefreshData>(POOL_MAX);
1259
Adam Powella0506632012-04-10 17:19:20 -07001260 public int id;
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001261 public int progress;
Adam Powella0506632012-04-10 17:19:20 -07001262 public boolean fromUser;
Adam Powella0506632012-04-10 17:19:20 -07001263
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001264 public static RefreshData obtain(int id, int progress, boolean fromUser) {
Adam Powella0506632012-04-10 17:19:20 -07001265 RefreshData rd = sPool.acquire();
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001266 if (rd == null) {
1267 rd = new RefreshData();
1268 }
Adam Powella0506632012-04-10 17:19:20 -07001269 rd.id = id;
1270 rd.progress = progress;
1271 rd.fromUser = fromUser;
1272 return rd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 }
RoboErik5b071432015-02-11 13:52:05 -08001274
Adam Powella0506632012-04-10 17:19:20 -07001275 public void recycle() {
1276 sPool.release(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 }
Svetoslav Ganovabae2a12012-11-27 16:59:37 -08001279
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001280 private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
Joe Onoratoaa072632010-12-08 15:31:28 -08001281 boolean callBackToApp) {
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001282 float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
Alan Viverettebac8e122015-02-04 17:15:01 -08001283 final Drawable d = mCurrentDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 if (d != null) {
1285 Drawable progressDrawable = null;
1286
1287 if (d instanceof LayerDrawable) {
1288 progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -07001289 if (progressDrawable != null && canResolveLayoutDirection()) {
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07001290 progressDrawable.setLayoutDirection(getLayoutDirection());
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -07001291 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 }
1293
1294 final int level = (int) (scale * MAX_LEVEL);
1295 (progressDrawable != null ? progressDrawable : d).setLevel(level);
1296 } else {
1297 invalidate();
1298 }
RoboErik5b071432015-02-11 13:52:05 -08001299
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001300 if (callBackToApp && id == R.id.progress) {
RoboErik5b071432015-02-11 13:52:05 -08001301 onProgressRefresh(scale, fromUser, progress);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 }
1303 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001304
RoboErik5b071432015-02-11 13:52:05 -08001305 void onProgressRefresh(float scale, boolean fromUser, int progress) {
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001306 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
1307 scheduleAccessibilityEventSender();
1308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 }
1310
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001311 private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 if (mUiThreadId == Thread.currentThread().getId()) {
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001313 doRefreshProgress(id, progress, fromUser, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001315 if (mRefreshProgressRunnable == null) {
1316 mRefreshProgressRunnable = new RefreshProgressRunnable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 }
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001318
Alan Viverette5ce0ec02014-11-25 09:40:54 -08001319 final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
Adam Powella0506632012-04-10 17:19:20 -07001320 mRefreshData.add(rd);
1321 if (mAttached && !mRefreshIsPosted) {
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001322 post(mRefreshProgressRunnable);
Adam Powella0506632012-04-10 17:19:20 -07001323 mRefreshIsPosted = true;
1324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 }
1326 }
RoboErik5b071432015-02-11 13:52:05 -08001327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 /**
1329 * <p>Set the current progress to the specified value. Does not do anything
1330 * if the progress bar is in indeterminate mode.</p>
1331 *
1332 * @param progress the new progress, between 0 and {@link #getMax()}
1333 *
1334 * @see #setIndeterminate(boolean)
1335 * @see #isIndeterminate()
1336 * @see #getProgress()
RoboErik5b071432015-02-11 13:52:05 -08001337 * @see #incrementProgressBy(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338 */
1339 @android.view.RemotableViewMethod
1340 public synchronized void setProgress(int progress) {
1341 setProgress(progress, false);
1342 }
RoboErik5b071432015-02-11 13:52:05 -08001343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 @android.view.RemotableViewMethod
Alan Viverette12a44912015-04-16 13:06:00 -07001345 synchronized boolean setProgress(int progress, boolean fromUser) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001346 if (mIndeterminate) {
Alan Viverette12a44912015-04-16 13:06:00 -07001347 // Not applicable.
1348 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 }
1350
Alan Viverette12a44912015-04-16 13:06:00 -07001351 progress = MathUtils.constrain(progress, 0, mMax);
1352
1353 if (progress == mProgress) {
1354 // No change from current.
1355 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 }
1357
Alan Viverette12a44912015-04-16 13:06:00 -07001358 mProgress = progress;
1359 refreshProgress(R.id.progress, mProgress, fromUser);
1360 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 }
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}