1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view.animation;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.content.res.TypedArray;
22import android.util.AttributeSet;
23import android.util.TypedValue;
24
25/**
26 * An animation that controls the scale of an object. You can specify the point
27 * to use for the center of scaling.
28 *
29 */
30public class ScaleAnimation extends Animation {
31    private final Resources mResources;
32
33    private float mFromX;
34    private float mToX;
35    private float mFromY;
36    private float mToY;
37
38    private int mFromXType = TypedValue.TYPE_NULL;
39    private int mToXType = TypedValue.TYPE_NULL;
40    private int mFromYType = TypedValue.TYPE_NULL;
41    private int mToYType = TypedValue.TYPE_NULL;
42
43    private int mFromXData = 0;
44    private int mToXData = 0;
45    private int mFromYData = 0;
46    private int mToYData = 0;
47
48    private int mPivotXType = ABSOLUTE;
49    private int mPivotYType = ABSOLUTE;
50    private float mPivotXValue = 0.0f;
51    private float mPivotYValue = 0.0f;
52
53    private float mPivotX;
54    private float mPivotY;
55
56    /**
57     * Constructor used when a ScaleAnimation is loaded from a resource.
58     *
59     * @param context Application context to use
60     * @param attrs Attribute set from which to read values
61     */
62    public ScaleAnimation(Context context, AttributeSet attrs) {
63        super(context, attrs);
64
65        mResources = context.getResources();
66
67        TypedArray a = context.obtainStyledAttributes(attrs,
68                com.android.internal.R.styleable.ScaleAnimation);
69
70        TypedValue tv = a.peekValue(
71                com.android.internal.R.styleable.ScaleAnimation_fromXScale);
72        mFromX = 0.0f;
73        if (tv != null) {
74            if (tv.type == TypedValue.TYPE_FLOAT) {
75                // This is a scaling factor.
76                mFromX = tv.getFloat();
77            } else {
78                mFromXType = tv.type;
79                mFromXData = tv.data;
80            }
81        }
82        tv = a.peekValue(
83                com.android.internal.R.styleable.ScaleAnimation_toXScale);
84        mToX = 0.0f;
85        if (tv != null) {
86            if (tv.type == TypedValue.TYPE_FLOAT) {
87                // This is a scaling factor.
88                mToX = tv.getFloat();
89            } else {
90                mToXType = tv.type;
91                mToXData = tv.data;
92            }
93        }
94
95        tv = a.peekValue(
96                com.android.internal.R.styleable.ScaleAnimation_fromYScale);
97        mFromY = 0.0f;
98        if (tv != null) {
99            if (tv.type == TypedValue.TYPE_FLOAT) {
100                // This is a scaling factor.
101                mFromY = tv.getFloat();
102            } else {
103                mFromYType = tv.type;
104                mFromYData = tv.data;
105            }
106        }
107        tv = a.peekValue(
108                com.android.internal.R.styleable.ScaleAnimation_toYScale);
109        mToY = 0.0f;
110        if (tv != null) {
111            if (tv.type == TypedValue.TYPE_FLOAT) {
112                // This is a scaling factor.
113                mToY = tv.getFloat();
114            } else {
115                mToYType = tv.type;
116                mToYData = tv.data;
117            }
118        }
119
120        Description d = Description.parseValue(a.peekValue(
121                com.android.internal.R.styleable.ScaleAnimation_pivotX));
122        mPivotXType = d.type;
123        mPivotXValue = d.value;
124
125        d = Description.parseValue(a.peekValue(
126            com.android.internal.R.styleable.ScaleAnimation_pivotY));
127        mPivotYType = d.type;
128        mPivotYValue = d.value;
129
130        a.recycle();
131
132        initializePivotPoint();
133    }
134
135    /**
136     * Constructor to use when building a ScaleAnimation from code
137     *
138     * @param fromX Horizontal scaling factor to apply at the start of the
139     *        animation
140     * @param toX Horizontal scaling factor to apply at the end of the animation
141     * @param fromY Vertical scaling factor to apply at the start of the
142     *        animation
143     * @param toY Vertical scaling factor to apply at the end of the animation
144     */
145    public ScaleAnimation(float fromX, float toX, float fromY, float toY) {
146        mResources = null;
147        mFromX = fromX;
148        mToX = toX;
149        mFromY = fromY;
150        mToY = toY;
151        mPivotX = 0;
152        mPivotY = 0;
153    }
154
155    /**
156     * Constructor to use when building a ScaleAnimation from code
157     *
158     * @param fromX Horizontal scaling factor to apply at the start of the
159     *        animation
160     * @param toX Horizontal scaling factor to apply at the end of the animation
161     * @param fromY Vertical scaling factor to apply at the start of the
162     *        animation
163     * @param toY Vertical scaling factor to apply at the end of the animation
164     * @param pivotX The X coordinate of the point about which the object is
165     *        being scaled, specified as an absolute number where 0 is the left
166     *        edge. (This point remains fixed while the object changes size.)
167     * @param pivotY The Y coordinate of the point about which the object is
168     *        being scaled, specified as an absolute number where 0 is the top
169     *        edge. (This point remains fixed while the object changes size.)
170     */
171    public ScaleAnimation(float fromX, float toX, float fromY, float toY,
172            float pivotX, float pivotY) {
173        mResources = null;
174        mFromX = fromX;
175        mToX = toX;
176        mFromY = fromY;
177        mToY = toY;
178
179        mPivotXType = ABSOLUTE;
180        mPivotYType = ABSOLUTE;
181        mPivotXValue = pivotX;
182        mPivotYValue = pivotY;
183        initializePivotPoint();
184    }
185
186    /**
187     * Constructor to use when building a ScaleAnimation from code
188     *
189     * @param fromX Horizontal scaling factor to apply at the start of the
190     *        animation
191     * @param toX Horizontal scaling factor to apply at the end of the animation
192     * @param fromY Vertical scaling factor to apply at the start of the
193     *        animation
194     * @param toY Vertical scaling factor to apply at the end of the animation
195     * @param pivotXType Specifies how pivotXValue should be interpreted. One of
196     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
197     *        Animation.RELATIVE_TO_PARENT.
198     * @param pivotXValue The X coordinate of the point about which the object
199     *        is being scaled, specified as an absolute number where 0 is the
200     *        left edge. (This point remains fixed while the object changes
201     *        size.) This value can either be an absolute number if pivotXType
202     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
203     * @param pivotYType Specifies how pivotYValue should be interpreted. One of
204     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
205     *        Animation.RELATIVE_TO_PARENT.
206     * @param pivotYValue The Y coordinate of the point about which the object
207     *        is being scaled, specified as an absolute number where 0 is the
208     *        top edge. (This point remains fixed while the object changes
209     *        size.) This value can either be an absolute number if pivotYType
210     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
211     */
212    public ScaleAnimation(float fromX, float toX, float fromY, float toY,
213            int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
214        mResources = null;
215        mFromX = fromX;
216        mToX = toX;
217        mFromY = fromY;
218        mToY = toY;
219
220        mPivotXValue = pivotXValue;
221        mPivotXType = pivotXType;
222        mPivotYValue = pivotYValue;
223        mPivotYType = pivotYType;
224        initializePivotPoint();
225    }
226
227    /**
228     * Called at the end of constructor methods to initialize, if possible, values for
229     * the pivot point. This is only possible for ABSOLUTE pivot values.
230     */
231    private void initializePivotPoint() {
232        if (mPivotXType == ABSOLUTE) {
233            mPivotX = mPivotXValue;
234        }
235        if (mPivotYType == ABSOLUTE) {
236            mPivotY = mPivotYValue;
237        }
238    }
239
240    @Override
241    protected void applyTransformation(float interpolatedTime, Transformation t) {
242        float sx = 1.0f;
243        float sy = 1.0f;
244        float scale = getScaleFactor();
245
246        if (mFromX != 1.0f || mToX != 1.0f) {
247            sx = mFromX + ((mToX - mFromX) * interpolatedTime);
248        }
249        if (mFromY != 1.0f || mToY != 1.0f) {
250            sy = mFromY + ((mToY - mFromY) * interpolatedTime);
251        }
252
253        if (mPivotX == 0 && mPivotY == 0) {
254            t.getMatrix().setScale(sx, sy);
255        } else {
256            t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY);
257        }
258    }
259
260    float resolveScale(float scale, int type, int data, int size, int psize) {
261        float targetSize;
262        if (type == TypedValue.TYPE_FRACTION) {
263            targetSize = TypedValue.complexToFraction(data, size, psize);
264        } else if (type == TypedValue.TYPE_DIMENSION) {
265            targetSize = TypedValue.complexToDimension(data, mResources.getDisplayMetrics());
266        } else {
267            return scale;
268        }
269
270        if (size == 0) {
271            return 1;
272        }
273
274        return targetSize/(float)size;
275    }
276
277    @Override
278    public void initialize(int width, int height, int parentWidth, int parentHeight) {
279        super.initialize(width, height, parentWidth, parentHeight);
280
281        mFromX = resolveScale(mFromX, mFromXType, mFromXData, width, parentWidth);
282        mToX = resolveScale(mToX, mToXType, mToXData, width, parentWidth);
283        mFromY = resolveScale(mFromY, mFromYType, mFromYData, height, parentHeight);
284        mToY = resolveScale(mToY, mToYType, mToYData, height, parentHeight);
285
286        mPivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth);
287        mPivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight);
288    }
289}
290