Roll android_tools support library to 25.1.0
[android_tools.git] / sdk / sources / android-23 / android / graphics / drawable / RotateDrawable.java
blob036a078eb00d511823a55e3885909a0ce8cdb493
1 /*
2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package android.graphics.drawable;
19 import com.android.internal.R;
21 import org.xmlpull.v1.XmlPullParser;
22 import org.xmlpull.v1.XmlPullParserException;
24 import android.graphics.Canvas;
25 import android.graphics.Rect;
26 import android.content.res.Resources;
27 import android.content.res.TypedArray;
28 import android.content.res.Resources.Theme;
29 import android.util.MathUtils;
30 import android.util.TypedValue;
31 import android.util.AttributeSet;
33 import java.io.IOException;
35 /**
36 * <p>
37 * A Drawable that can rotate another Drawable based on the current level value.
38 * The start and end angles of rotation can be controlled to map any circular
39 * arc to the level values range.
40 * <p>
41 * It can be defined in an XML file with the <code>&lt;rotate&gt;</code> element.
42 * For more information, see the guide to
43 * <a href="{@docRoot}guide/topics/resources/animation-resource.html">Animation Resources</a>.
45 * @attr ref android.R.styleable#RotateDrawable_visible
46 * @attr ref android.R.styleable#RotateDrawable_fromDegrees
47 * @attr ref android.R.styleable#RotateDrawable_toDegrees
48 * @attr ref android.R.styleable#RotateDrawable_pivotX
49 * @attr ref android.R.styleable#RotateDrawable_pivotY
50 * @attr ref android.R.styleable#RotateDrawable_drawable
52 public class RotateDrawable extends DrawableWrapper {
53 private static final int MAX_LEVEL = 10000;
55 private RotateState mState;
57 /**
58 * Creates a new rotating drawable with no wrapped drawable.
60 public RotateDrawable() {
61 this(new RotateState(null), null);
64 @Override
65 public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
66 throws XmlPullParserException, IOException {
67 final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
68 super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible);
70 updateStateFromTypedArray(a);
71 inflateChildDrawable(r, parser, attrs, theme);
72 verifyRequiredAttributes(a);
73 a.recycle();
76 private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
77 // If we're not waiting on a theme, verify required attributes.
78 if (getDrawable() == null && (mState.mThemeAttrs == null
79 || mState.mThemeAttrs[R.styleable.RotateDrawable_drawable] == 0)) {
80 throw new XmlPullParserException(a.getPositionDescription()
81 + ": <rotate> tag requires a 'drawable' attribute or "
82 + "child tag defining a drawable");
86 @Override
87 void updateStateFromTypedArray(TypedArray a) {
88 super.updateStateFromTypedArray(a);
90 final RotateState state = mState;
92 // Extract the theme attributes, if any.
93 state.mThemeAttrs = a.extractThemeAttrs();
95 if (a.hasValue(R.styleable.RotateDrawable_pivotX)) {
96 final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotX);
97 state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION;
98 state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
101 if (a.hasValue(R.styleable.RotateDrawable_pivotY)) {
102 final TypedValue tv = a.peekValue(R.styleable.RotateDrawable_pivotY);
103 state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
104 state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
107 state.mFromDegrees = a.getFloat(
108 R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
109 state.mToDegrees = a.getFloat(
110 R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
111 state.mCurrentDegrees = state.mFromDegrees;
113 final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
114 if (dr != null) {
115 setDrawable(dr);
119 @Override
120 public void applyTheme(Theme t) {
121 final RotateState state = mState;
122 if (state == null) {
123 return;
126 if (state.mThemeAttrs != null) {
127 final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
128 try {
129 updateStateFromTypedArray(a);
130 verifyRequiredAttributes(a);
131 } catch (XmlPullParserException e) {
132 throw new RuntimeException(e);
133 } finally {
134 a.recycle();
138 // The drawable may have changed as a result of applying the theme, so
139 // apply the theme to the wrapped drawable last.
140 super.applyTheme(t);
143 @Override
144 public void draw(Canvas canvas) {
145 final Drawable d = getDrawable();
146 final Rect bounds = d.getBounds();
147 final int w = bounds.right - bounds.left;
148 final int h = bounds.bottom - bounds.top;
149 final RotateState st = mState;
150 final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
151 final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
153 final int saveCount = canvas.save();
154 canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
155 d.draw(canvas);
156 canvas.restoreToCount(saveCount);
160 * Sets the start angle for rotation.
162 * @param fromDegrees starting angle in degrees
163 * @see #getFromDegrees()
164 * @attr ref android.R.styleable#RotateDrawable_fromDegrees
166 public void setFromDegrees(float fromDegrees) {
167 if (mState.mFromDegrees != fromDegrees) {
168 mState.mFromDegrees = fromDegrees;
169 invalidateSelf();
174 * @return starting angle for rotation in degrees
175 * @see #setFromDegrees(float)
176 * @attr ref android.R.styleable#RotateDrawable_fromDegrees
178 public float getFromDegrees() {
179 return mState.mFromDegrees;
183 * Sets the end angle for rotation.
185 * @param toDegrees ending angle in degrees
186 * @see #getToDegrees()
187 * @attr ref android.R.styleable#RotateDrawable_toDegrees
189 public void setToDegrees(float toDegrees) {
190 if (mState.mToDegrees != toDegrees) {
191 mState.mToDegrees = toDegrees;
192 invalidateSelf();
197 * @return ending angle for rotation in degrees
198 * @see #setToDegrees(float)
199 * @attr ref android.R.styleable#RotateDrawable_toDegrees
201 public float getToDegrees() {
202 return mState.mToDegrees;
206 * Sets the X position around which the drawable is rotated.
208 * @param pivotX X position around which to rotate. If the X pivot is
209 * relative, the position represents a fraction of the drawable
210 * width. Otherwise, the position represents an absolute value in
211 * pixels.
212 * @see #setPivotXRelative(boolean)
213 * @attr ref android.R.styleable#RotateDrawable_pivotX
215 public void setPivotX(float pivotX) {
216 if (mState.mPivotX != pivotX) {
217 mState.mPivotX = pivotX;
218 invalidateSelf();
223 * @return X position around which to rotate
224 * @see #setPivotX(float)
225 * @attr ref android.R.styleable#RotateDrawable_pivotX
227 public float getPivotX() {
228 return mState.mPivotX;
232 * Sets whether the X pivot value represents a fraction of the drawable
233 * width or an absolute value in pixels.
235 * @param relative true if the X pivot represents a fraction of the drawable
236 * width, or false if it represents an absolute value in pixels
237 * @see #isPivotXRelative()
239 public void setPivotXRelative(boolean relative) {
240 if (mState.mPivotXRel != relative) {
241 mState.mPivotXRel = relative;
242 invalidateSelf();
247 * @return true if the X pivot represents a fraction of the drawable width,
248 * or false if it represents an absolute value in pixels
249 * @see #setPivotXRelative(boolean)
251 public boolean isPivotXRelative() {
252 return mState.mPivotXRel;
256 * Sets the Y position around which the drawable is rotated.
258 * @param pivotY Y position around which to rotate. If the Y pivot is
259 * relative, the position represents a fraction of the drawable
260 * height. Otherwise, the position represents an absolute value
261 * in pixels.
262 * @see #getPivotY()
263 * @attr ref android.R.styleable#RotateDrawable_pivotY
265 public void setPivotY(float pivotY) {
266 if (mState.mPivotY != pivotY) {
267 mState.mPivotY = pivotY;
268 invalidateSelf();
273 * @return Y position around which to rotate
274 * @see #setPivotY(float)
275 * @attr ref android.R.styleable#RotateDrawable_pivotY
277 public float getPivotY() {
278 return mState.mPivotY;
282 * Sets whether the Y pivot value represents a fraction of the drawable
283 * height or an absolute value in pixels.
285 * @param relative True if the Y pivot represents a fraction of the drawable
286 * height, or false if it represents an absolute value in pixels
287 * @see #isPivotYRelative()
289 public void setPivotYRelative(boolean relative) {
290 if (mState.mPivotYRel != relative) {
291 mState.mPivotYRel = relative;
292 invalidateSelf();
297 * @return true if the Y pivot represents a fraction of the drawable height,
298 * or false if it represents an absolute value in pixels
299 * @see #setPivotYRelative(boolean)
301 public boolean isPivotYRelative() {
302 return mState.mPivotYRel;
305 @Override
306 protected boolean onLevelChange(int level) {
307 super.onLevelChange(level);
309 final float value = level / (float) MAX_LEVEL;
310 final float degrees = MathUtils.lerp(mState.mFromDegrees, mState.mToDegrees, value);
311 mState.mCurrentDegrees = degrees;
313 invalidateSelf();
314 return true;
317 @Override
318 DrawableWrapperState mutateConstantState() {
319 mState = new RotateState(mState);
320 return mState;
323 static final class RotateState extends DrawableWrapper.DrawableWrapperState {
324 boolean mPivotXRel = true;
325 float mPivotX = 0.5f;
326 boolean mPivotYRel = true;
327 float mPivotY = 0.5f;
328 float mFromDegrees = 0.0f;
329 float mToDegrees = 360.0f;
330 float mCurrentDegrees = 0.0f;
332 RotateState(RotateState orig) {
333 super(orig);
335 if (orig != null) {
336 mPivotXRel = orig.mPivotXRel;
337 mPivotX = orig.mPivotX;
338 mPivotYRel = orig.mPivotYRel;
339 mPivotY = orig.mPivotY;
340 mFromDegrees = orig.mFromDegrees;
341 mToDegrees = orig.mToDegrees;
342 mCurrentDegrees = orig.mCurrentDegrees;
346 @Override
347 public Drawable newDrawable(Resources res) {
348 return new RotateDrawable(this, res);
352 private RotateDrawable(RotateState state, Resources res) {
353 super(state, res);
355 mState = state;