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 
17 package com.android.incallui.widget.multiwaveview;
18 
19 import android.content.res.Resources;
20 import android.graphics.Canvas;
21 import android.graphics.ColorFilter;
22 import android.graphics.Rect;
23 import android.graphics.drawable.Drawable;
24 import android.graphics.drawable.StateListDrawable;
25 import android.util.Log;
26 
27 public 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      */
TargetDrawable(Resources res, int resId, int count)61     public TargetDrawable(Resources res, int resId, int count) {
62         mResourceId = resId;
63         setDrawable(res, resId);
64         mNumDrawables = count;
65     }
66 
setDrawable(Resources res, int resId)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 
TargetDrawable(TargetDrawable other)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 
setState(int [] state)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      */
isActive()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      */
isEnabled()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      */
resizeDrawables()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 
setX(float x)155     public void setX(float x) {
156         mTranslationX = x;
157     }
158 
setY(float y)159     public void setY(float y) {
160         mTranslationY = y;
161     }
162 
setScaleX(float x)163     public void setScaleX(float x) {
164         mScaleX = x;
165     }
166 
setScaleY(float y)167     public void setScaleY(float y) {
168         mScaleY = y;
169     }
170 
setAlpha(float alpha)171     public void setAlpha(float alpha) {
172         mAlpha = alpha;
173     }
174 
getX()175     public float getX() {
176         return mTranslationX;
177     }
178 
getY()179     public float getY() {
180         return mTranslationY;
181     }
182 
getScaleX()183     public float getScaleX() {
184         return mScaleX;
185     }
186 
getScaleY()187     public float getScaleY() {
188         return mScaleY;
189     }
190 
getAlpha()191     public float getAlpha() {
192         return mAlpha;
193     }
194 
setPositionX(float x)195     public void setPositionX(float x) {
196         mPositionX = x;
197     }
198 
setPositionY(float y)199     public void setPositionY(float y) {
200         mPositionY = y;
201     }
202 
getPositionX()203     public float getPositionX() {
204         return mPositionX;
205     }
206 
getPositionY()207     public float getPositionY() {
208         return mPositionY;
209     }
210 
getWidth()211     public int getWidth() {
212         return mDrawable != null ? mDrawable.getIntrinsicWidth() : 0;
213     }
214 
getHeight()215     public int getHeight() {
216         return mDrawable != null ? mDrawable.getIntrinsicHeight() : 0;
217     }
218 
getBounds()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 
draw(Canvas canvas)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 
setEnabled(boolean enabled)243     public void setEnabled(boolean enabled) {
244         mEnabled  = enabled;
245     }
246 
getResourceId()247     public int getResourceId() {
248         return mResourceId;
249     }
250 }
251