19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.graphics.drawable;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1917cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viveretteimport com.android.internal.R;
2017cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParser;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport org.xmlpull.v1.XmlPullParserException;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Canvas;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.ColorFilter;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect;
27b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viveretteimport android.graphics.PorterDuff.Mode;
28b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viveretteimport android.content.res.ColorStateList;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.TypedArray;
3152b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viveretteimport android.content.res.Resources.Theme;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.TypedValue;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
38a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette * <p>
39a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette * A Drawable that can rotate another Drawable based on the current level value.
40a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette * The start and end angles of rotation can be controlled to map any circular
41a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette * arc to the level values range.
42a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette * <p>
43a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette * It can be defined in an XML file with the <code>&lt;rotate&gt;</code> element.
44a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette * For more information, see the guide to
45a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette * <a href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#RotateDrawable_visible
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#RotateDrawable_fromDegrees
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#RotateDrawable_toDegrees
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#RotateDrawable_pivotX
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#RotateDrawable_pivotY
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @attr ref android.R.styleable#RotateDrawable_drawable
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class RotateDrawable extends Drawable implements Drawable.Callback {
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final float MAX_LEVEL = 10000.0f;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
57a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    private final RotateState mState;
58a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMutated;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
62a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Create a new rotating drawable with an empty state.
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public RotateDrawable() {
659db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru        this(null, null);
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
69a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Create a new rotating drawable with the specified state. A copy of
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this state is used as the internal state for the newly created
71a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * drawable.
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param rotateState the state for this drawable
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
759db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru    private RotateDrawable(RotateState rotateState, Resources res) {
769db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru        mState = new RotateState(rotateState, this, res);
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
79a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    @Override
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void draw(Canvas canvas) {
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final RotateState st = mState;
82a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final Drawable d = st.mDrawable;
83a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final Rect bounds = d.getBounds();
84a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final int w = bounds.right - bounds.left;
85a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final int h = bounds.bottom - bounds.top;
86a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
87a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
88a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
89a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final int saveCount = canvas.save();
90a1b92c5e8b750d8f5b2dc5ca7e8b4edc97de5575Adam Powell        canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
91a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        d.draw(canvas);
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        canvas.restoreToCount(saveCount);
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
96a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Sets the drawable rotated by this RotateDrawable.
97a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *
98a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @param drawable The drawable to rotate
99a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
100a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public void setDrawable(Drawable drawable) {
101a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final Drawable oldDrawable = mState.mDrawable;
102a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        if (oldDrawable != drawable) {
103a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            if (oldDrawable != null) {
104a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette                oldDrawable.setCallback(null);
105a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            }
106a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            mState.mDrawable = drawable;
107a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            if (drawable != null) {
108a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette                drawable.setCallback(this);
109a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            }
110a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        }
111a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
112a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
113a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
114a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @return The drawable rotated by this RotateDrawable
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable getDrawable() {
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mState.mDrawable;
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getChangingConfigurations() {
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.getChangingConfigurations()
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                | mState.mChangingConfigurations
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                | mState.mDrawable.getChangingConfigurations();
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
126a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
127a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    @Override
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setAlpha(int alpha) {
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mState.mDrawable.setAlpha(alpha);
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
132b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    @Override
133b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    public int getAlpha() {
134b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase        return mState.mDrawable.getAlpha();
135b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase    }
136b1af7f3d4be6cd6bc6e1e805f22c209e19bf928fChet Haase
137a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    @Override
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setColorFilter(ColorFilter cf) {
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mState.mDrawable.setColorFilter(cf);
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
142a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    @Override
143a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    public void setTintList(ColorStateList tint) {
144a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mState.mDrawable.setTintList(tint);
145a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    }
146a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette
147a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    @Override
148a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    public void setTintMode(Mode tintMode) {
149a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        mState.mDrawable.setTintMode(tintMode);
150b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    }
151b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette
152b3c56086d802ae28888dd97ba1f49bd6cee0b673Alan Viverette    @Override
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getOpacity() {
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mState.mDrawable.getOpacity();
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
157a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
158a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Sets the start angle for rotation.
159a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *
160a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @param fromDegrees Starting angle in degrees
161e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
162e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @see #getFromDegrees()
163e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
164a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
165a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public void setFromDegrees(float fromDegrees) {
166a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        if (mState.mFromDegrees != fromDegrees) {
167a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            mState.mFromDegrees = fromDegrees;
168a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            invalidateSelf();
169a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        }
170a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
171a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
172a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
173a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @return The starting angle for rotation in degrees
174e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
175e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @see #setFromDegrees(float)
176e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
177a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
178a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public float getFromDegrees() {
179a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        return mState.mFromDegrees;
180a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
181a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
182a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
183a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Sets the end angle for rotation.
184a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *
185a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @param toDegrees Ending angle in degrees
186e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
187e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @see #getToDegrees()
188e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @attr ref android.R.styleable#RotateDrawable_toDegrees
189a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
190a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public void setToDegrees(float toDegrees) {
191a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        if (mState.mToDegrees != toDegrees) {
192a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            mState.mToDegrees = toDegrees;
193a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            invalidateSelf();
194a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        }
195a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
196a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
197a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
198a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @return The ending angle for rotation in degrees
199e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
200e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @see #setToDegrees(float)
201e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @attr ref android.R.styleable#RotateDrawable_toDegrees
202a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
203a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public float getToDegrees() {
204a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        return mState.mToDegrees;
205a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
206a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
207a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
208a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Sets the X position around which the drawable is rotated.
209a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *
210a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @param pivotX X position around which to rotate. If the X pivot is
211a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *            relative, the position represents a fraction of the drawable
212a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *            width. Otherwise, the position represents an absolute value in
213a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *            pixels.
214e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
215a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @see #setPivotXRelative(boolean)
216e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @attr ref android.R.styleable#RotateDrawable_pivotX
217a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
218a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public void setPivotX(float pivotX) {
219735b75ce274ef7a4c78745844a4269d72cb4feaejungheang.lee        if (mState.mPivotX != pivotX) {
220a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            mState.mPivotX = pivotX;
221a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            invalidateSelf();
222a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        }
223a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
224a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
225a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
226a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @return X position around which to rotate
227e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
228a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @see #setPivotX(float)
229e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @attr ref android.R.styleable#RotateDrawable_pivotX
230a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
231a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public float getPivotX() {
232a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        return mState.mPivotX;
233a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
234a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
235a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
236a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Sets whether the X pivot value represents a fraction of the drawable
237a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * width or an absolute value in pixels.
238a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *
239a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @param relative True if the X pivot represents a fraction of the drawable
240a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *            width, or false if it represents an absolute value in pixels
241e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
242e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @see #isPivotXRelative()
243a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
244a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public void setPivotXRelative(boolean relative) {
245735b75ce274ef7a4c78745844a4269d72cb4feaejungheang.lee        if (mState.mPivotXRel != relative) {
246a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            mState.mPivotXRel = relative;
247a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            invalidateSelf();
248a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        }
249a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
250a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
251a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
252a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @return True if the X pivot represents a fraction of the drawable width,
253a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *         or false if it represents an absolute value in pixels
254e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
255a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @see #setPivotXRelative(boolean)
256a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
257a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public boolean isPivotXRelative() {
258a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        return mState.mPivotXRel;
259a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
260a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
261a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
262a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Sets the Y position around which the drawable is rotated.
263a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *
264a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @param pivotY Y position around which to rotate. If the Y pivot is
265a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *            relative, the position represents a fraction of the drawable
266a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *            height. Otherwise, the position represents an absolute value
267a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *            in pixels.
268e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
269e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @see #getPivotY()
270e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @attr ref android.R.styleable#RotateDrawable_pivotY
271a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
272a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public void setPivotY(float pivotY) {
273735b75ce274ef7a4c78745844a4269d72cb4feaejungheang.lee        if (mState.mPivotY != pivotY) {
274a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            mState.mPivotY = pivotY;
275a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            invalidateSelf();
276a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        }
277a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
278a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
279a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
280a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @return Y position around which to rotate
281e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
282a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @see #setPivotY(float)
283e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @attr ref android.R.styleable#RotateDrawable_pivotY
284a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
285a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public float getPivotY() {
286a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        return mState.mPivotY;
287a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
288a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
289a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
290a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Sets whether the Y pivot value represents a fraction of the drawable
291a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * height or an absolute value in pixels.
292a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *
293a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @param relative True if the Y pivot represents a fraction of the drawable
294a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *            height, or false if it represents an absolute value in pixels
295e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
296e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     * @see #isPivotYRelative()
297a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
298a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public void setPivotYRelative(boolean relative) {
299735b75ce274ef7a4c78745844a4269d72cb4feaejungheang.lee        if (mState.mPivotYRel != relative) {
300a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            mState.mPivotYRel = relative;
301a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette            invalidateSelf();
302a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        }
303a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
304a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
305a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    /**
306a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @return True if the Y pivot represents a fraction of the drawable height,
307a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     *         or false if it represents an absolute value in pixels
308e5b082d6eb0489e7dbe3159338f8c94c0af61deeAlan Viverette     *
309a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * @see #setPivotYRelative(boolean)
310a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     */
311a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    public boolean isPivotYRelative() {
312a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        return mState.mPivotYRel;
313a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    }
314a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
315a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    @Override
316d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    public boolean canApplyTheme() {
317d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
318d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
319d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
320d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    @Override
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void invalidateDrawable(Drawable who) {
322f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy        final Callback callback = getCallback();
323f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy        if (callback != null) {
324f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy            callback.invalidateDrawable(this);
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
328a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    @Override
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void scheduleDrawable(Drawable who, Runnable what, long when) {
330f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy        final Callback callback = getCallback();
331f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy        if (callback != null) {
332f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy            callback.scheduleDrawable(this, what, when);
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
336a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette    @Override
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unscheduleDrawable(Drawable who, Runnable what) {
338f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy        final Callback callback = getCallback();
339f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy        if (callback != null) {
340f2a47782f31b58d2d31bd00b50fe43604af8b9c2Romain Guy            callback.unscheduleDrawable(this, what);
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project   @Override
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean getPadding(Rect padding) {
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mState.mDrawable.getPadding(padding);
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean setVisible(boolean visible, boolean restart) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mState.mDrawable.setVisible(visible, restart);
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return super.setVisible(visible, restart);
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStateful() {
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mState.mDrawable.isStateful();
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
359a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean onStateChange(int[] state) {
362a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        final boolean changed = mState.mDrawable.setState(state);
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onBoundsChange(getBounds());
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return changed;
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected boolean onLevelChange(int level) {
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mState.mDrawable.setLevel(level);
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        onBoundsChange(getBounds());
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mState.mCurrentDegrees = mState.mFromDegrees +
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (mState.mToDegrees - mState.mFromDegrees) *
374a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette                        (level / MAX_LEVEL);
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        invalidateSelf();
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onBoundsChange(Rect bounds) {
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mState.mDrawable.setBounds(bounds.left, bounds.top,
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                bounds.right, bounds.bottom);
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicWidth() {
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mState.mDrawable.getIntrinsicWidth();
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getIntrinsicHeight() {
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mState.mDrawable.getIntrinsicHeight();
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ConstantState getConstantState() {
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mState.canConstantState()) {
3996efd2bad954e0e5bd74916a32f036a0f149dcd4dChristopher Lais            mState.mChangingConfigurations = getChangingConfigurations();
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mState;
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return null;
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
40652b999f0721b53e9c6e18a4bd664e89aeb65b2d5Alan Viverette    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throws XmlPullParserException, IOException {
408d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
409d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible);
410a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
411d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        // Reset mDrawable to preserve old multiple-inflate behavior. This is
412d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        // silly, but we have CTS tests that rely on it.
413d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        mState.mDrawable = null;
414d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
415d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        updateStateFromTypedArray(a);
416d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        inflateChildElements(r, parser, attrs, theme);
417d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        verifyRequiredAttributes(a);
418d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        a.recycle();
419d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
420b81b1447d2cfa9dc5bcc02c8a1b7193400a97ab6Cyril Mottier
421d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    @Override
422d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    public void applyTheme(Theme t) {
423d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        super.applyTheme(t);
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
425d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        final RotateState state = mState;
426d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        if (state == null) {
427d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            return;
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4307f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette        if (state.mThemeAttrs != null) {
4317f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
4327f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette            try {
4337f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette                updateStateFromTypedArray(a);
4347f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette                verifyRequiredAttributes(a);
4357f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette            } catch (XmlPullParserException e) {
4367f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette                throw new RuntimeException(e);
4377f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette            } finally {
4387f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette                a.recycle();
4397f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette            }
440d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        }
441a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
442d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
443d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            state.mDrawable.applyTheme(t);
444d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        }
4457f4a63d1ebc13c6499a48331ecb78c4d27446dbcAlan Viverette
446d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
448d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
449d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            Theme theme) throws XmlPullParserException, IOException {
450d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        Drawable dr = null;
451d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        int type;
452d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        final int outerDepth = parser.getDepth();
453d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
454d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (type != XmlPullParser.START_TAG) {
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
458d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
461d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        if (dr != null) {
462d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            mState.mDrawable = dr;
463d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            dr.setCallback(this);
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
465d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    }
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
467d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
468d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        // If we're not waiting on a theme, verify required attributes.
469d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        if (mState.mDrawable == null && (mState.mThemeAttrs == null
470d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
471d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            throw new XmlPullParserException(a.getPositionDescription()
472d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                    + ": <rotate> tag requires a 'drawable' attribute or "
473d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                    + "child tag defining a drawable");
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
477d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette    private void updateStateFromTypedArray(TypedArray a) {
47817cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        final RotateState state = mState;
479d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
480d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        // Account for any configuration changes.
481d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.mChangingConfigurations |= a.getChangingConfigurations();
482d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
483d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        // Extract the theme attributes, if any.
484d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.mThemeAttrs = a.extractThemeAttrs();
485d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
486d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        if (a.hasValue(R.styleable.RotateDrawable_pivotX)) {
487d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotX);
488d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION;
489d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
49017cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        }
49117cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette
492d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        if (a.hasValue(R.styleable.RotateDrawable_pivotY)) {
493d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotY);
494d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
495d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
49617cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette        }
49717cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette
498d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.mFromDegrees = a.getFloat(R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
499d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        state.mToDegrees = a.getFloat(R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
500d03963ce364e9946f1bd603c2fcf07a49088af19Alan Viverette        state.mCurrentDegrees = state.mFromDegrees;
501d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
502d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
503d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        if (dr != null) {
504d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            state.mDrawable = dr;
505d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            dr.setCallback(this);
506d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        }
50717cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette    }
50817cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette
50917cd4dfe3a05c2eddbcbc76066ff3b13fc3f2c8bAlan Viverette    @Override
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Drawable mutate() {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mMutated && super.mutate() == this) {
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mState.mDrawable.mutate();
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMutated = true;
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return this;
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
519727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette     * @hide
520727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette     */
521727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    public void clearMutated() {
522727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette        super.clearMutated();
523727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette        mState.mDrawable.clearMutated();
524727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette        mMutated = false;
525727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    }
526727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette
527727cae197b123ef764a1f8fbe08a995b000d14c3Alan Viverette    /**
528a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * Represents the state of a rotation for a given drawable. The same
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * rotate drawable can be invoked with different states to drive several
530a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette     * rotations at the same time.
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    final static class RotateState extends Drawable.ConstantState {
533d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        int[] mThemeAttrs;
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int mChangingConfigurations;
535a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
536d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        Drawable mDrawable;
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
538d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        boolean mPivotXRel = true;
539d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        float mPivotX = 0.5f;
540d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        boolean mPivotYRel = true;
541d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        float mPivotY = 0.5f;
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
543d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        float mFromDegrees = 0.0f;
544d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        float mToDegrees = 360.0f;
545d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
546d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        float mCurrentDegrees = 0.0f;
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
548a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette        private boolean mCheckedConstantState;
549d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        private boolean mCanConstantState;
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
551d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        RotateState(RotateState orig, RotateDrawable owner, Resources res) {
552d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette            if (orig != null) {
553d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                mThemeAttrs = orig.mThemeAttrs;
554d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                mChangingConfigurations = orig.mChangingConfigurations;
5559db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru                if (res != null) {
556d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                    mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
5579db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru                } else {
558d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                    mDrawable = orig.mDrawable.getConstantState().newDrawable();
5599db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru                }
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDrawable.setCallback(owner);
561d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection());
562d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                mDrawable.setBounds(orig.mDrawable.getBounds());
563d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                mDrawable.setLevel(orig.mDrawable.getLevel());
564d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                mPivotXRel = orig.mPivotXRel;
565d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                mPivotX = orig.mPivotX;
566d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                mPivotYRel = orig.mPivotYRel;
567d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                mPivotY = orig.mPivotY;
568d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                mFromDegrees = orig.mFromDegrees;
569d7853e576301bf68e96148a0b9e52085bfc7cf95Alan Viverette                mToDegrees = orig.mToDegrees;
570d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                mCurrentDegrees = orig.mCurrentDegrees;
571d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                mCheckedConstantState = mCanConstantState = true;
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
576d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        public boolean canApplyTheme() {
577d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
578d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette                    || super.canApplyTheme();
579d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        }
580d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette
581d21fd9d1ccd2b525f9c004a6cd9ba19a645701abAlan Viverette        @Override
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public Drawable newDrawable() {
5839db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru            return new RotateDrawable(this, null);
5849db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru        }
585a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
5869db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru        @Override
5879db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru        public Drawable newDrawable(Resources res) {
5889db3d07b9620b4269ab33f78604a36327e536ce1Jean-Baptiste Queru            return new RotateDrawable(this, res);
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
590a8b2edec93beeaa76b3cfc93bb9cb3e19fc34addAlan Viverette
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getChangingConfigurations() {
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mChangingConfigurations;
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean canConstantState() {
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!mCheckedConstantState) {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCanConstantState = mDrawable.getConstantState() != null;
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mCheckedConstantState = true;
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mCanConstantState;
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
606