blob: a28e9ff26f826309b1473fb10b9546baf622d210 [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;
Adam Powella0506632012-04-10 17:19:20 -070041import android.util.Pool;
42import android.util.Poolable;
43import android.util.PoolableManager;
44import android.util.Pools;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.view.Gravity;
Steve Howardb25ffff2010-08-20 17:39:26 -070046import android.view.RemotableViewMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.view.View;
Steve Zeigler7a367882010-02-23 16:39:08 -080048import android.view.ViewDebug;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -070049import android.view.accessibility.AccessibilityEvent;
50import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080051import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.view.animation.AlphaAnimation;
53import android.view.animation.Animation;
54import android.view.animation.AnimationUtils;
55import android.view.animation.Interpolator;
56import android.view.animation.LinearInterpolator;
57import android.view.animation.Transformation;
58import android.widget.RemoteViews.RemoteView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
Adam Powella0506632012-04-10 17:19:20 -070060import java.util.ArrayList;
61
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
63/**
64 * <p>
65 * Visual indicator of progress in some operation. Displays a bar to the user
66 * representing how far the operation has progressed; the application can
67 * change the amount of progress (modifying the length of the bar) as it moves
68 * forward. There is also a secondary progress displayable on a progress bar
69 * which is useful for displaying intermediate progress, such as the buffer
70 * level during a streaming playback progress bar.
71 * </p>
72 *
73 * <p>
74 * A progress bar can also be made indeterminate. In indeterminate mode, the
Scott Main42f139c2011-04-29 10:31:10 -070075 * progress bar shows a cyclic animation without an indication of progress. This mode is used by
76 * applications when the length of the task is unknown. The indeterminate progress bar can be either
77 * a spinning wheel or a horizontal bar.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 * </p>
79 *
80 * <p>The following code example shows how a progress bar can be used from
81 * a worker thread to update the user interface to notify the user of progress:
82 * </p>
83 *
Scott Main42f139c2011-04-29 10:31:10 -070084 * <pre>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 * public class MyActivity extends Activity {
86 * private static final int PROGRESS = 0x1;
87 *
88 * private ProgressBar mProgress;
89 * private int mProgressStatus = 0;
90 *
91 * private Handler mHandler = new Handler();
92 *
93 * protected void onCreate(Bundle icicle) {
94 * super.onCreate(icicle);
95 *
96 * setContentView(R.layout.progressbar_activity);
97 *
98 * mProgress = (ProgressBar) findViewById(R.id.progress_bar);
99 *
100 * // Start lengthy operation in a background thread
101 * new Thread(new Runnable() {
102 * public void run() {
Scott Main42f139c2011-04-29 10:31:10 -0700103 * while (mProgressStatus &lt; 100) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 * mProgressStatus = doWork();
105 *
106 * // Update the progress bar
107 * mHandler.post(new Runnable() {
108 * public void run() {
109 * mProgress.setProgress(mProgressStatus);
110 * }
111 * });
112 * }
113 * }
114 * }).start();
115 * }
Scott Main42f139c2011-04-29 10:31:10 -0700116 * }</pre>
117 *
118 * <p>To add a progress bar to a layout file, you can use the {@code &lt;ProgressBar&gt;} element.
119 * By default, the progress bar is a spinning wheel (an indeterminate indicator). To change to a
120 * horizontal progress bar, apply the {@link android.R.style#Widget_ProgressBar_Horizontal
121 * Widget.ProgressBar.Horizontal} style, like so:</p>
122 *
123 * <pre>
124 * &lt;ProgressBar
125 * style="@android:style/Widget.ProgressBar.Horizontal"
126 * ... /&gt;</pre>
127 *
128 * <p>If you will use the progress bar to show real progress, you must use the horizontal bar. You
129 * can then increment the progress with {@link #incrementProgressBy incrementProgressBy()} or
130 * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If
131 * necessary, you can adjust the maximum value (the value for a full bar) using the {@link
132 * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed
133 * below.</p>
134 *
135 * <p>Another common style to apply to the progress bar is {@link
136 * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller
137 * version of the spinning wheel&mdash;useful when waiting for content to load.
138 * For example, you can insert this kind of progress bar into your default layout for
139 * a view that will be populated by some content fetched from the Internet&mdash;the spinning wheel
140 * appears immediately and when your application receives the content, it replaces the progress bar
141 * with the loaded content. For example:</p>
142 *
143 * <pre>
144 * &lt;LinearLayout
145 * android:orientation="horizontal"
146 * ... &gt;
147 * &lt;ProgressBar
148 * android:layout_width="wrap_content"
149 * android:layout_height="wrap_content"
150 * style="@android:style/Widget.ProgressBar.Small"
151 * android:layout_marginRight="5dp" /&gt;
152 * &lt;TextView
153 * android:layout_width="wrap_content"
154 * android:layout_height="wrap_content"
155 * android:text="@string/loading" /&gt;
156 * &lt;/LinearLayout&gt;</pre>
157 *
158 * <p>Other progress bar styles provided by the system include:</p>
159 * <ul>
160 * <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li>
161 * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li>
162 * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li>
163 * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li>
164 * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse
165 * Widget.ProgressBar.Small.Inverse}</li>
166 * <li>{@link android.R.style#Widget_ProgressBar_Large_Inverse
167 * Widget.ProgressBar.Large.Inverse}</li>
168 * </ul>
169 * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
170 * if your application uses a light colored theme (a white background).</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 *
172 * <p><strong>XML attributes</b></strong>
173 * <p>
174 * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
175 * {@link android.R.styleable#View View Attributes}
176 * </p>
177 *
Scott Main42f139c2011-04-29 10:31:10 -0700178 * @attr ref android.R.styleable#ProgressBar_animationResolution
179 * @attr ref android.R.styleable#ProgressBar_indeterminate
180 * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
181 * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
182 * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
183 * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
184 * @attr ref android.R.styleable#ProgressBar_interpolator
185 * @attr ref android.R.styleable#ProgressBar_max
186 * @attr ref android.R.styleable#ProgressBar_maxHeight
187 * @attr ref android.R.styleable#ProgressBar_maxWidth
188 * @attr ref android.R.styleable#ProgressBar_minHeight
189 * @attr ref android.R.styleable#ProgressBar_minWidth
190 * @attr ref android.R.styleable#ProgressBar_progress
191 * @attr ref android.R.styleable#ProgressBar_progressDrawable
192 * @attr ref android.R.styleable#ProgressBar_secondaryProgress
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 */
194@RemoteView
195public class ProgressBar extends View {
196 private static final int MAX_LEVEL = 10000;
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700197 private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198
199 int mMinWidth;
200 int mMaxWidth;
201 int mMinHeight;
202 int mMaxHeight;
203
204 private int mProgress;
205 private int mSecondaryProgress;
206 private int mMax;
207
208 private int mBehavior;
209 private int mDuration;
210 private boolean mIndeterminate;
211 private boolean mOnlyIndeterminate;
212 private Transformation mTransformation;
213 private AlphaAnimation mAnimation;
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700214 private boolean mHasAnimation;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 private Drawable mIndeterminateDrawable;
216 private Drawable mProgressDrawable;
217 private Drawable mCurrentDrawable;
218 Bitmap mSampleTile;
219 private boolean mNoInvalidate;
220 private Interpolator mInterpolator;
221 private RefreshProgressRunnable mRefreshProgressRunnable;
222 private long mUiThreadId;
223 private boolean mShouldStartAnimationDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224
225 private boolean mInDrawing;
Adam Powella0506632012-04-10 17:19:20 -0700226 private boolean mAttached;
227 private boolean mRefreshIsPosted;
228
229 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
308 a.recycle();
309 }
310
311 /**
312 * Converts a drawable to a tiled version of itself. It will recursively
313 * traverse layer and state list drawables.
314 */
315 private Drawable tileify(Drawable drawable, boolean clip) {
316
317 if (drawable instanceof LayerDrawable) {
318 LayerDrawable background = (LayerDrawable) drawable;
319 final int N = background.getNumberOfLayers();
320 Drawable[] outDrawables = new Drawable[N];
321
322 for (int i = 0; i < N; i++) {
323 int id = background.getId(i);
324 outDrawables[i] = tileify(background.getDrawable(i),
325 (id == R.id.progress || id == R.id.secondaryProgress));
326 }
327
328 LayerDrawable newBg = new LayerDrawable(outDrawables);
329
330 for (int i = 0; i < N; i++) {
331 newBg.setId(i, background.getId(i));
332 }
333
334 return newBg;
335
336 } else if (drawable instanceof StateListDrawable) {
337 StateListDrawable in = (StateListDrawable) drawable;
338 StateListDrawable out = new StateListDrawable();
339 int numStates = in.getStateCount();
340 for (int i = 0; i < numStates; i++) {
341 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
342 }
343 return out;
344
345 } else if (drawable instanceof BitmapDrawable) {
346 final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
347 if (mSampleTile == null) {
348 mSampleTile = tileBitmap;
349 }
350
351 final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
352
353 final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
354 Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
355 shapeDrawable.getPaint().setShader(bitmapShader);
356
Fabrice Di Meglioaac0d4e2012-07-19 19:21:26 -0700357 return (clip) ? new ClipDrawable(shapeDrawable, Gravity.START,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 ClipDrawable.HORIZONTAL) : shapeDrawable;
359 }
360
361 return drawable;
362 }
363
364 Shape getDrawableShape() {
365 final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
366 return new RoundRectShape(roundedCorners, null, null);
367 }
368
369 /**
370 * Convert a AnimationDrawable for use as a barberpole animation.
371 * Each frame of the animation is wrapped in a ClipDrawable and
372 * given a tiling BitmapShader.
373 */
374 private Drawable tileifyIndeterminate(Drawable drawable) {
375 if (drawable instanceof AnimationDrawable) {
376 AnimationDrawable background = (AnimationDrawable) drawable;
377 final int N = background.getNumberOfFrames();
378 AnimationDrawable newBg = new AnimationDrawable();
379 newBg.setOneShot(background.isOneShot());
380
381 for (int i = 0; i < N; i++) {
382 Drawable frame = tileify(background.getFrame(i), true);
383 frame.setLevel(10000);
384 newBg.addFrame(frame, background.getDuration(i));
385 }
386 newBg.setLevel(10000);
387 drawable = newBg;
388 }
389 return drawable;
390 }
391
392 /**
393 * <p>
394 * Initialize the progress bar's default values:
395 * </p>
396 * <ul>
397 * <li>progress = 0</li>
398 * <li>max = 100</li>
399 * <li>animation duration = 4000 ms</li>
400 * <li>indeterminate = false</li>
401 * <li>behavior = repeat</li>
402 * </ul>
403 */
404 private void initProgressBar() {
405 mMax = 100;
406 mProgress = 0;
407 mSecondaryProgress = 0;
408 mIndeterminate = false;
409 mOnlyIndeterminate = false;
410 mDuration = 4000;
411 mBehavior = AlphaAnimation.RESTART;
412 mMinWidth = 24;
413 mMaxWidth = 48;
414 mMinHeight = 24;
415 mMaxHeight = 48;
416 }
417
418 /**
419 * <p>Indicate whether this progress bar is in indeterminate mode.</p>
420 *
421 * @return true if the progress bar is in indeterminate mode
422 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700423 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 public synchronized boolean isIndeterminate() {
425 return mIndeterminate;
426 }
427
428 /**
429 * <p>Change the indeterminate mode for this progress bar. In indeterminate
430 * mode, the progress is ignored and the progress bar shows an infinite
431 * animation instead.</p>
432 *
433 * If this progress bar's style only supports indeterminate mode (such as the circular
434 * progress bars), then this will be ignored.
435 *
436 * @param indeterminate true to enable the indeterminate mode
437 */
438 @android.view.RemotableViewMethod
439 public synchronized void setIndeterminate(boolean indeterminate) {
440 if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
441 mIndeterminate = indeterminate;
442
443 if (indeterminate) {
444 // swap between indeterminate and regular backgrounds
445 mCurrentDrawable = mIndeterminateDrawable;
446 startAnimation();
447 } else {
448 mCurrentDrawable = mProgressDrawable;
449 stopAnimation();
450 }
451 }
452 }
453
454 /**
455 * <p>Get the drawable used to draw the progress bar in
456 * indeterminate mode.</p>
457 *
458 * @return a {@link android.graphics.drawable.Drawable} instance
459 *
460 * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable)
461 * @see #setIndeterminate(boolean)
462 */
463 public Drawable getIndeterminateDrawable() {
464 return mIndeterminateDrawable;
465 }
466
467 /**
468 * <p>Define the drawable used to draw the progress bar in
469 * indeterminate mode.</p>
470 *
471 * @param d the new drawable
472 *
473 * @see #getIndeterminateDrawable()
474 * @see #setIndeterminate(boolean)
475 */
476 public void setIndeterminateDrawable(Drawable d) {
477 if (d != null) {
478 d.setCallback(this);
479 }
480 mIndeterminateDrawable = d;
Fabrice Di Megliob03b4342012-06-04 12:55:30 -0700481 if (mIndeterminateDrawable != null) {
482 mIndeterminateDrawable.setLayoutDirection(getLayoutDirection());
483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 if (mIndeterminate) {
485 mCurrentDrawable = d;
486 postInvalidate();
487 }
488 }
489
490 /**
491 * <p>Get the drawable used to draw the progress bar in
492 * progress mode.</p>
493 *
494 * @return a {@link android.graphics.drawable.Drawable} instance
495 *
496 * @see #setProgressDrawable(android.graphics.drawable.Drawable)
497 * @see #setIndeterminate(boolean)
498 */
499 public Drawable getProgressDrawable() {
500 return mProgressDrawable;
501 }
502
503 /**
504 * <p>Define the drawable used to draw the progress bar in
505 * progress mode.</p>
506 *
507 * @param d the new drawable
508 *
509 * @see #getProgressDrawable()
510 * @see #setIndeterminate(boolean)
511 */
512 public void setProgressDrawable(Drawable d) {
Joe Onoratoaa072632010-12-08 15:31:28 -0800513 boolean needUpdate;
514 if (mProgressDrawable != null && d != mProgressDrawable) {
515 mProgressDrawable.setCallback(null);
516 needUpdate = true;
517 } else {
518 needUpdate = false;
519 }
520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 if (d != null) {
522 d.setCallback(this);
Fabrice Di Megliob03b4342012-06-04 12:55:30 -0700523 d.setLayoutDirection(getLayoutDirection());
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500524
Romain Guy8d21bdb2009-12-30 13:54:04 -0800525 // Make sure the ProgressBar is always tall enough
526 int drawableHeight = d.getMinimumHeight();
NoraBoraa7f7e2a2009-12-25 19:51:34 -0500527 if (mMaxHeight < drawableHeight) {
528 mMaxHeight = drawableHeight;
529 requestLayout();
530 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 }
532 mProgressDrawable = d;
533 if (!mIndeterminate) {
534 mCurrentDrawable = d;
535 postInvalidate();
536 }
Joe Onoratoaa072632010-12-08 15:31:28 -0800537
538 if (needUpdate) {
539 updateDrawableBounds(getWidth(), getHeight());
540 updateDrawableState();
541 doRefreshProgress(R.id.progress, mProgress, false, false);
542 doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 }
545
546 /**
547 * @return The drawable currently used to draw the progress bar
548 */
549 Drawable getCurrentDrawable() {
550 return mCurrentDrawable;
551 }
552
553 @Override
554 protected boolean verifyDrawable(Drawable who) {
555 return who == mProgressDrawable || who == mIndeterminateDrawable
556 || super.verifyDrawable(who);
557 }
558
559 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -0700560 public void jumpDrawablesToCurrentState() {
561 super.jumpDrawablesToCurrentState();
562 if (mProgressDrawable != null) mProgressDrawable.jumpToCurrentState();
563 if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState();
564 }
565
566 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 public void postInvalidate() {
568 if (!mNoInvalidate) {
569 super.postInvalidate();
570 }
571 }
572
573 private class RefreshProgressRunnable implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 public void run() {
Adam Powella0506632012-04-10 17:19:20 -0700575 synchronized (ProgressBar.this) {
576 final int count = mRefreshData.size();
577 for (int i = 0; i < count; i++) {
578 final RefreshData rd = mRefreshData.get(i);
579 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
580 rd.recycle();
581 }
582 mRefreshData.clear();
583 mRefreshIsPosted = false;
584 }
585 }
586 }
587
588 private static class RefreshData implements Poolable<RefreshData> {
589 public int id;
590 public int progress;
591 public boolean fromUser;
592
593 private RefreshData mNext;
594 private boolean mIsPooled;
595
596 private static final int POOL_MAX = 24;
597 private static final Pool<RefreshData> sPool = Pools.synchronizedPool(
598 Pools.finitePool(new PoolableManager<RefreshData>() {
599 @Override
600 public RefreshData newInstance() {
601 return new RefreshData();
602 }
603
604 @Override
605 public void onAcquired(RefreshData element) {
606 }
607
608 @Override
609 public void onReleased(RefreshData element) {
610 }
611 }, POOL_MAX));
612
613 public static RefreshData obtain(int id, int progress, boolean fromUser) {
614 RefreshData rd = sPool.acquire();
615 rd.id = id;
616 rd.progress = progress;
617 rd.fromUser = fromUser;
618 return rd;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 }
620
Adam Powella0506632012-04-10 17:19:20 -0700621 public void recycle() {
622 sPool.release(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 }
Adam Powella0506632012-04-10 17:19:20 -0700624
625 @Override
626 public void setNextPoolable(RefreshData element) {
627 mNext = element;
628 }
629
630 @Override
631 public RefreshData getNextPoolable() {
632 return mNext;
633 }
634
635 @Override
636 public boolean isPooled() {
637 return mIsPooled;
638 }
639
640 @Override
641 public void setPooled(boolean isPooled) {
642 mIsPooled = isPooled;
643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 }
645
Joe Onoratoaa072632010-12-08 15:31:28 -0800646 private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
647 boolean callBackToApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
649 final Drawable d = mCurrentDrawable;
650 if (d != null) {
651 Drawable progressDrawable = null;
652
653 if (d instanceof LayerDrawable) {
654 progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
655 }
656
657 final int level = (int) (scale * MAX_LEVEL);
658 (progressDrawable != null ? progressDrawable : d).setLevel(level);
659 } else {
660 invalidate();
661 }
662
Joe Onoratoaa072632010-12-08 15:31:28 -0800663 if (callBackToApp && id == R.id.progress) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 onProgressRefresh(scale, fromUser);
665 }
666 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -0700667
668 void onProgressRefresh(float scale, boolean fromUser) {
669 if (AccessibilityManager.getInstance(mContext).isEnabled()) {
670 scheduleAccessibilityEventSender();
671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 }
673
674 private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
675 if (mUiThreadId == Thread.currentThread().getId()) {
Joe Onoratoaa072632010-12-08 15:31:28 -0800676 doRefreshProgress(id, progress, fromUser, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700678 if (mRefreshProgressRunnable == null) {
679 mRefreshProgressRunnable = new RefreshProgressRunnable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 }
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700681
Adam Powella0506632012-04-10 17:19:20 -0700682 final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
683 mRefreshData.add(rd);
684 if (mAttached && !mRefreshIsPosted) {
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700685 post(mRefreshProgressRunnable);
Adam Powella0506632012-04-10 17:19:20 -0700686 mRefreshIsPosted = true;
687 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
689 }
690
691 /**
692 * <p>Set the current progress to the specified value. Does not do anything
693 * if the progress bar is in indeterminate mode.</p>
694 *
695 * @param progress the new progress, between 0 and {@link #getMax()}
696 *
697 * @see #setIndeterminate(boolean)
698 * @see #isIndeterminate()
699 * @see #getProgress()
700 * @see #incrementProgressBy(int)
701 */
702 @android.view.RemotableViewMethod
703 public synchronized void setProgress(int progress) {
704 setProgress(progress, false);
705 }
706
707 @android.view.RemotableViewMethod
708 synchronized void setProgress(int progress, boolean fromUser) {
709 if (mIndeterminate) {
710 return;
711 }
712
713 if (progress < 0) {
714 progress = 0;
715 }
716
717 if (progress > mMax) {
718 progress = mMax;
719 }
720
721 if (progress != mProgress) {
722 mProgress = progress;
723 refreshProgress(R.id.progress, mProgress, fromUser);
724 }
725 }
726
727 /**
728 * <p>
729 * Set the current secondary progress to the specified value. Does not do
730 * anything if the progress bar is in indeterminate mode.
731 * </p>
732 *
733 * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
734 * @see #setIndeterminate(boolean)
735 * @see #isIndeterminate()
736 * @see #getSecondaryProgress()
737 * @see #incrementSecondaryProgressBy(int)
738 */
739 @android.view.RemotableViewMethod
740 public synchronized void setSecondaryProgress(int secondaryProgress) {
741 if (mIndeterminate) {
742 return;
743 }
744
745 if (secondaryProgress < 0) {
746 secondaryProgress = 0;
747 }
748
749 if (secondaryProgress > mMax) {
750 secondaryProgress = mMax;
751 }
752
753 if (secondaryProgress != mSecondaryProgress) {
754 mSecondaryProgress = secondaryProgress;
755 refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false);
756 }
757 }
758
759 /**
760 * <p>Get the progress bar's current level of progress. Return 0 when the
761 * progress bar is in indeterminate mode.</p>
762 *
763 * @return the current progress, between 0 and {@link #getMax()}
764 *
765 * @see #setIndeterminate(boolean)
766 * @see #isIndeterminate()
767 * @see #setProgress(int)
768 * @see #setMax(int)
769 * @see #getMax()
770 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700771 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800772 public synchronized int getProgress() {
773 return mIndeterminate ? 0 : mProgress;
774 }
775
776 /**
777 * <p>Get the progress bar's current level of secondary progress. Return 0 when the
778 * progress bar is in indeterminate mode.</p>
779 *
780 * @return the current secondary progress, between 0 and {@link #getMax()}
781 *
782 * @see #setIndeterminate(boolean)
783 * @see #isIndeterminate()
784 * @see #setSecondaryProgress(int)
785 * @see #setMax(int)
786 * @see #getMax()
787 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700788 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 public synchronized int getSecondaryProgress() {
790 return mIndeterminate ? 0 : mSecondaryProgress;
791 }
792
793 /**
794 * <p>Return the upper limit of this progress bar's range.</p>
795 *
796 * @return a positive integer
797 *
798 * @see #setMax(int)
799 * @see #getProgress()
800 * @see #getSecondaryProgress()
801 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700802 @ViewDebug.ExportedProperty(category = "progress")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 public synchronized int getMax() {
804 return mMax;
805 }
806
807 /**
808 * <p>Set the range of the progress bar to 0...<tt>max</tt>.</p>
809 *
810 * @param max the upper range of this progress bar
811 *
812 * @see #getMax()
813 * @see #setProgress(int)
814 * @see #setSecondaryProgress(int)
815 */
816 @android.view.RemotableViewMethod
817 public synchronized void setMax(int max) {
818 if (max < 0) {
819 max = 0;
820 }
821 if (max != mMax) {
822 mMax = max;
823 postInvalidate();
824
825 if (mProgress > max) {
826 mProgress = max;
827 }
Michael Krehan58e38222011-02-17 20:04:27 -0800828 refreshProgress(R.id.progress, mProgress, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 }
830 }
831
832 /**
833 * <p>Increase the progress bar's progress by the specified amount.</p>
834 *
835 * @param diff the amount by which the progress must be increased
836 *
837 * @see #setProgress(int)
838 */
839 public synchronized final void incrementProgressBy(int diff) {
840 setProgress(mProgress + diff);
841 }
842
843 /**
844 * <p>Increase the progress bar's secondary progress by the specified amount.</p>
845 *
846 * @param diff the amount by which the secondary progress must be increased
847 *
848 * @see #setSecondaryProgress(int)
849 */
850 public synchronized final void incrementSecondaryProgressBy(int diff) {
851 setSecondaryProgress(mSecondaryProgress + diff);
852 }
853
854 /**
855 * <p>Start the indeterminate progress animation.</p>
856 */
857 void startAnimation() {
Romain Guya05e8a52010-02-25 14:32:39 -0800858 if (getVisibility() != VISIBLE) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 return;
860 }
861
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700862 if (mIndeterminateDrawable instanceof Animatable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 mShouldStartAnimationDrawable = true;
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700864 mHasAnimation = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 } else {
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700866 mHasAnimation = true;
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 if (mInterpolator == null) {
869 mInterpolator = new LinearInterpolator();
870 }
871
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700872 if (mTransformation == null) {
873 mTransformation = new Transformation();
874 } else {
875 mTransformation.clear();
876 }
877
878 if (mAnimation == null) {
879 mAnimation = new AlphaAnimation(0.0f, 1.0f);
880 } else {
881 mAnimation.reset();
882 }
883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 mAnimation.setRepeatMode(mBehavior);
885 mAnimation.setRepeatCount(Animation.INFINITE);
886 mAnimation.setDuration(mDuration);
887 mAnimation.setInterpolator(mInterpolator);
888 mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 }
Evan Charlton08e14732010-06-07 10:38:53 -0700890 postInvalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 }
892
893 /**
894 * <p>Stop the indeterminate progress animation.</p>
895 */
896 void stopAnimation() {
Romain Guyab4c4f4f2012-05-06 13:11:24 -0700897 mHasAnimation = false;
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700898 if (mIndeterminateDrawable instanceof Animatable) {
899 ((Animatable) mIndeterminateDrawable).stop();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 mShouldStartAnimationDrawable = false;
901 }
Evan Charlton08e14732010-06-07 10:38:53 -0700902 postInvalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 }
904
905 /**
906 * Sets the acceleration curve for the indeterminate animation.
907 * The interpolator is loaded as a resource from the specified context.
908 *
909 * @param context The application environment
910 * @param resID The resource identifier of the interpolator to load
911 */
912 public void setInterpolator(Context context, int resID) {
913 setInterpolator(AnimationUtils.loadInterpolator(context, resID));
914 }
915
916 /**
917 * Sets the acceleration curve for the indeterminate animation.
918 * Defaults to a linear interpolation.
919 *
920 * @param interpolator The interpolator which defines the acceleration curve
921 */
922 public void setInterpolator(Interpolator interpolator) {
923 mInterpolator = interpolator;
924 }
925
926 /**
927 * Gets the acceleration curve type for the indeterminate animation.
928 *
929 * @return the {@link Interpolator} associated to this animation
930 */
931 public Interpolator getInterpolator() {
932 return mInterpolator;
933 }
934
935 @Override
Steve Howardb25ffff2010-08-20 17:39:26 -0700936 @RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 public void setVisibility(int v) {
938 if (getVisibility() != v) {
939 super.setVisibility(v);
940
941 if (mIndeterminate) {
942 // let's be nice with the UI thread
943 if (v == GONE || v == INVISIBLE) {
944 stopAnimation();
Romain Guya05e8a52010-02-25 14:32:39 -0800945 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 startAnimation();
947 }
948 }
949 }
950 }
951
952 @Override
Romain Guya05e8a52010-02-25 14:32:39 -0800953 protected void onVisibilityChanged(View changedView, int visibility) {
954 super.onVisibilityChanged(changedView, visibility);
955
956 if (mIndeterminate) {
957 // let's be nice with the UI thread
958 if (visibility == GONE || visibility == INVISIBLE) {
959 stopAnimation();
960 } else {
961 startAnimation();
962 }
963 }
964 }
965
966 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 public void invalidateDrawable(Drawable dr) {
968 if (!mInDrawing) {
The Android Open Source Projectba87e3e2009-03-13 13:04:22 -0700969 if (verifyDrawable(dr)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 final Rect dirty = dr.getBounds();
971 final int scrollX = mScrollX + mPaddingLeft;
972 final int scrollY = mScrollY + mPaddingTop;
973
974 invalidate(dirty.left + scrollX, dirty.top + scrollY,
975 dirty.right + scrollX, dirty.bottom + scrollY);
976 } else {
977 super.invalidateDrawable(dr);
978 }
979 }
980 }
981
982 @Override
983 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Joe Onoratoaa072632010-12-08 15:31:28 -0800984 updateDrawableBounds(w, h);
985 }
986
987 private void updateDrawableBounds(int w, int h) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 // onDraw will translate the canvas so we draw starting at 0,0
989 int right = w - mPaddingRight - mPaddingLeft;
990 int bottom = h - mPaddingBottom - mPaddingTop;
Adam Powella1b92c52011-09-02 15:05:15 -0700991 int top = 0;
992 int left = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993
994 if (mIndeterminateDrawable != null) {
Chet Haasea79803c2011-09-28 17:51:53 -0700995 // Aspect ratio logic does not apply to AnimationDrawables
996 if (mOnlyIndeterminate && !(mIndeterminateDrawable instanceof AnimationDrawable)) {
Adam Powella1b92c52011-09-02 15:05:15 -0700997 // Maintain aspect ratio. Certain kinds of animated drawables
998 // get very confused otherwise.
999 final int intrinsicWidth = mIndeterminateDrawable.getIntrinsicWidth();
1000 final int intrinsicHeight = mIndeterminateDrawable.getIntrinsicHeight();
1001 final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight;
1002 final float boundAspect = (float) w / h;
1003 if (intrinsicAspect != boundAspect) {
1004 if (boundAspect > intrinsicAspect) {
1005 // New width is larger. Make it smaller to match height.
1006 final int width = (int) (h * intrinsicAspect);
1007 left = (w - width) / 2;
1008 right = left + width;
1009 } else {
1010 // New height is larger. Make it smaller to match width.
1011 final int height = (int) (w * (1 / intrinsicAspect));
1012 top = (h - height) / 2;
1013 bottom = top + height;
1014 }
1015 }
1016 }
1017 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();
1034 canvas.translate(mPaddingLeft, mPaddingTop);
1035 long time = getDrawingTime();
Romain Guyab4c4f4f2012-05-06 13:11:24 -07001036 if (mHasAnimation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 mAnimation.getTransformation(time, mTransformation);
1038 float scale = mTransformation.getAlpha();
1039 try {
1040 mInDrawing = true;
1041 d.setLevel((int) (scale * MAX_LEVEL));
1042 } finally {
1043 mInDrawing = false;
1044 }
Jeff Brown6cb7b462012-03-05 13:21:17 -08001045 postInvalidateOnAnimation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 }
1047 d.draw(canvas);
1048 canvas.restore();
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001049 if (mShouldStartAnimationDrawable && d instanceof Animatable) {
1050 ((Animatable) d).start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 mShouldStartAnimationDrawable = false;
1052 }
1053 }
1054 }
1055
1056 @Override
1057 protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1058 Drawable d = mCurrentDrawable;
1059
1060 int dw = 0;
1061 int dh = 0;
1062 if (d != null) {
1063 dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
1064 dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
1065 }
Joe Onoratoaa072632010-12-08 15:31:28 -08001066 updateDrawableState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 dw += mPaddingLeft + mPaddingRight;
1068 dh += mPaddingTop + mPaddingBottom;
1069
Dianne Hackborn189ee182010-12-02 21:48:53 -08001070 setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
1071 resolveSizeAndState(dh, heightMeasureSpec, 0));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 }
1073
1074 @Override
1075 protected void drawableStateChanged() {
1076 super.drawableStateChanged();
Joe Onoratoaa072632010-12-08 15:31:28 -08001077 updateDrawableState();
1078 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079
Joe Onoratoaa072632010-12-08 15:31:28 -08001080 private void updateDrawableState() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 int[] state = getDrawableState();
1082
1083 if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
1084 mProgressDrawable.setState(state);
1085 }
1086
1087 if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
1088 mIndeterminateDrawable.setState(state);
1089 }
1090 }
1091
1092 static class SavedState extends BaseSavedState {
1093 int progress;
1094 int secondaryProgress;
1095
1096 /**
1097 * Constructor called from {@link ProgressBar#onSaveInstanceState()}
1098 */
1099 SavedState(Parcelable superState) {
1100 super(superState);
1101 }
1102
1103 /**
1104 * Constructor called from {@link #CREATOR}
1105 */
1106 private SavedState(Parcel in) {
1107 super(in);
1108 progress = in.readInt();
1109 secondaryProgress = in.readInt();
1110 }
1111
1112 @Override
1113 public void writeToParcel(Parcel out, int flags) {
1114 super.writeToParcel(out, flags);
1115 out.writeInt(progress);
1116 out.writeInt(secondaryProgress);
1117 }
1118
1119 public static final Parcelable.Creator<SavedState> CREATOR
1120 = new Parcelable.Creator<SavedState>() {
1121 public SavedState createFromParcel(Parcel in) {
1122 return new SavedState(in);
1123 }
1124
1125 public SavedState[] newArray(int size) {
1126 return new SavedState[size];
1127 }
1128 };
1129 }
1130
1131 @Override
1132 public Parcelable onSaveInstanceState() {
1133 // Force our ancestor class to save its state
1134 Parcelable superState = super.onSaveInstanceState();
1135 SavedState ss = new SavedState(superState);
1136
1137 ss.progress = mProgress;
1138 ss.secondaryProgress = mSecondaryProgress;
1139
1140 return ss;
1141 }
1142
1143 @Override
1144 public void onRestoreInstanceState(Parcelable state) {
1145 SavedState ss = (SavedState) state;
1146 super.onRestoreInstanceState(ss.getSuperState());
1147
1148 setProgress(ss.progress);
1149 setSecondaryProgress(ss.secondaryProgress);
1150 }
David Sobreira Marques52a35432010-05-15 16:10:18 -03001151
1152 @Override
1153 protected void onAttachedToWindow() {
1154 super.onAttachedToWindow();
1155 if (mIndeterminate) {
1156 startAnimation();
1157 }
Adam Powella0506632012-04-10 17:19:20 -07001158 if (mRefreshData != null) {
1159 synchronized (this) {
1160 final int count = mRefreshData.size();
1161 for (int i = 0; i < count; i++) {
1162 final RefreshData rd = mRefreshData.get(i);
1163 doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
1164 rd.recycle();
1165 }
1166 mRefreshData.clear();
1167 }
1168 }
1169 mAttached = true;
David Sobreira Marques52a35432010-05-15 16:10:18 -03001170 }
1171
1172 @Override
1173 protected void onDetachedFromWindow() {
David Sobreira Marques52a35432010-05-15 16:10:18 -03001174 if (mIndeterminate) {
1175 stopAnimation();
1176 }
Adam Powella0506632012-04-10 17:19:20 -07001177 if (mRefreshProgressRunnable != null) {
1178 removeCallbacks(mRefreshProgressRunnable);
1179 }
1180 if (mRefreshProgressRunnable != null && mRefreshIsPosted) {
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001181 removeCallbacks(mRefreshProgressRunnable);
1182 }
1183 if (mAccessibilityEventSender != null) {
1184 removeCallbacks(mAccessibilityEventSender);
1185 }
Patrick Dubroyec84c3a2011-01-13 17:55:37 -08001186 // This should come after stopAnimation(), otherwise an invalidate message remains in the
1187 // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
1188 super.onDetachedFromWindow();
Adam Powella0506632012-04-10 17:19:20 -07001189 mAttached = false;
David Sobreira Marques52a35432010-05-15 16:10:18 -03001190 }
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001191
1192 @Override
Svetoslav Ganov30401322011-05-12 18:53:45 -07001193 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1194 super.onInitializeAccessibilityEvent(event);
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001195 event.setClassName(ProgressBar.class.getName());
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001196 event.setItemCount(mMax);
1197 event.setCurrentItemIndex(mProgress);
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001198 }
1199
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001200 @Override
1201 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1202 super.onInitializeAccessibilityNodeInfo(info);
1203 info.setClassName(ProgressBar.class.getName());
1204 }
1205
Svetoslav Ganov6518ad72011-03-18 16:19:55 -07001206 /**
1207 * Schedule a command for sending an accessibility event.
1208 * </br>
1209 * Note: A command is used to ensure that accessibility events
1210 * are sent at most one in a given time frame to save
1211 * system resources while the progress changes quickly.
1212 */
1213 private void scheduleAccessibilityEventSender() {
1214 if (mAccessibilityEventSender == null) {
1215 mAccessibilityEventSender = new AccessibilityEventSender();
1216 } else {
1217 removeCallbacks(mAccessibilityEventSender);
1218 }
1219 postDelayed(mAccessibilityEventSender, TIMEOUT_SEND_ACCESSIBILITY_EVENT);
1220 }
1221
1222 /**
1223 * Command for sending an accessibility event.
1224 */
1225 private class AccessibilityEventSender implements Runnable {
1226 public void run() {
1227 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
1228 }
1229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230}