1ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banespackage android.support.v7.internal.widget;
2ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
3ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes/*
4ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * Copyright (C) 2013 Android Open Source Project
5ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes *
6ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * Licensed under the Apache License, Version 2.0 (the "License");
7ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * you may not use this file except in compliance with the License.
8ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * You may obtain a copy of the License at
9ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes *
10ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes *      http://www.apache.org/licenses/LICENSE-2.0
11ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes *
12ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * Unless required by applicable law or agreed to in writing, software
13ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * distributed under the License is distributed on an "AS IS" BASIS,
14ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * See the License for the specific language governing permissions and
16ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * limitations under the License.
17ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes */
18ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
19ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
20ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.content.Context;
21ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.content.res.TypedArray;
22ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.Bitmap;
23ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.BitmapShader;
24ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.Canvas;
25ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.Rect;
26ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.Shader;
27ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.Animatable;
28ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.AnimationDrawable;
29ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.BitmapDrawable;
30ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.ClipDrawable;
31ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.Drawable;
32ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.LayerDrawable;
33ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.ShapeDrawable;
34ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.shapes.RoundRectShape;
35ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.graphics.drawable.shapes.Shape;
36ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.os.Parcel;
37ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.os.Parcelable;
38ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.os.SystemClock;
39ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.util.AttributeSet;
40ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.view.Gravity;
41ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.view.View;
42ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.view.animation.AlphaAnimation;
43ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.view.animation.Animation;
44ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.view.animation.AnimationUtils;
45ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.view.animation.Interpolator;
46ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.view.animation.LinearInterpolator;
47ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banesimport android.view.animation.Transformation;
48ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
49ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes/**
50ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes * @hide
51ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes */
52ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banespublic class ProgressBarICS extends View {
53ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
54ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private static final int MAX_LEVEL = 10000;
55ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private static final int ANIMATION_RESOLUTION = 200;
56ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
57ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
58ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * android.R.styleable.ProgressBar is internalised, so we need to create it ourselves.
59ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes      */
60ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private static final int[] android_R_styleable_ProgressBar = new int[]{
61ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.max,
62ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.progress,
63ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.secondaryProgress,
64ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.indeterminate,
65ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.indeterminateOnly,
66ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.indeterminateDrawable,
67ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.progressDrawable,
68ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.indeterminateDuration,
69ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.indeterminateBehavior,
70ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.minWidth,
71ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.maxWidth,
72ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.minHeight,
73ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.maxHeight,
74ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            android.R.attr.interpolator,
75ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    };
76ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
77ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    int mMinWidth;
78ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    int mMaxWidth;
79ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    int mMinHeight;
80ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    int mMaxHeight;
81ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
82ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private int mProgress;
83ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private int mSecondaryProgress;
84ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private int mMax;
85ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
86ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private int mBehavior;
87ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private int mDuration;
88ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private boolean mIndeterminate;
89ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private boolean mOnlyIndeterminate;
90ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private Transformation mTransformation;
91ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private AlphaAnimation mAnimation;
92ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private Drawable mIndeterminateDrawable;
93ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private Drawable mProgressDrawable;
94ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private Drawable mCurrentDrawable;
95ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    Bitmap mSampleTile;
96ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private boolean mNoInvalidate;
97ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private Interpolator mInterpolator;
98ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private RefreshProgressRunnable mRefreshProgressRunnable;
99ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private long mUiThreadId;
100ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private boolean mShouldStartAnimationDrawable;
101ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private long mLastDrawTime;
102ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
103ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private boolean mInDrawing;
104ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
105ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
106ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @hide
107ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
108ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public ProgressBarICS(Context context, AttributeSet attrs, int defStyle, int styleRes) {
109ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        super(context, attrs, defStyle);
110ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mUiThreadId = Thread.currentThread().getId();
111ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        initProgressBar();
112ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
113ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        TypedArray a = context.obtainStyledAttributes(attrs, android_R_styleable_ProgressBar,
114ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                defStyle, styleRes);
115ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
116ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mNoInvalidate = true;
117ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
118ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setMax(a.getInt(0, mMax));
119ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setProgress(a.getInt(1, mProgress));
120ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setSecondaryProgress(a.getInt(2, mSecondaryProgress));
121ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
122ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        final boolean indeterminate = a.getBoolean(3, mIndeterminate);
123ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mOnlyIndeterminate = a.getBoolean(4, mOnlyIndeterminate);
124ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
125ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        Drawable drawable = a.getDrawable(5);
126ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (drawable != null) {
127ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            drawable = tileifyIndeterminate(drawable);
128ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            setIndeterminateDrawable(drawable);
129ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
130ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
131ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        drawable = a.getDrawable(6);
132ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (drawable != null) {
133ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            drawable = tileify(drawable, false);
134ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            // Calling this method can set mMaxHeight, make sure the corresponding
135ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            // XML attribute for mMaxHeight is read after calling this method
136ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            setProgressDrawable(drawable);
137ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
138ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
139ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mDuration = a.getInt(7, mDuration);
140ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mBehavior = a.getInt(8, mBehavior);
141ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMinWidth = a.getDimensionPixelSize(9, mMinWidth);
142ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMaxWidth = a.getDimensionPixelSize(10, mMaxWidth);
143ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMinHeight = a.getDimensionPixelSize(11, mMinHeight);
144ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMaxHeight = a.getDimensionPixelSize(12, mMaxHeight);
145ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
146ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        final int resID = a.getResourceId(13, android.R.anim.linear_interpolator);
147ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (resID > 0) {
148ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            setInterpolator(context, resID);
149ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
150ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
151ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        a.recycle();
152ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
153ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mNoInvalidate = false;
154ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setIndeterminate(mOnlyIndeterminate || indeterminate);
155ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
156ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
157ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
158ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Converts a drawable to a tiled version of itself. It will recursively
159ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * traverse layer and state list drawables.
160ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
161ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private Drawable tileify(Drawable drawable, boolean clip) {
162ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
163ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (drawable instanceof LayerDrawable) {
164ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            LayerDrawable background = (LayerDrawable) drawable;
165ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            final int N = background.getNumberOfLayers();
166ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            Drawable[] outDrawables = new Drawable[N];
167ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
168ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            for (int i = 0; i < N; i++) {
169ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                int id = background.getId(i);
170ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                outDrawables[i] = tileify(background.getDrawable(i),
171ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        (id == android.R.id.progress || id == android.R.id.secondaryProgress));
172ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
173ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
174ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            LayerDrawable newBg = new LayerDrawable(outDrawables);
175ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
176ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            for (int i = 0; i < N; i++) {
177ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                newBg.setId(i, background.getId(i));
178ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
179ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
180ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            return newBg;
181ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
182ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        } else if (drawable instanceof BitmapDrawable) {
183ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
184ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mSampleTile == null) {
185ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mSampleTile = tileBitmap;
186ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
187ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
188ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
189ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
190ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
191ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
192ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            shapeDrawable.getPaint().setShader(bitmapShader);
193ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
194ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
195ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    ClipDrawable.HORIZONTAL) : shapeDrawable;
196ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
197ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
198ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return drawable;
199ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
200ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
201ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    Shape getDrawableShape() {
202ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
203ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return new RoundRectShape(roundedCorners, null, null);
204ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
205ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
206ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
207ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Convert a AnimationDrawable for use as a barberpole animation.
208ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Each frame of the animation is wrapped in a ClipDrawable and
209ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * given a tiling BitmapShader.
210ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
211ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private Drawable tileifyIndeterminate(Drawable drawable) {
212ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (drawable instanceof AnimationDrawable) {
213ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            AnimationDrawable background = (AnimationDrawable) drawable;
214ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            final int N = background.getNumberOfFrames();
215ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            AnimationDrawable newBg = new AnimationDrawable();
216ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            newBg.setOneShot(background.isOneShot());
217ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
218ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            for (int i = 0; i < N; i++) {
219ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                Drawable frame = tileify(background.getFrame(i), true);
220ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                frame.setLevel(10000);
221ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                newBg.addFrame(frame, background.getDuration(i));
222ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
223ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            newBg.setLevel(10000);
224ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            drawable = newBg;
225ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
226ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return drawable;
227ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
228ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
229ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
230ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>
231ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Initialize the progress bar's default values:
232ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * </p>
233ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <ul>
234ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <li>progress = 0</li>
235ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <li>max = 100</li>
236ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <li>animation duration = 4000 ms</li>
237ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <li>indeterminate = false</li>
238ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <li>behavior = repeat</li>
239ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * </ul>
240ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
241ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private void initProgressBar() {
242ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMax = 100;
243ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mProgress = 0;
244ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mSecondaryProgress = 0;
245ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mIndeterminate = false;
246ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mOnlyIndeterminate = false;
247ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mDuration = 4000;
248ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mBehavior = AlphaAnimation.RESTART;
249ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMinWidth = 24;
250ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMaxWidth = 48;
251ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMinHeight = 24;
252ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mMaxHeight = 48;
253ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
254ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
255ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
256ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Indicate whether this progress bar is in indeterminate mode.</p>
257ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
258ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @return true if the progress bar is in indeterminate mode
259ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
260ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized boolean isIndeterminate() {
261ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return mIndeterminate;
262ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
263ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
264ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
265ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Change the indeterminate mode for this progress bar. In indeterminate
266ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * mode, the progress is ignored and the progress bar shows an infinite
267ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * animation instead.</p>
268ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
269ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * If this progress bar's style only supports indeterminate mode (such as the circular
270ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * progress bars), then this will be ignored.
271ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
272ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param indeterminate true to enable the indeterminate mode
273ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
274ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized void setIndeterminate(boolean indeterminate) {
275ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
276ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mIndeterminate = indeterminate;
277ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
278ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (indeterminate) {
279ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                // swap between indeterminate and regular backgrounds
280ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mCurrentDrawable = mIndeterminateDrawable;
281ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                startAnimation();
282ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            } else {
283ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mCurrentDrawable = mProgressDrawable;
284ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                stopAnimation();
285ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
286ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
287ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
288ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
289ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
290ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Get the drawable used to draw the progress bar in
291ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * indeterminate mode.</p>
292ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
293ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @return a {@link android.graphics.drawable.Drawable} instance
294ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
295ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable)
296ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminate(boolean)
297ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
298ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public Drawable getIndeterminateDrawable() {
299ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return mIndeterminateDrawable;
300ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
301ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
302ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
303ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Define the drawable used to draw the progress bar in
304ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * indeterminate mode.</p>
305ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
306ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param d the new drawable
307ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
308ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getIndeterminateDrawable()
309ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminate(boolean)
310ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
311ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public void setIndeterminateDrawable(Drawable d) {
312ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (d != null) {
313ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            d.setCallback(this);
314ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
315ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mIndeterminateDrawable = d;
316ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminate) {
317ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mCurrentDrawable = d;
318ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            postInvalidate();
319ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
320ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
321ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
322ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
323ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Get the drawable used to draw the progress bar in
324ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * progress mode.</p>
325ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
326ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @return a {@link android.graphics.drawable.Drawable} instance
327ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
328ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setProgressDrawable(android.graphics.drawable.Drawable)
329ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminate(boolean)
330ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
331ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public Drawable getProgressDrawable() {
332ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return mProgressDrawable;
333ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
334ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
335ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
336ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Define the drawable used to draw the progress bar in
337ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * progress mode.</p>
338ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
339ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param d the new drawable
340ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
341ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getProgressDrawable()
342ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminate(boolean)
343ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
344ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public void setProgressDrawable(Drawable d) {
345ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        boolean needUpdate;
346ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mProgressDrawable != null && d != mProgressDrawable) {
347ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mProgressDrawable.setCallback(null);
348ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            needUpdate = true;
349ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        } else {
350ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            needUpdate = false;
351ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
352ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
353ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (d != null) {
354ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            d.setCallback(this);
355ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
356ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            // Make sure the android_R_styleable_ProgressBar is always tall enough
357ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            int drawableHeight = d.getMinimumHeight();
358ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mMaxHeight < drawableHeight) {
359ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mMaxHeight = drawableHeight;
360ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                requestLayout();
361ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
362ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
363ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mProgressDrawable = d;
364ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (!mIndeterminate) {
365ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mCurrentDrawable = d;
366ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            postInvalidate();
367ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
368ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
369ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (needUpdate) {
370ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            updateDrawableBounds(getWidth(), getHeight());
371ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            updateDrawableState();
372ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            doRefreshProgress(android.R.id.progress, mProgress, false, false);
373ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            doRefreshProgress(android.R.id.secondaryProgress, mSecondaryProgress, false, false);
374ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
375ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
376ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
377ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
378ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    protected boolean verifyDrawable(Drawable who) {
379ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return who == mProgressDrawable || who == mIndeterminateDrawable
380ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                || super.verifyDrawable(who);
381ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
382ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
383ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
384ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public void postInvalidate() {
385ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (!mNoInvalidate) {
386ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            super.postInvalidate();
387ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
388ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
389ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
390ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private class RefreshProgressRunnable implements Runnable {
391ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
392ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        private int mId;
393ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        private int mProgress;
394ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        private boolean mFromUser;
395ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
396ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        RefreshProgressRunnable(int id, int progress, boolean fromUser) {
397ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mId = id;
398ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mProgress = progress;
399ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mFromUser = fromUser;
400ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
401ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
402ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        public void run() {
403ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            doRefreshProgress(mId, mProgress, mFromUser, true);
404ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            // Put ourselves back in the cache when we are done
405ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mRefreshProgressRunnable = this;
406ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
407ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
408ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        public void setup(int id, int progress, boolean fromUser) {
409ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mId = id;
410ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mProgress = progress;
411ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mFromUser = fromUser;
412ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
413ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
414ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
415ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
416ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
417ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            boolean callBackToApp) {
418ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
419ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        final Drawable d = mCurrentDrawable;
420ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (d != null) {
421ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            Drawable progressDrawable = null;
422ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
423ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (d instanceof LayerDrawable) {
424ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
425ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
426ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
427ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            final int level = (int) (scale * MAX_LEVEL);
428ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            (progressDrawable != null ? progressDrawable : d).setLevel(level);
429ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        } else {
430ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            invalidate();
431ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
432ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
433ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
434ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
435ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mUiThreadId == Thread.currentThread().getId()) {
436ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            doRefreshProgress(id, progress, fromUser, true);
437ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        } else {
438ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            RefreshProgressRunnable r;
439ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mRefreshProgressRunnable != null) {
440ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                // Use cached RefreshProgressRunnable if available
441ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                r = mRefreshProgressRunnable;
442ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                // Uncache it
443ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mRefreshProgressRunnable = null;
444ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                r.setup(id, progress, fromUser);
445ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            } else {
446ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                // Make a new one
447ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                r = new RefreshProgressRunnable(id, progress, fromUser);
448ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
449ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            post(r);
450ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
451ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
452ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
453ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
454ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Set the current progress to the specified value. Does not do anything
455ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * if the progress bar is in indeterminate mode.</p>
456ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
457ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param progress the new progress, between 0 and {@link #getMax()}
458ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
459ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminate(boolean)
460ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #isIndeterminate()
461ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getProgress()
462ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #incrementProgressBy(int)
463ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
464ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized void setProgress(int progress) {
465ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setProgress(progress, false);
466ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
467ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
468ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    synchronized void setProgress(int progress, boolean fromUser) {
469ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminate) {
470ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            return;
471ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
472ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
473ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (progress < 0) {
474ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            progress = 0;
475ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
476ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
477ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (progress > mMax) {
478ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            progress = mMax;
479ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
480ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
481ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (progress != mProgress) {
482ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mProgress = progress;
483ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            refreshProgress(android.R.id.progress, mProgress, fromUser);
484ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
485ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
486ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
487ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
488ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>
489ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Set the current secondary progress to the specified value. Does not do
490ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * anything if the progress bar is in indeterminate mode.
491ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * </p>
492ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
493ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
494ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminate(boolean)
495ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #isIndeterminate()
496ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getSecondaryProgress()
497ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #incrementSecondaryProgressBy(int)
498ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
499ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized void setSecondaryProgress(int secondaryProgress) {
500ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminate) {
501ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            return;
502ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
503ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
504ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (secondaryProgress < 0) {
505ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            secondaryProgress = 0;
506ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
507ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
508ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (secondaryProgress > mMax) {
509ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            secondaryProgress = mMax;
510ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
511ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
512ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (secondaryProgress != mSecondaryProgress) {
513ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mSecondaryProgress = secondaryProgress;
514ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            refreshProgress(android.R.id.secondaryProgress, mSecondaryProgress, false);
515ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
516ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
517ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
518ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
519ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Get the progress bar's current level of progress. Return 0 when the
520ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * progress bar is in indeterminate mode.</p>
521ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
522ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @return the current progress, between 0 and {@link #getMax()}
523ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
524ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminate(boolean)
525ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #isIndeterminate()
526ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setProgress(int)
527ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setMax(int)
528ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getMax()
529ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
530ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized int getProgress() {
531ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return mIndeterminate ? 0 : mProgress;
532ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
533ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
534ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
535ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Get the progress bar's current level of secondary progress. Return 0 when the
536ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * progress bar is in indeterminate mode.</p>
537ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
538ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @return the current secondary progress, between 0 and {@link #getMax()}
539ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
540ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setIndeterminate(boolean)
541ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #isIndeterminate()
542ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setSecondaryProgress(int)
543ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setMax(int)
544ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getMax()
545ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
546ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized int getSecondaryProgress() {
547ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return mIndeterminate ? 0 : mSecondaryProgress;
548ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
549ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
550ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
551ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Return the upper limit of this progress bar's range.</p>
552ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
553ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @return a positive integer
554ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
555ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setMax(int)
556ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getProgress()
557ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getSecondaryProgress()
558ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
559ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized int getMax() {
560ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return mMax;
561ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
562ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
563ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
564ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Set the range of the progress bar to 0...<tt>max</tt>.</p>
565ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
566ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param max the upper range of this progress bar
567ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
568ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #getMax()
569ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setProgress(int)
570ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setSecondaryProgress(int)
571ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
572ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized void setMax(int max) {
573ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (max < 0) {
574ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            max = 0;
575ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
576ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (max != mMax) {
577ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mMax = max;
578ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            postInvalidate();
579ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
580ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mProgress > max) {
581ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mProgress = max;
582ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
583ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            refreshProgress(android.R.id.progress, mProgress, false);
584ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
585ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
586ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
587ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
588ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Increase the progress bar's progress by the specified amount.</p>
589ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
590ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param diff the amount by which the progress must be increased
591ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
592ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setProgress(int)
593ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
594ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized final void incrementProgressBy(int diff) {
595ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setProgress(mProgress + diff);
596ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
597ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
598ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
599ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Increase the progress bar's secondary progress by the specified amount.</p>
600ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
601ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param diff the amount by which the secondary progress must be increased
602ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
603ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @see #setSecondaryProgress(int)
604ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
605ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public synchronized final void incrementSecondaryProgressBy(int diff) {
606ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setSecondaryProgress(mSecondaryProgress + diff);
607ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
608ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
609ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
610ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Start the indeterminate progress animation.</p>
611ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
612ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    void startAnimation() {
613ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (getVisibility() != VISIBLE) {
614ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            return;
615ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
616ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
617ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminateDrawable instanceof Animatable) {
618ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mShouldStartAnimationDrawable = true;
619ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mAnimation = null;
620ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        } else {
621ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mInterpolator == null) {
622ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mInterpolator = new LinearInterpolator();
623ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
624ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
625ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mTransformation = new Transformation();
626ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mAnimation = new AlphaAnimation(0.0f, 1.0f);
627ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mAnimation.setRepeatMode(mBehavior);
628ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mAnimation.setRepeatCount(Animation.INFINITE);
629ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mAnimation.setDuration(mDuration);
630ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mAnimation.setInterpolator(mInterpolator);
631ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME);
632ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
633ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        postInvalidate();
634ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
635ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
636ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
637ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * <p>Stop the indeterminate progress animation.</p>
638ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
639ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    void stopAnimation() {
640ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mAnimation = null;
641ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mTransformation = null;
642ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminateDrawable instanceof Animatable) {
643ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            ((Animatable) mIndeterminateDrawable).stop();
644ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mShouldStartAnimationDrawable = false;
645ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
646ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        postInvalidate();
647ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
648ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
649ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
650ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Sets the acceleration curve for the indeterminate animation.
651ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * The interpolator is loaded as a resource from the specified context.
652ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
653ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param context The application environment
654ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param resID The resource identifier of the interpolator to load
655ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
656ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public void setInterpolator(Context context, int resID) {
657ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setInterpolator(AnimationUtils.loadInterpolator(context, resID));
658ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
659ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
660ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
661ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Sets the acceleration curve for the indeterminate animation.
662ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Defaults to a linear interpolation.
663ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
664ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @param interpolator The interpolator which defines the acceleration curve
665ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
666ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public void setInterpolator(Interpolator interpolator) {
667ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        mInterpolator = interpolator;
668ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
669ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
670ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    /**
671ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * Gets the acceleration curve type for the indeterminate animation.
672ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     *
673ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     * @return the {@link Interpolator} associated to this animation
674ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes     */
675ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public Interpolator getInterpolator() {
676ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return mInterpolator;
677ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
678ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
679ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
680ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public void setVisibility(int v) {
681ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (getVisibility() != v) {
682ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            super.setVisibility(v);
683ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
684ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mIndeterminate) {
685ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                // let's be nice with the UI thread
686ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                if (v == GONE || v == INVISIBLE) {
687ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    stopAnimation();
688ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                } else {
689ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    startAnimation();
690ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                }
691ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
692ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
693ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
694ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
695ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
696ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    protected void onVisibilityChanged(View changedView, int visibility) {
697ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        super.onVisibilityChanged(changedView, visibility);
698ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
699ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminate) {
700ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            // let's be nice with the UI thread
701ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (visibility == GONE || visibility == INVISIBLE) {
702ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                stopAnimation();
703ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            } else {
704ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                startAnimation();
705ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
706ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
707ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
708ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
709ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
710ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public void invalidateDrawable(Drawable dr) {
711ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (!mInDrawing) {
712ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (verifyDrawable(dr)) {
713ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                final Rect dirty = dr.getBounds();
714ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                final int scrollX = getScrollX() + getPaddingLeft();
715ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                final int scrollY = getScrollY() + getPaddingTop();
716ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
717ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                invalidate(dirty.left + scrollX, dirty.top + scrollY,
718ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        dirty.right + scrollX, dirty.bottom + scrollY);
719ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            } else {
720ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                super.invalidateDrawable(dr);
721ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
722ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
723ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
724ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
725ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
726ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
727ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        updateDrawableBounds(w, h);
728ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
729ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
730ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private void updateDrawableBounds(int w, int h) {
731ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        // onDraw will translate the canvas so we draw starting at 0,0
732ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int right = w - getPaddingRight() - getPaddingLeft();
733ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int bottom = h - getPaddingBottom() - getPaddingTop();
734ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int top = 0;
735ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int left = 0;
736ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
737ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminateDrawable != null) {
738ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            // Aspect ratio logic does not apply to AnimationDrawables
739ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mOnlyIndeterminate && !(mIndeterminateDrawable instanceof AnimationDrawable)) {
740ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                // Maintain aspect ratio. Certain kinds of animated drawables
741ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                // get very confused otherwise.
742ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                final int intrinsicWidth = mIndeterminateDrawable.getIntrinsicWidth();
743ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                final int intrinsicHeight = mIndeterminateDrawable.getIntrinsicHeight();
744ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight;
745ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                final float boundAspect = (float) w / h;
746ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                if (intrinsicAspect != boundAspect) {
747ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    if (boundAspect > intrinsicAspect) {
748ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        // New width is larger. Make it smaller to match height.
749ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        final int width = (int) (h * intrinsicAspect);
750ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        left = (w - width) / 2;
751ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        right = left + width;
752ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    } else {
753ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        // New height is larger. Make it smaller to match width.
754ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        final int height = (int) (w * (1 / intrinsicAspect));
755ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        top = (h - height) / 2;
756ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                        bottom = top + height;
757ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    }
758ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                }
759ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
760ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mIndeterminateDrawable.setBounds(left, top, right, bottom);
761ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
762ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
763ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mProgressDrawable != null) {
764ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mProgressDrawable.setBounds(0, 0, right, bottom);
765ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
766ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
767ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
768ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
769ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    protected synchronized void onDraw(Canvas canvas) {
770ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        super.onDraw(canvas);
771ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
772ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        Drawable d = mCurrentDrawable;
773ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (d != null) {
774ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            // Translate canvas so a indeterminate circular progress bar with padding
775ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            // rotates properly in its animation
776ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            canvas.save();
777ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            canvas.translate(getPaddingLeft(), getPaddingTop());
778ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            long time = getDrawingTime();
779ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mAnimation != null) {
780ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mAnimation.getTransformation(time, mTransformation);
781ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                float scale = mTransformation.getAlpha();
782ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                try {
783ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    mInDrawing = true;
784ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    d.setLevel((int) (scale * MAX_LEVEL));
785ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                } finally {
786ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    mInDrawing = false;
787ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                }
788ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                if (SystemClock.uptimeMillis() - mLastDrawTime >= ANIMATION_RESOLUTION) {
789ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    mLastDrawTime = SystemClock.uptimeMillis();
790ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                    postInvalidateDelayed(ANIMATION_RESOLUTION);
791ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                }
792ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
793ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            d.draw(canvas);
794ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            canvas.restore();
795ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            if (mShouldStartAnimationDrawable && d instanceof Animatable) {
796ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                ((Animatable) d).start();
797ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                mShouldStartAnimationDrawable = false;
798ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
799ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
800ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
801ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
802ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
803ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
804ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        Drawable d = mCurrentDrawable;
805ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
806ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int dw = 0;
807ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int dh = 0;
808ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (d != null) {
809ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
810ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
811ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
812ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        updateDrawableState();
813ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        dw += getPaddingLeft() + getPaddingRight();
814ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        dh += getPaddingTop() + getPaddingBottom();
815ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
816ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setMeasuredDimension(resolveSize(dw, widthMeasureSpec),
817ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                resolveSize(dh, heightMeasureSpec));
818ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
819ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
820ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
821ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    protected void drawableStateChanged() {
822ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        super.drawableStateChanged();
823ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        updateDrawableState();
824ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
825ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
826ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    private void updateDrawableState() {
827ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int[] state = getDrawableState();
828ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
829ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
830ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mProgressDrawable.setState(state);
831ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
832ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
833ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
834ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            mIndeterminateDrawable.setState(state);
835ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
836ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
837ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
838ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    static class SavedState extends BaseSavedState {
839ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int progress;
840ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        int secondaryProgress;
841ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
842ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        /**
843ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes         * Constructor called from {@link ProgressBarICS#onSaveInstanceState()}
844ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes         */
845ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        SavedState(Parcelable superState) {
846ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            super(superState);
847ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
848ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
849ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        /**
850ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes         * Constructor called from {@link #CREATOR}
851ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes         */
852ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        private SavedState(Parcel in) {
853ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            super(in);
854ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            progress = in.readInt();
855ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            secondaryProgress = in.readInt();
856ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
857ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
858ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        @Override
859ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        public void writeToParcel(Parcel out, int flags) {
860ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            super.writeToParcel(out, flags);
861ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            out.writeInt(progress);
862ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            out.writeInt(secondaryProgress);
863ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
864ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
865ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        public static final Parcelable.Creator<SavedState> CREATOR
866ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                = new Parcelable.Creator<SavedState>() {
867ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            public SavedState createFromParcel(Parcel in) {
868ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                return new SavedState(in);
869ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
870ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
871ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            public SavedState[] newArray(int size) {
872ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes                return new SavedState[size];
873ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            }
874ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        };
875ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
876ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
877ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
878ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public Parcelable onSaveInstanceState() {
879ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        // Force our ancestor class to save its state
880ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        Parcelable superState = super.onSaveInstanceState();
881ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        SavedState ss = new SavedState(superState);
882ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
883ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        ss.progress = mProgress;
884ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        ss.secondaryProgress = mSecondaryProgress;
885ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
886ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        return ss;
887ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
888ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
889ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
890ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    public void onRestoreInstanceState(Parcelable state) {
891ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        SavedState ss = (SavedState) state;
892ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        super.onRestoreInstanceState(ss.getSuperState());
893ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
894ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setProgress(ss.progress);
895ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        setSecondaryProgress(ss.secondaryProgress);
896ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
897ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
898ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
899ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    protected void onAttachedToWindow() {
900ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        super.onAttachedToWindow();
901ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminate) {
902ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            startAnimation();
903ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
904ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
905ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
906ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    @Override
907ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    protected void onDetachedFromWindow() {
908ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if (mIndeterminate) {
909ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            stopAnimation();
910ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
911ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        if(mRefreshProgressRunnable != null) {
912ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes            removeCallbacks(mRefreshProgressRunnable);
913ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        }
914ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
915ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        // This should come after stopAnimation(), otherwise an invalidate message remains in the
916ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
917ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes        super.onDetachedFromWindow();
918ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes    }
919ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes
920ed34e2dffd0ce7da89063d06fd3b25687ca367a2Chris Banes}