blob: 5392a96715bf3590f986439b13663a592a3b52ab [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
Svetoslav Ganov6518ad72011-03-18 16:19:55 -070019import com.android.internal.R;
20
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.Context;
22import android.content.res.TypedArray;
23import android.graphics.Bitmap;
24import android.graphics.BitmapShader;
25import android.graphics.Canvas;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.graphics.Rect;
Steve Howardb25ffff2010-08-20 17:39:26 -070027import android.graphics.Shader;
28import android.graphics.drawable.Animatable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.graphics.drawable.AnimationDrawable;
30import android.graphics.drawable.BitmapDrawable;
31import android.graphics.drawable.ClipDrawable;
32import android.graphics.drawable.Drawable;
33import android.graphics.drawable.LayerDrawable;
34import android.graphics.drawable.ShapeDrawable;
35import android.graphics.drawable.StateListDrawable;
36import android.graphics.drawable.shapes.RoundRectShape;
37import android.graphics.drawable.shapes.Shape;
Steve Howardb25ffff2010-08-20 17:39:26 -070038import android.os.Parcel;
39import android.os.Parcelable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.util.AttributeSet;
Svetoslav Ganovabae2a12012-11-27 16:59:37 -080041import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.view.Gravity;
Steve Howardb25ffff2010-08-20 17:39:26 -070043import android.view.RemotableViewMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.view.View;
Steve Zeigler7a367882010-02-23 16:39:08 -080045import android.view.ViewDebug;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -070046import android.view.accessibility.AccessibilityEvent;
47import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080048import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.view.animation.AlphaAnimation;
50import android.view.animation.Animation;
51import android.view.animation.AnimationUtils;
52import android.view.animation.Interpolator;
53import android.view.animation.LinearInterpolator;
54import android.view.animation.Transformation;
55import android.widget.RemoteViews.RemoteView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
Adam Powella0506632012-04-10 17:19:20 -070057import java.util.ArrayList;
58
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
60/**
61 * <p>
62 * Visual indicator of progress in some operation. Displays a bar to the user
63 * representing how far the operation has progressed; the application can
64 * change the amount of progress (modifying the length of the bar) as it moves
65 * forward. There is also a secondary progress displayable on a progress bar
66 * which is useful for displaying intermediate progress, such as the buffer
67 * level during a streaming playback progress bar.
68 * </p>
69 *
70 * <p>
71 * A progress bar can also be made indeterminate. In indeterminate mode, the
Scott Main42f139c2011-04-29 10:31:10 -070072 * progress bar shows a cyclic animation without an indication of progress. This mode is used by
73 * applications when the length of the task is unknown. The indeterminate progress bar can be either
74 * a spinning wheel or a horizontal bar.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 * </p>
76 *
77 * <p>The following code example shows how a progress bar can be used from
78 * a worker thread to update the user interface to notify the user of progress:
79 * </p>
80 *
Scott Main42f139c2011-04-29 10:31:10 -070081 * <pre>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 * public class MyActivity extends Activity {
83 * private static final int PROGRESS = 0x1;
84 *
85 * private ProgressBar mProgress;
86 * private int mProgressStatus = 0;
87 *
88 * private Handler mHandler = new Handler();
89 *
90 * protected void onCreate(Bundle icicle) {
91 * super.onCreate(icicle);
92 *
93 * setContentView(R.layout.progressbar_activity);
94 *
95 * mProgress = (ProgressBar) findViewById(R.id.progress_bar);
96 *
97 * // Start lengthy operation in a background thread
98 * new Thread(new Runnable() {
99 * public void run() {
Scott Main42f139c2011-04-29 10:31:10 -0700100 * while (mProgressStatus &lt; 100) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 * mProgressStatus = doWork();
102 *
103 * // Update the progress bar
104 * mHandler.post(new Runnable() {
105 * public void run() {
106 * mProgress.setProgress(mProgressStatus);
107 * }
108 * });
109 * }
110 * }
111 * }).start();
112 * }
Scott Main42f139c2011-04-29 10:31:10 -0700113 * }</pre>
114 *
115 * <p>To add a progress bar to a layout file, you can use the {@code &lt;ProgressBar&gt;} element.
116 * By default, the progress bar is a spinning wheel (an indeterminate indicator). To change to a
117 * horizontal progress bar, apply the {@link android.R.style#Widget_ProgressBar_Horizontal
118 * Widget.ProgressBar.Horizontal} style, like so:</p>
119 *
120 * <pre>
121 * &lt;ProgressBar
122 * style="@android:style/Widget.ProgressBar.Horizontal"
123 * ... /&gt;</pre>
124 *
125 * <p>If you will use the progress bar to show real progress, you must use the horizontal bar. You
126 * can then increment the progress with {@link #incrementProgressBy incrementProgressBy()} or
127 * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If
128 * necessary, you can adjust the maximum value (the value for a full bar) using the {@link
129 * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed
130 * below.</p>
131 *
132 * <p>Another common style to apply to the progress bar is {@link
133 * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller
134 * version of the spinning wheel&mdash;useful when waiting for content to load.
135 * For example, you can insert this kind of progress bar into your default layout for
136 * a view that will be populated by some content fetched from the Internet&mdash;the spinning wheel
137 * appears immediately and when your application receives the content, it replaces the progress bar
138 * with the loaded content. For example:</p>
139 *
140 * <pre>
141 * &lt;LinearLayout
142 * android:orientation="horizontal"
143 * ... &gt;
144 * &lt;ProgressBar
145 * android:layout_width="wrap_content"
146 * android:layout_height="wrap_content"
147 * style="@android:style/Widget.ProgressBar.Small"
148 * android:layout_marginRight="5dp" /&gt;
149 * &lt;TextView
150 * android:layout_width="wrap_content"
151 * android:layout_height="wrap_content"
152 * android:text="@string/loading" /&gt;
153 * &lt;/LinearLayout&gt;</pre>
154 *
155 * <p>Other progress bar styles provided by the system include:</p>
156 * <ul>
157 * <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li>
158 * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li>
159 * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li>
160 * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li>
161 * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse
162 * Widget.ProgressBar.Small.Inverse}</li>
163 * <li>{@link android.R.style#Widget_ProgressBar_Large_Inverse
164 * Widget.ProgressBar.Large.Inverse}</li>
165 * </ul>
166 * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
167 * if your application uses a light colored theme (a white background).</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 *
169 * <p><strong>XML attributes</b></strong>
170 * <p>
171 * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
172 * {@link android.R.styleable#View View Attributes}
173 * </p>
174 *
Scott Main42f139c2011-04-29 10:31:10 -0700175 * @attr ref android.R.styleable#ProgressBar_animationResolution
176 * @attr ref android.R.styleable#ProgressBar_indeterminate
177 * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
178 * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
179 * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
180 * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
181 * @attr ref android.R.styleable#ProgressBar_interpolator
182 * @attr ref android.R.styleable#ProgressBar_max
183 * @attr ref android.R.styleable#ProgressBar_maxHeight
184 * @attr ref android.R.styleable#ProgressBar_maxWidth
185 * @attr ref android.R.styleable#ProgressBar_minHeight
186 * @attr ref android.R.styleable#ProgressBar_minWidth
Scott Mainb40c1fd2013-04-23 13:30:06 -0700187 * @attr ref android.R.styleable#ProgressBar_mirrorForRtl
Scott Main42f139c2011-04-29 10:31:10 -0700188 * @attr ref android.R.styleable#ProgressBar_progress
189 * @attr ref android.R.styleable#ProgressBar_progressDrawable
190 * @attr ref android.R.styleable#ProgressBar_secondaryProgress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 */
192@RemoteView
193public class ProgressBar extends View {
194 private static final int MAX_LEVEL = 10000;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700195 private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196
197 int mMinWidth;
198 int mMaxWidth;
199 int mMinHeight;
200 int mMaxHeight;
201
202 private int mProgress;
203 private int mSecondaryProgress;
204 private int mMax;
205
206 private int mBehavior;
207 private int mDuration;
208 private boolean mIndeterminate;
209 private boolean mOnlyIndeterminate;
210 private Transformation mTransformation;
211 private AlphaAnimation mAnimation;
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700212 private boolean mHasAnimation;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 private Drawable mIndeterminateDrawable;
214 private Drawable mProgressDrawable;
215 private Drawable mCurrentDrawable;
216 Bitmap mSampleTile;
217 private boolean mNoInvalidate;
218 private Interpolator mInterpolator;
219 private RefreshProgressRunnable mRefreshProgressRunnable;
220 private long mUiThreadId;
221 private boolean mShouldStartAnimationDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222
223 private boolean mInDrawing;
Adam Powella0506632012-04-10 17:19:20 -0700224 private boolean mAttached;
225 private boolean mRefreshIsPosted;
226
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800227 boolean mMirrorForRtl = false;
228
Adam Powella0506632012-04-10 17:19:20 -0700229 private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700231 private AccessibilityEventSender mAccessibilityEventSender;
232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 /**
234 * Create a new progress bar with range 0...100 and initial progress of 0.
235 * @param context the application environment
236 */
237 public ProgressBar(Context context) {
238 this(context, null);
239 }
240
241 public ProgressBar(Context context, AttributeSet attrs) {
242 this(context, attrs, com.android.internal.R.attr.progressBarStyle);
243 }
244
245 public ProgressBar(Context context, AttributeSet attrs, int defStyle) {
Adam Powell6af97e12010-11-11 21:11:53 -0800246 this(context, attrs, defStyle, 0);
247 }
248
249 /**
250 * @hide
251 */
252 public ProgressBar(Context context, AttributeSet attrs, int defStyle, int styleRes) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 super(context, attrs, defStyle);
254 mUiThreadId = Thread.currentThread().getId();
255 initProgressBar();
256
257 TypedArray a =
Adam Powell6af97e12010-11-11 21:11:53 -0800258 context.obtainStyledAttributes(attrs, R.styleable.ProgressBar, defStyle, styleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 mNoInvalidate = true;
261
262 Drawable drawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
263 if (drawable != null) {
264 drawable = tileify(drawable, false);
Romain Guy8d21bdb2009-12-30 13:54:04 -0800265 // Calling this method can set mMaxHeight, make sure the corresponding
266 // XML attribute for mMaxHeight is read after calling this method
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 setProgressDrawable(drawable);
268 }
269
270
271 mDuration = a.getInt(R.styleable.ProgressBar_indeterminateDuration, mDuration);
272
273 mMinWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_minWidth, mMinWidth);
274 mMaxWidth = a.getDimensionPixelSize(R.styleable.ProgressBar_maxWidth, mMaxWidth);
275 mMinHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_minHeight, mMinHeight);
276 mMaxHeight = a.getDimensionPixelSize(R.styleable.ProgressBar_maxHeight, mMaxHeight);
277
278 mBehavior = a.getInt(R.styleable.ProgressBar_indeterminateBehavior, mBehavior);
279
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700280 final int resID = a.getResourceId(
281 com.android.internal.R.styleable.ProgressBar_interpolator,
282 android.R.anim.linear_interpolator); // default to linear interpolator
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 if (resID > 0) {
284 setInterpolator(context, resID);
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700285 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286
287 setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
288
289 setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
290
291 setSecondaryProgress(
292 a.getInt(R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
293
294 drawable = a.getDrawable(R.styleable.ProgressBar_indeterminateDrawable);
295 if (drawable != null) {
296 drawable = tileifyIndeterminate(drawable);
297 setIndeterminateDrawable(drawable);
298 }
299
300 mOnlyIndeterminate = a.getBoolean(
301 R.styleable.ProgressBar_indeterminateOnly, mOnlyIndeterminate);
302
303 mNoInvalidate = false;
304
305 setIndeterminate(mOnlyIndeterminate || a.getBoolean(
306 R.styleable.ProgressBar_indeterminate, mIndeterminate));
307
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -0800308 mMirrorForRtl = a.getBoolean(R.styleable.ProgressBar_mirrorForRtl, mMirrorForRtl);
309
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 a.recycle();
311 }
312
313 /**
314 * Converts a drawable to a tiled version of itself. It will recursively
315 * traverse layer and state list drawables.
316 */
317 private Drawable tileify(Drawable drawable, boolean clip) {
318
319 if (drawable instanceof LayerDrawable) {
320 LayerDrawable background = (LayerDrawable) drawable;
321 final int N = background.getNumberOfLayers();
322 Drawable[] outDrawables = new Drawable[N];
323
324 for (int i = 0; i < N; i++) {
325 int id = background.getId(i);
326 outDrawables[i] = tileify(background.getDrawable(i),
327 (id == R.id.progress || id == R.id.secondaryProgress));
328 }
329
330 LayerDrawable newBg = new LayerDrawable(outDrawables);
331
332 for (int i = 0; i < N; i++) {
333 newBg.setId(i, background.getId(i));
334 }
335
336 return newBg;
337
338 } else if (drawable instanceof StateListDrawable) {
339 StateListDrawable in = (StateListDrawable) drawable;
340 StateListDrawable out = new StateListDrawable();
341 int numStates = in.getStateCount();
342 for (int i = 0; i < numStates; i++) {
343 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
344 }
345 return out;
346
347 } else if (drawable instanceof BitmapDrawable) {
348 final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
349 if (mSampleTile == null) {
350 mSampleTile = tileBitmap;
351 }
352
353 final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
354
355 final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
356 Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
357 shapeDrawable.getPaint().setShader(bitmapShader);
358
Fabrice Di Meglio7fb98b32012-09-12 20:04:04 -0700359 return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 ClipDrawable.HORIZONTAL) : shapeDrawable;
361 }
362
363 return drawable;
364 }
365
366 Shape getDrawableShape() {
367 final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
368 return new RoundRectShape(roundedCorners, null, null);
369 }
370
371 /**
372 * Convert a AnimationDrawable for use as a barberpole animation.
373 * Each frame of the animation is wrapped in a ClipDrawable and
374 * given a tiling BitmapShader.
375 */
376 private Drawable tileifyIndeterminate(Drawable drawable) {
377 if (drawable instanceof AnimationDrawable) {
378 AnimationDrawable background = (AnimationDrawable) drawable;
379 final int N = background.getNumberOfFrames();
380 AnimationDrawable newBg = new AnimationDrawable();
381 newBg.setOneShot(background.isOneShot());
382
383 for (int i = 0; i < N; i++) {
384 Drawable frame = tileify(background.getFrame(i), true);
385 frame.setLevel(10000);
386 newBg.addFrame(frame, background.getDuration(i));
387 }
388 newBg.setLevel(10000);
389 drawable = newBg;
390 }
391 return drawable;
392 }
393
394 /**
395 * <p>
396 * Initialize the progress bar's default values:
397 * </p>
398 * <ul>
399 * <li>progress = 0</li>
400 * <li>max = 100</li>
401 * <li>animation duration = 4000 ms</li>
402 * <li>indeterminate = false</li>
403 * <li>behavior = repeat</li>
404 * </ul>
405 */
406 private void initProgressBar() {
407 mMax = 100;
408 mProgress = 0;
409 mSecondaryProgress = 0;
410 mIndeterminate = false;
411 mOnlyIndeterminate = false;
412 mDuration = 4000;
413 mBehavior = AlphaAnimation.RESTART;
414 mMinWidth = 24;
415 mMaxWidth = 48;
416 mMinHeight = 24;
417 mMaxHeight = 48;
418 }
419
420 /**
421 * <p>Indicate whether this progress bar is in indeterminate mode.</p>
422 *
423 * @return true if the progress bar is in indeterminate mode
424 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700425 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 public synchronized boolean isIndeterminate() {
427 return mIndeterminate;
428 }
429
430 /**
431 * <p>Change the indeterminate mode for this progress bar. In indeterminate
432 * mode, the progress is ignored and the progress bar shows an infinite
433 * animation instead.</p>
434 *
435 * If this progress bar's style only supports indeterminate mode (such as the circular
436 * progress bars), then this will be ignored.
437 *
438 * @param indeterminate true to enable the indeterminate mode
439 */
440 @android.view.RemotableViewMethod
441 public synchronized void setIndeterminate(boolean indeterminate) {
442 if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
443 mIndeterminate = indeterminate;
444
445 if (indeterminate) {
446 // swap between indeterminate and regular backgrounds
447 mCurrentDrawable = mIndeterminateDrawable;
448 startAnimation();
449 } else {
450 mCurrentDrawable = mProgressDrawable;
451 stopAnimation();
452 }
453 }
454 }
455
456 /**
457 * <p>Get the drawable used to draw the progress bar in
458 * indeterminate mode.</p>
459 *
460 * @return a {@link android.graphics.drawable.Drawable} instance
461 *
462 * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable)
463 * @see #setIndeterminate(boolean)
464 */
465 public Drawable getIndeterminateDrawable() {
466 return mIndeterminateDrawable;
467 }
468
469 /**
470 * <p>Define the drawable used to draw the progress bar in
471 * indeterminate mode.</p>
472 *
473 * @param d the new drawable
474 *
475 * @see #getIndeterminateDrawable()
476 * @see #setIndeterminate(boolean)
477 */
478 public void setIndeterminateDrawable(Drawable d) {
479 if (d != null) {
480 d.setCallback(this);
481 }
482 mIndeterminateDrawable = d;
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700483 if (mIndeterminateDrawable != null && canResolveLayoutDirection()) {
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700484 mIndeterminateDrawable.setLayoutDirection(getLayoutDirection());
Fabrice Di Megliob03b4342012-06-04 12:55:30 -0700485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 if (mIndeterminate) {
487 mCurrentDrawable = d;
488 postInvalidate();
489 }
490 }
491
492 /**
493 * <p>Get the drawable used to draw the progress bar in
494 * progress mode.</p>
495 *
496 * @return a {@link android.graphics.drawable.Drawable} instance
497 *
498 * @see #setProgressDrawable(android.graphics.drawable.Drawable)
499 * @see #setIndeterminate(boolean)
500 */
501 public Drawable getProgressDrawable() {
502 return mProgressDrawable;
503 }
504
505 /**
506 * <p>Define the drawable used to draw the progress bar in
507 * progress mode.</p>
508 *
509 * @param d the new drawable
510 *
511 * @see #getProgressDrawable()
512 * @see #setIndeterminate(boolean)
513 */
514 public void setProgressDrawable(Drawable d) {
Joe Onoratoaa072632010-12-08 15:31:28 -0800515 boolean needUpdate;
516 if (mProgressDrawable != null && d != mProgressDrawable) {
517 mProgressDrawable.setCallback(null);
518 needUpdate = true;
519 } else {
520 needUpdate = false;
521 }
522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 if (d != null) {
524 d.setCallback(this);
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700525 if (canResolveLayoutDirection()) {
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700526 d.setLayoutDirection(getLayoutDirection());
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700527 }
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500528
Romain Guy8d21bdb2009-12-30 13:54:04 -0800529 // Make sure the ProgressBar is always tall enough
530 int drawableHeight = d.getMinimumHeight();
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500531 if (mMaxHeight < drawableHeight) {
532 mMaxHeight = drawableHeight;
533 requestLayout();
534 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 }
536 mProgressDrawable = d;
537 if (!mIndeterminate) {
538 mCurrentDrawable = d;
539 postInvalidate();
540 }
Joe Onoratoaa072632010-12-08 15:31:28 -0800541
542 if (needUpdate) {
543 updateDrawableBounds(getWidth(), getHeight());
544 updateDrawableState();
545 doRefreshProgress(R.id.progress, mProgress, false, false);
546 doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
547 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 }
549
550 /**
551 * @return The drawable currently used to draw the progress bar
552 */
553 Drawable getCurrentDrawable() {
554 return mCurrentDrawable;
555 }
556
557 @Override
558 protected boolean verifyDrawable(Drawable who) {
559 return who == mProgressDrawable || who == mIndeterminateDrawable
560 || super.verifyDrawable(who);
561 }
562
563 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -0700564 public void jumpDrawablesToCurrentState() {
565 super.jumpDrawablesToCurrentState();
566 if (mProgressDrawable != null) mProgressDrawable.jumpToCurrentState();
567 if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState();
568 }
569
Fabrice Di Meglio4457e852012-09-18 19:23:12 -0700570 /**
571 * @hide
572 */
Dianne Hackborne2136772010-11-04 15:08:59 -0700573 @Override
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700574 public void onResolveDrawables(int layoutDirection) {
575 final Drawable d = mCurrentDrawable;
576 if (d != null) {
577 d.setLayoutDirection(layoutDirection);
578 }
579 if (mIndeterminateDrawable != null) {
580 mIndeterminateDrawable.setLayoutDirection(layoutDirection);
581 }
582 if (mProgressDrawable != null) {
583 mProgressDrawable.setLayoutDirection(layoutDirection);
584 }
585 }
586
587 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 public void postInvalidate() {
589 if (!mNoInvalidate) {
590 super.postInvalidate();
591 }
592 }
593
594 private class RefreshProgressRunnable implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 public void run() {
Adam Powella0506632012-04-10 17:19:20 -0700596 synchronized (ProgressBar.this) {
597 final int count = mRefreshData.size();
598 for (int i = 0; i < count; i++) {
599 final RefreshData rd = mRefreshData.get(i);
600 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
601 rd.recycle();
602 }
603 mRefreshData.clear();
604 mRefreshIsPosted = false;
605 }
606 }
607 }
608
Svetoslav Ganovabae2a12012-11-27 16:59:37 -0800609 private static class RefreshData {
610 private static final int POOL_MAX = 24;
611 private static final SynchronizedPool<RefreshData> sPool =
612 new SynchronizedPool<RefreshData>(POOL_MAX);
613
Adam Powella0506632012-04-10 17:19:20 -0700614 public int id;
615 public int progress;
616 public boolean fromUser;
Adam Powella0506632012-04-10 17:19:20 -0700617
618 public static RefreshData obtain(int id, int progress, boolean fromUser) {
619 RefreshData rd = sPool.acquire();
Svetoslav Ganovabae2a12012-11-27 16:59:37 -0800620 if (rd == null) {
621 rd = new RefreshData();
622 }
Adam Powella0506632012-04-10 17:19:20 -0700623 rd.id = id;
624 rd.progress = progress;
625 rd.fromUser = fromUser;
626 return rd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 }
628
Adam Powella0506632012-04-10 17:19:20 -0700629 public void recycle() {
630 sPool.release(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 }
Svetoslav Ganovabae2a12012-11-27 16:59:37 -0800633
Joe Onoratoaa072632010-12-08 15:31:28 -0800634 private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
635 boolean callBackToApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
637 final Drawable d = mCurrentDrawable;
638 if (d != null) {
639 Drawable progressDrawable = null;
640
641 if (d instanceof LayerDrawable) {
642 progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700643 if (progressDrawable != null && canResolveLayoutDirection()) {
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700644 progressDrawable.setLayoutDirection(getLayoutDirection());
Fabrice Di Meglio0af4b8b2012-06-11 18:30:05 -0700645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 }
647
648 final int level = (int) (scale * MAX_LEVEL);
649 (progressDrawable != null ? progressDrawable : d).setLevel(level);
650 } else {
651 invalidate();
652 }
653
Joe Onoratoaa072632010-12-08 15:31:28 -0800654 if (callBackToApp && id == R.id.progress) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 onProgressRefresh(scale, fromUser);
656 }
657 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700658
659 void onProgressRefresh(float scale, boolean fromUser) {
660 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
661 scheduleAccessibilityEventSender();
662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 }
664
665 private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
666 if (mUiThreadId == Thread.currentThread().getId()) {
Joe Onoratoaa072632010-12-08 15:31:28 -0800667 doRefreshProgress(id, progress, fromUser, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700669 if (mRefreshProgressRunnable == null) {
670 mRefreshProgressRunnable = new RefreshProgressRunnable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 }
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700672
Adam Powella0506632012-04-10 17:19:20 -0700673 final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
674 mRefreshData.add(rd);
675 if (mAttached && !mRefreshIsPosted) {
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700676 post(mRefreshProgressRunnable);
Adam Powella0506632012-04-10 17:19:20 -0700677 mRefreshIsPosted = true;
678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 }
680 }
681
682 /**
683 * <p>Set the current progress to the specified value. Does not do anything
684 * if the progress bar is in indeterminate mode.</p>
685 *
686 * @param progress the new progress, between 0 and {@link #getMax()}
687 *
688 * @see #setIndeterminate(boolean)
689 * @see #isIndeterminate()
690 * @see #getProgress()
691 * @see #incrementProgressBy(int)
692 */
693 @android.view.RemotableViewMethod
694 public synchronized void setProgress(int progress) {
695 setProgress(progress, false);
696 }
697
698 @android.view.RemotableViewMethod
699 synchronized void setProgress(int progress, boolean fromUser) {
700 if (mIndeterminate) {
701 return;
702 }
703
704 if (progress < 0) {
705 progress = 0;
706 }
707
708 if (progress > mMax) {
709 progress = mMax;
710 }
711
712 if (progress != mProgress) {
713 mProgress = progress;
714 refreshProgress(R.id.progress, mProgress, fromUser);
715 }
716 }
717
718 /**
719 * <p>
720 * Set the current secondary progress to the specified value. Does not do
721 * anything if the progress bar is in indeterminate mode.
722 * </p>
723 *
724 * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
725 * @see #setIndeterminate(boolean)
726 * @see #isIndeterminate()
727 * @see #getSecondaryProgress()
728 * @see #incrementSecondaryProgressBy(int)
729 */
730 @android.view.RemotableViewMethod
731 public synchronized void setSecondaryProgress(int secondaryProgress) {
732 if (mIndeterminate) {
733 return;
734 }
735
736 if (secondaryProgress < 0) {
737 secondaryProgress = 0;
738 }
739
740 if (secondaryProgress > mMax) {
741 secondaryProgress = mMax;
742 }
743
744 if (secondaryProgress != mSecondaryProgress) {
745 mSecondaryProgress = secondaryProgress;
746 refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false);
747 }
748 }
749
750 /**
751 * <p>Get the progress bar's current level of progress. Return 0 when the
752 * progress bar is in indeterminate mode.</p>
753 *
754 * @return the current progress, between 0 and {@link #getMax()}
755 *
756 * @see #setIndeterminate(boolean)
757 * @see #isIndeterminate()
758 * @see #setProgress(int)
759 * @see #setMax(int)
760 * @see #getMax()
761 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700762 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 public synchronized int getProgress() {
764 return mIndeterminate ? 0 : mProgress;
765 }
766
767 /**
768 * <p>Get the progress bar's current level of secondary progress. Return 0 when the
769 * progress bar is in indeterminate mode.</p>
770 *
771 * @return the current secondary progress, between 0 and {@link #getMax()}
772 *
773 * @see #setIndeterminate(boolean)
774 * @see #isIndeterminate()
775 * @see #setSecondaryProgress(int)
776 * @see #setMax(int)
777 * @see #getMax()
778 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700779 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 public synchronized int getSecondaryProgress() {
781 return mIndeterminate ? 0 : mSecondaryProgress;
782 }
783
784 /**
785 * <p>Return the upper limit of this progress bar's range.</p>
786 *
787 * @return a positive integer
788 *
789 * @see #setMax(int)
790 * @see #getProgress()
791 * @see #getSecondaryProgress()
792 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700793 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 public synchronized int getMax() {
795 return mMax;
796 }
797
798 /**
799 * <p>Set the range of the progress bar to 0...<tt>max</tt>.</p>
800 *
801 * @param max the upper range of this progress bar
802 *
803 * @see #getMax()
804 * @see #setProgress(int)
805 * @see #setSecondaryProgress(int)
806 */
807 @android.view.RemotableViewMethod
808 public synchronized void setMax(int max) {
809 if (max < 0) {
810 max = 0;
811 }
812 if (max != mMax) {
813 mMax = max;
814 postInvalidate();
815
816 if (mProgress > max) {
817 mProgress = max;
818 }
Michael Krehan58e38222011-02-17 20:04:27 -0800819 refreshProgress(R.id.progress, mProgress, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
821 }
822
823 /**
824 * <p>Increase the progress bar's progress by the specified amount.</p>
825 *
826 * @param diff the amount by which the progress must be increased
827 *
828 * @see #setProgress(int)
829 */
830 public synchronized final void incrementProgressBy(int diff) {
831 setProgress(mProgress + diff);
832 }
833
834 /**
835 * <p>Increase the progress bar's secondary progress by the specified amount.</p>
836 *
837 * @param diff the amount by which the secondary progress must be increased
838 *
839 * @see #setSecondaryProgress(int)
840 */
841 public synchronized final void incrementSecondaryProgressBy(int diff) {
842 setSecondaryProgress(mSecondaryProgress + diff);
843 }
844
845 /**
846 * <p>Start the indeterminate progress animation.</p>
847 */
848 void startAnimation() {
Romain Guya05e8a52010-02-25 14:32:39 -0800849 if (getVisibility() != VISIBLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 return;
851 }
852
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700853 if (mIndeterminateDrawable instanceof Animatable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 mShouldStartAnimationDrawable = true;
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700855 mHasAnimation = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700857 mHasAnimation = true;
858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 if (mInterpolator == null) {
860 mInterpolator = new LinearInterpolator();
861 }
862
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700863 if (mTransformation == null) {
864 mTransformation = new Transformation();
865 } else {
866 mTransformation.clear();
867 }
868
869 if (mAnimation == null) {
870 mAnimation = new AlphaAnimation(0.0f, 1.0f);
871 } else {
872 mAnimation.reset();
873 }
874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 mAnimation.setRepeatMode(mBehavior);
876 mAnimation.setRepeatCount(Animation.INFINITE);
877 mAnimation.setDuration(mDuration);
878 mAnimation.setInterpolator(mInterpolator);
879 mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 }
Evan Charlton08e14732010-06-07 10:38:53 -0700881 postInvalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 }
883
884 /**
885 * <p>Stop the indeterminate progress animation.</p>
886 */
887 void stopAnimation() {
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700888 mHasAnimation = false;
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700889 if (mIndeterminateDrawable instanceof Animatable) {
890 ((Animatable) mIndeterminateDrawable).stop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 mShouldStartAnimationDrawable = false;
892 }
Evan Charlton08e14732010-06-07 10:38:53 -0700893 postInvalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 }
895
896 /**
897 * Sets the acceleration curve for the indeterminate animation.
898 * The interpolator is loaded as a resource from the specified context.
899 *
900 * @param context The application environment
901 * @param resID The resource identifier of the interpolator to load
902 */
903 public void setInterpolator(Context context, int resID) {
904 setInterpolator(AnimationUtils.loadInterpolator(context, resID));
905 }
906
907 /**
908 * Sets the acceleration curve for the indeterminate animation.
909 * Defaults to a linear interpolation.
910 *
911 * @param interpolator The interpolator which defines the acceleration curve
912 */
913 public void setInterpolator(Interpolator interpolator) {
914 mInterpolator = interpolator;
915 }
916
917 /**
918 * Gets the acceleration curve type for the indeterminate animation.
919 *
920 * @return the {@link Interpolator} associated to this animation
921 */
922 public Interpolator getInterpolator() {
923 return mInterpolator;
924 }
925
926 @Override
Steve Howardb25ffff2010-08-20 17:39:26 -0700927 @RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928 public void setVisibility(int v) {
929 if (getVisibility() != v) {
930 super.setVisibility(v);
931
932 if (mIndeterminate) {
933 // let's be nice with the UI thread
934 if (v == GONE || v == INVISIBLE) {
935 stopAnimation();
Romain Guya05e8a52010-02-25 14:32:39 -0800936 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 startAnimation();
938 }
939 }
940 }
941 }
942
943 @Override
Romain Guya05e8a52010-02-25 14:32:39 -0800944 protected void onVisibilityChanged(View changedView, int visibility) {
945 super.onVisibilityChanged(changedView, visibility);
946
947 if (mIndeterminate) {
948 // let's be nice with the UI thread
949 if (visibility == GONE || visibility == INVISIBLE) {
950 stopAnimation();
951 } else {
952 startAnimation();
953 }
954 }
955 }
956
957 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 public void invalidateDrawable(Drawable dr) {
959 if (!mInDrawing) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700960 if (verifyDrawable(dr)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 final Rect dirty = dr.getBounds();
Chris Craik7546a4b2013-10-30 19:49:37 -0700962 final int scrollX = mScrollX + mPaddingLeft;
963 final int scrollY = mScrollY + mPaddingTop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964
Chris Craik7546a4b2013-10-30 19:49:37 -0700965 invalidate(dirty.left + scrollX, dirty.top + scrollY,
966 dirty.right + scrollX, dirty.bottom + scrollY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 } else {
968 super.invalidateDrawable(dr);
969 }
970 }
971 }
972
973 @Override
974 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Joe Onoratoaa072632010-12-08 15:31:28 -0800975 updateDrawableBounds(w, h);
976 }
977
978 private void updateDrawableBounds(int w, int h) {
Adam Powell6322af52012-08-08 15:59:12 -0700979 // onDraw will translate the canvas so we draw starting at 0,0.
980 // Subtract out padding for the purposes of the calculations below.
981 w -= mPaddingRight + mPaddingLeft;
982 h -= mPaddingTop + mPaddingBottom;
983
984 int right = w;
985 int bottom = h;
Adam Powella1b92c52011-09-02 15:05:15 -0700986 int top = 0;
987 int left = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988
989 if (mIndeterminateDrawable != null) {
Chet Haasea79803c2011-09-28 17:51:53 -0700990 // Aspect ratio logic does not apply to AnimationDrawables
991 if (mOnlyIndeterminate && !(mIndeterminateDrawable instanceof AnimationDrawable)) {
Adam Powella1b92c52011-09-02 15:05:15 -0700992 // Maintain aspect ratio. Certain kinds of animated drawables
993 // get very confused otherwise.
994 final int intrinsicWidth = mIndeterminateDrawable.getIntrinsicWidth();
995 final int intrinsicHeight = mIndeterminateDrawable.getIntrinsicHeight();
996 final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight;
997 final float boundAspect = (float) w / h;
998 if (intrinsicAspect != boundAspect) {
999 if (boundAspect > intrinsicAspect) {
1000 // New width is larger. Make it smaller to match height.
1001 final int width = (int) (h * intrinsicAspect);
1002 left = (w - width) / 2;
1003 right = left + width;
1004 } else {
1005 // New height is larger. Make it smaller to match width.
1006 final int height = (int) (w * (1 / intrinsicAspect));
1007 top = (h - height) / 2;
1008 bottom = top + height;
1009 }
1010 }
1011 }
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -08001012 if (isLayoutRtl() && mMirrorForRtl) {
Fabrice Di Meglio7fb98b32012-09-12 20:04:04 -07001013 int tempLeft = left;
1014 left = w - right;
1015 right = w - tempLeft;
1016 }
Adam Powella1b92c52011-09-02 15:05:15 -07001017 mIndeterminateDrawable.setBounds(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 }
1019
1020 if (mProgressDrawable != null) {
1021 mProgressDrawable.setBounds(0, 0, right, bottom);
1022 }
1023 }
1024
1025 @Override
1026 protected synchronized void onDraw(Canvas canvas) {
1027 super.onDraw(canvas);
1028
1029 Drawable d = mCurrentDrawable;
1030 if (d != null) {
1031 // Translate canvas so a indeterminate circular progress bar with padding
1032 // rotates properly in its animation
1033 canvas.save();
Fabrice Di Meglio2b378cd2013-01-30 16:39:33 -08001034 if(isLayoutRtl() && mMirrorForRtl) {
Fabrice Di Meglio7fb98b32012-09-12 20:04:04 -07001035 canvas.translate(getWidth() - mPaddingRight, mPaddingTop);
1036 canvas.scale(-1.0f, 1.0f);
1037 } else {
1038 canvas.translate(mPaddingLeft, mPaddingTop);
1039 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 long time = getDrawingTime();
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001041 if (mHasAnimation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 mAnimation.getTransformation(time, mTransformation);
1043 float scale = mTransformation.getAlpha();
1044 try {
1045 mInDrawing = true;
1046 d.setLevel((int) (scale * MAX_LEVEL));
1047 } finally {
1048 mInDrawing = false;
1049 }
Jeff Brown6cb7b462012-03-05 13:21:17 -08001050 postInvalidateOnAnimation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 }
1052 d.draw(canvas);
1053 canvas.restore();
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001054 if (mShouldStartAnimationDrawable && d instanceof Animatable) {
1055 ((Animatable) d).start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056 mShouldStartAnimationDrawable = false;
1057 }
1058 }
1059 }
1060
1061 @Override
1062 protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1063 Drawable d = mCurrentDrawable;
1064
1065 int dw = 0;
1066 int dh = 0;
1067 if (d != null) {
1068 dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
1069 dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
1070 }
Joe Onoratoaa072632010-12-08 15:31:28 -08001071 updateDrawableState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 dw += mPaddingLeft + mPaddingRight;
1073 dh += mPaddingTop + mPaddingBottom;
1074
Dianne Hackborn189ee182010-12-02 21:48:53 -08001075 setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
1076 resolveSizeAndState(dh, heightMeasureSpec, 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
1078
1079 @Override
1080 protected void drawableStateChanged() {
1081 super.drawableStateChanged();
Joe Onoratoaa072632010-12-08 15:31:28 -08001082 updateDrawableState();
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084
Joe Onoratoaa072632010-12-08 15:31:28 -08001085 private void updateDrawableState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 int[] state = getDrawableState();
1087
1088 if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
1089 mProgressDrawable.setState(state);
1090 }
1091
1092 if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
1093 mIndeterminateDrawable.setState(state);
1094 }
1095 }
1096
1097 static class SavedState extends BaseSavedState {
1098 int progress;
1099 int secondaryProgress;
1100
1101 /**
1102 * Constructor called from {@link ProgressBar#onSaveInstanceState()}
1103 */
1104 SavedState(Parcelable superState) {
1105 super(superState);
1106 }
1107
1108 /**
1109 * Constructor called from {@link #CREATOR}
1110 */
1111 private SavedState(Parcel in) {
1112 super(in);
1113 progress = in.readInt();
1114 secondaryProgress = in.readInt();
1115 }
1116
1117 @Override
1118 public void writeToParcel(Parcel out, int flags) {
1119 super.writeToParcel(out, flags);
1120 out.writeInt(progress);
1121 out.writeInt(secondaryProgress);
1122 }
1123
1124 public static final Parcelable.Creator<SavedState> CREATOR
1125 = new Parcelable.Creator<SavedState>() {
1126 public SavedState createFromParcel(Parcel in) {
1127 return new SavedState(in);
1128 }
1129
1130 public SavedState[] newArray(int size) {
1131 return new SavedState[size];
1132 }
1133 };
1134 }
1135
1136 @Override
1137 public Parcelable onSaveInstanceState() {
1138 // Force our ancestor class to save its state
1139 Parcelable superState = super.onSaveInstanceState();
1140 SavedState ss = new SavedState(superState);
1141
1142 ss.progress = mProgress;
1143 ss.secondaryProgress = mSecondaryProgress;
1144
1145 return ss;
1146 }
1147
1148 @Override
1149 public void onRestoreInstanceState(Parcelable state) {
1150 SavedState ss = (SavedState) state;
1151 super.onRestoreInstanceState(ss.getSuperState());
1152
1153 setProgress(ss.progress);
1154 setSecondaryProgress(ss.secondaryProgress);
1155 }
David Sobreira Marques52a35432010-05-15 16:10:18 -03001156
1157 @Override
1158 protected void onAttachedToWindow() {
1159 super.onAttachedToWindow();
1160 if (mIndeterminate) {
1161 startAnimation();
1162 }
Adam Powella0506632012-04-10 17:19:20 -07001163 if (mRefreshData != null) {
1164 synchronized (this) {
1165 final int count = mRefreshData.size();
1166 for (int i = 0; i < count; i++) {
1167 final RefreshData rd = mRefreshData.get(i);
1168 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
1169 rd.recycle();
1170 }
1171 mRefreshData.clear();
1172 }
1173 }
1174 mAttached = true;
David Sobreira Marques52a35432010-05-15 16:10:18 -03001175 }
1176
1177 @Override
1178 protected void onDetachedFromWindow() {
David Sobreira Marques52a35432010-05-15 16:10:18 -03001179 if (mIndeterminate) {
1180 stopAnimation();
1181 }
Adam Powella0506632012-04-10 17:19:20 -07001182 if (mRefreshProgressRunnable != null) {
1183 removeCallbacks(mRefreshProgressRunnable);
1184 }
1185 if (mRefreshProgressRunnable != null && mRefreshIsPosted) {
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001186 removeCallbacks(mRefreshProgressRunnable);
1187 }
1188 if (mAccessibilityEventSender != null) {
1189 removeCallbacks(mAccessibilityEventSender);
1190 }
Patrick Dubroyec84c3a2011-01-13 17:55:37 -08001191 // This should come after stopAnimation(), otherwise an invalidate message remains in the
1192 // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
1193 super.onDetachedFromWindow();
Adam Powella0506632012-04-10 17:19:20 -07001194 mAttached = false;
David Sobreira Marques52a35432010-05-15 16:10:18 -03001195 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001196
1197 @Override
Svetoslav Ganov30401322011-05-12 18:53:45 -07001198 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1199 super.onInitializeAccessibilityEvent(event);
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001200 event.setClassName(ProgressBar.class.getName());
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001201 event.setItemCount(mMax);
1202 event.setCurrentItemIndex(mProgress);
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001203 }
1204
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001205 @Override
1206 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1207 super.onInitializeAccessibilityNodeInfo(info);
1208 info.setClassName(ProgressBar.class.getName());
1209 }
1210
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001211 /**
1212 * Schedule a command for sending an accessibility event.
1213 * </br>
1214 * Note: A command is used to ensure that accessibility events
1215 * are sent at most one in a given time frame to save
1216 * system resources while the progress changes quickly.
1217 */
1218 private void scheduleAccessibilityEventSender() {
1219 if (mAccessibilityEventSender == null) {
1220 mAccessibilityEventSender = new AccessibilityEventSender();
1221 } else {
1222 removeCallbacks(mAccessibilityEventSender);
1223 }
1224 postDelayed(mAccessibilityEventSender, TIMEOUT_SEND_ACCESSIBILITY_EVENT);
1225 }
1226
1227 /**
1228 * Command for sending an accessibility event.
1229 */
1230 private class AccessibilityEventSender implements Runnable {
1231 public void run() {
1232 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
1233 }
1234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235}