1/*
2 * Copyright (C) 2011 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 com.android.internal.widget.multiwaveview;
18
19import android.content.res.Resources;
20import android.graphics.Canvas;
21import android.graphics.drawable.Drawable;
22import android.graphics.drawable.StateListDrawable;
23import android.util.Log;
24
25public class TargetDrawable {
26    private static final String TAG = "TargetDrawable";
27    private static final boolean DEBUG = false;
28
29    public static final int[] STATE_ACTIVE =
30            { android.R.attr.state_enabled, android.R.attr.state_active };
31    public static final int[] STATE_INACTIVE =
32            { android.R.attr.state_enabled, -android.R.attr.state_active };
33    public static final int[] STATE_FOCUSED =
34            { android.R.attr.state_enabled, -android.R.attr.state_active,
35                android.R.attr.state_focused };
36
37    private float mTranslationX = 0.0f;
38    private float mTranslationY = 0.0f;
39    private float mPositionX = 0.0f;
40    private float mPositionY = 0.0f;
41    private float mScaleX = 1.0f;
42    private float mScaleY = 1.0f;
43    private float mAlpha = 1.0f;
44    private Drawable mDrawable;
45    private boolean mEnabled = true;
46    private final int mResourceId;
47
48    public TargetDrawable(Resources res, int resId) {
49        mResourceId = resId;
50        setDrawable(res, resId);
51    }
52
53    public void setDrawable(Resources res, int resId) {
54        // Note we explicitly don't set mResourceId to resId since we allow the drawable to be
55        // swapped at runtime and want to re-use the existing resource id for identification.
56        Drawable drawable = resId == 0 ? null : res.getDrawable(resId);
57        // Mutate the drawable so we can animate shared drawable properties.
58        mDrawable = drawable != null ? drawable.mutate() : null;
59        resizeDrawables();
60        setState(STATE_INACTIVE);
61    }
62
63    public TargetDrawable(TargetDrawable other) {
64        mResourceId = other.mResourceId;
65        // Mutate the drawable so we can animate shared drawable properties.
66        mDrawable = other.mDrawable != null ? other.mDrawable.mutate() : null;
67        resizeDrawables();
68        setState(STATE_INACTIVE);
69    }
70
71    public void setState(int [] state) {
72        if (mDrawable instanceof StateListDrawable) {
73            StateListDrawable d = (StateListDrawable) mDrawable;
74            d.setState(state);
75        }
76    }
77
78    public boolean hasState(int [] state) {
79        if (mDrawable instanceof StateListDrawable) {
80            StateListDrawable d = (StateListDrawable) mDrawable;
81            // TODO: this doesn't seem to work
82            return d.getStateDrawableIndex(state) != -1;
83        }
84        return false;
85    }
86
87    /**
88     * Returns true if the drawable is a StateListDrawable and is in the focused state.
89     *
90     * @return
91     */
92    public boolean isActive() {
93        if (mDrawable instanceof StateListDrawable) {
94            StateListDrawable d = (StateListDrawable) mDrawable;
95            int[] states = d.getState();
96            for (int i = 0; i < states.length; i++) {
97                if (states[i] == android.R.attr.state_focused) {
98                    return true;
99                }
100            }
101        }
102        return false;
103    }
104
105    /**
106     * Returns true if this target is enabled. Typically an enabled target contains a valid
107     * drawable in a valid state. Currently all targets with valid drawables are valid.
108     *
109     * @return
110     */
111    public boolean isEnabled() {
112        return mDrawable != null && mEnabled;
113    }
114
115    /**
116     * Makes drawables in a StateListDrawable all the same dimensions.
117     * If not a StateListDrawable, then justs sets the bounds to the intrinsic size of the
118     * drawable.
119     */
120    private void resizeDrawables() {
121        if (mDrawable instanceof StateListDrawable) {
122            StateListDrawable d = (StateListDrawable) mDrawable;
123            int maxWidth = 0;
124            int maxHeight = 0;
125            for (int i = 0; i < d.getStateCount(); i++) {
126                Drawable childDrawable = d.getStateDrawable(i);
127                maxWidth = Math.max(maxWidth, childDrawable.getIntrinsicWidth());
128                maxHeight = Math.max(maxHeight, childDrawable.getIntrinsicHeight());
129            }
130            if (DEBUG) Log.v(TAG, "union of childDrawable rects " + d + " to: "
131                        + maxWidth + "x" + maxHeight);
132            d.setBounds(0, 0, maxWidth, maxHeight);
133            for (int i = 0; i < d.getStateCount(); i++) {
134                Drawable childDrawable = d.getStateDrawable(i);
135                if (DEBUG) Log.v(TAG, "sizing drawable " + childDrawable + " to: "
136                            + maxWidth + "x" + maxHeight);
137                childDrawable.setBounds(0, 0, maxWidth, maxHeight);
138            }
139        } else if (mDrawable != null) {
140            mDrawable.setBounds(0, 0,
141                    mDrawable.getIntrinsicWidth(), mDrawable.getIntrinsicHeight());
142        }
143    }
144
145    public void setX(float x) {
146        mTranslationX = x;
147    }
148
149    public void setY(float y) {
150        mTranslationY = y;
151    }
152
153    public void setScaleX(float x) {
154        mScaleX = x;
155    }
156
157    public void setScaleY(float y) {
158        mScaleY = y;
159    }
160
161    public void setAlpha(float alpha) {
162        mAlpha = alpha;
163    }
164
165    public float getX() {
166        return mTranslationX;
167    }
168
169    public float getY() {
170        return mTranslationY;
171    }
172
173    public float getScaleX() {
174        return mScaleX;
175    }
176
177    public float getScaleY() {
178        return mScaleY;
179    }
180
181    public float getAlpha() {
182        return mAlpha;
183    }
184
185    public void setPositionX(float x) {
186        mPositionX = x;
187    }
188
189    public void setPositionY(float y) {
190        mPositionY = y;
191    }
192
193    public float getPositionX() {
194        return mPositionX;
195    }
196
197    public float getPositionY() {
198        return mPositionY;
199    }
200
201    public int getWidth() {
202        return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
203    }
204
205    public int getHeight() {
206        return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0;
207    }
208
209    public void draw(Canvas canvas) {
210        if (mDrawable == null || !mEnabled) {
211            return;
212        }
213        canvas.save(Canvas.MATRIX_SAVE_FLAG);
214        canvas.scale(mScaleX, mScaleY, mPositionX, mPositionY);
215        canvas.translate(mTranslationX + mPositionX, mTranslationY + mPositionY);
216        canvas.translate(-0.5f * getWidth(), -0.5f * getHeight());
217        mDrawable.setAlpha((int) Math.round(mAlpha * 255f));
218        mDrawable.draw(canvas);
219        canvas.restore();
220    }
221
222    public void setEnabled(boolean enabled) {
223        mEnabled  = enabled;
224    }
225
226    public int getResourceId() {
227        return mResourceId;
228    }
229}
230