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