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