blob: ebaad59d134c6b67c4741f8ddeefab18adc7ef66 [file] [log] [blame]
George Mountd6107a32014-03-10 16:51:16 -07001/*
2 * Copyright (C) 2014 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 */
16package android.transition;
17
18import android.content.res.Resources;
19import android.graphics.Canvas;
20import android.graphics.ColorFilter;
21import android.graphics.Matrix;
22import android.graphics.Rect;
23import android.graphics.drawable.Drawable;
24import android.util.Property;
25
26/**
27 * Used in MoveImage to mock an ImageView as a Drawable to be scaled in the scene root Overlay.
28 * @hide
29 */
30class MatrixClippedDrawable extends Drawable implements Drawable.Callback {
31 private static final String TAG = "MatrixClippedDrawable";
32
33 private ClippedMatrixState mClippedMatrixState;
34
35 public static final Property<MatrixClippedDrawable, Rect> CLIP_PROPERTY
36 = new Property<MatrixClippedDrawable, Rect>(Rect.class, "clipRect") {
37
38 @Override
39 public Rect get(MatrixClippedDrawable object) {
40 return object.getClipRect();
41 }
42
43 @Override
44 public void set(MatrixClippedDrawable object, Rect value) {
45 object.setClipRect(value);
46 }
47 };
48
49 public static final Property<MatrixClippedDrawable, Matrix> MATRIX_PROPERTY
50 = new Property<MatrixClippedDrawable, Matrix>(Matrix.class, "matrix") {
51 @Override
52 public void set(MatrixClippedDrawable object, Matrix value) {
53 object.setMatrix(value);
54 }
55
56 @Override
57 public Matrix get(MatrixClippedDrawable object) {
58 return object.getMatrix();
59 }
60 };
61
62 public MatrixClippedDrawable(Drawable drawable) {
63 this(null, null);
64
65 mClippedMatrixState.mDrawable = drawable;
66
67 if (drawable != null) {
68 drawable.setCallback(this);
69 }
70 }
71
72 public void setMatrix(Matrix matrix) {
73 if (matrix == null) {
74 mClippedMatrixState.mMatrix = null;
75 } else {
76 if (mClippedMatrixState.mMatrix == null) {
77 mClippedMatrixState.mMatrix = new Matrix();
78 }
79 mClippedMatrixState.mMatrix.set(matrix);
80 }
81 invalidateSelf();
82 }
83
84 public Matrix getMatrix() {
85 return mClippedMatrixState.mMatrix;
86 }
87
88 public Rect getClipRect() {
89 return mClippedMatrixState.mClipRect;
90 }
91
92 public void setClipRect(Rect clipRect) {
93 if (clipRect == null) {
94 if (mClippedMatrixState.mClipRect != null) {
95 mClippedMatrixState.mClipRect = null;
96 invalidateSelf();
97 }
98 } else {
99 if (mClippedMatrixState.mClipRect == null) {
100 mClippedMatrixState.mClipRect = new Rect(clipRect);
101 } else {
102 mClippedMatrixState.mClipRect.set(clipRect);
103 }
104 invalidateSelf();
105 }
106 }
107
108 // overrides from Drawable.Callback
109
110 public void invalidateDrawable(Drawable who) {
111 final Drawable.Callback callback = getCallback();
112 if (callback != null) {
113 callback.invalidateDrawable(this);
114 }
115 }
116
117 public void scheduleDrawable(Drawable who, Runnable what, long when) {
118 final Drawable.Callback callback = getCallback();
119 if (callback != null) {
120 callback.scheduleDrawable(this, what, when);
121 }
122 }
123
124 public void unscheduleDrawable(Drawable who, Runnable what) {
125 final Drawable.Callback callback = getCallback();
126 if (callback != null) {
127 callback.unscheduleDrawable(this, what);
128 }
129 }
130
131 // overrides from Drawable
132
133 @Override
134 public int getChangingConfigurations() {
135 return super.getChangingConfigurations()
136 | mClippedMatrixState.mChangingConfigurations
137 | mClippedMatrixState.mDrawable.getChangingConfigurations();
138 }
139
140 @Override
141 public boolean getPadding(Rect padding) {
142 // XXX need to adjust padding!
143 return mClippedMatrixState.mDrawable.getPadding(padding);
144 }
145
146 @Override
147 public boolean setVisible(boolean visible, boolean restart) {
148 mClippedMatrixState.mDrawable.setVisible(visible, restart);
149 return super.setVisible(visible, restart);
150 }
151
152 @Override
153 public void setAlpha(int alpha) {
154 mClippedMatrixState.mDrawable.setAlpha(alpha);
155 }
156
157 @Override
158 public int getAlpha() {
159 return mClippedMatrixState.mDrawable.getAlpha();
160 }
161
162 @Override
163 public void setColorFilter(ColorFilter cf) {
164 mClippedMatrixState.mDrawable.setColorFilter(cf);
165 }
166
167 @Override
168 public int getOpacity() {
169 return mClippedMatrixState.mDrawable.getOpacity();
170 }
171
172 @Override
173 public boolean isStateful() {
174 return mClippedMatrixState.mDrawable.isStateful();
175 }
176
177 @Override
178 protected boolean onStateChange(int[] state) {
179 return mClippedMatrixState.mDrawable.setState(state);
180 }
181
182 @Override
183 protected boolean onLevelChange(int level) {
184 mClippedMatrixState.mDrawable.setLevel(level);
185 invalidateSelf();
186 return true;
187 }
188
189 @Override
190 protected void onBoundsChange(Rect bounds) {
191 super.setBounds(bounds);
192 if (mClippedMatrixState.mMatrix == null) {
193 mClippedMatrixState.mDrawable.setBounds(bounds);
194 } else {
195 int drawableWidth = mClippedMatrixState.mDrawable.getIntrinsicWidth();
196 int drawableHeight = mClippedMatrixState.mDrawable.getIntrinsicHeight();
197 mClippedMatrixState.mDrawable.setBounds(bounds.left, bounds.top,
198 drawableWidth + bounds.left, drawableHeight + bounds.top);
199 }
200 invalidateSelf();
201 }
202
203 @Override
204 public void draw(Canvas canvas) {
205 Rect bounds = getBounds();
206 int left = bounds.left;
207 int top = bounds.top;
208 int saveCount = canvas.getSaveCount();
209 canvas.save();
210 if (mClippedMatrixState.mClipRect != null) {
211 canvas.clipRect(mClippedMatrixState.mClipRect);
212 } else {
213 canvas.clipRect(bounds);
214 }
215
216 if (mClippedMatrixState != null && !mClippedMatrixState.mMatrix.isIdentity()) {
217 canvas.translate(left, top);
218 canvas.concat(mClippedMatrixState.mMatrix);
219 canvas.translate(-left, -top);
220 }
221 mClippedMatrixState.mDrawable.draw(canvas);
222 canvas.restoreToCount(saveCount);
223 }
224
225 @Override
226 public int getIntrinsicWidth() {
227 return mClippedMatrixState.mDrawable.getIntrinsicWidth();
228 }
229
230 @Override
231 public int getIntrinsicHeight() {
232 return mClippedMatrixState.mDrawable.getIntrinsicHeight();
233 }
234
235 @Override
236 public Drawable.ConstantState getConstantState() {
237 if (mClippedMatrixState.canConstantState()) {
238 mClippedMatrixState.mChangingConfigurations = getChangingConfigurations();
239 return mClippedMatrixState;
240 }
241 return null;
242 }
243
244 final static class ClippedMatrixState extends Drawable.ConstantState {
245 Drawable mDrawable;
246 Matrix mMatrix;
247 Rect mClipRect;
248
249 private boolean mCheckedConstantState;
250 private boolean mCanConstantState;
251 int mChangingConfigurations;
252
253 ClippedMatrixState(ClippedMatrixState orig, MatrixClippedDrawable owner, Resources res) {
254 if (orig != null) {
255 if (res != null) {
256 mDrawable = orig.mDrawable.getConstantState().newDrawable(res);
257 } else {
258 mDrawable = orig.mDrawable.getConstantState().newDrawable();
259 }
260 mDrawable.setCallback(owner);
261 mCheckedConstantState = mCanConstantState = true;
262 if (orig.mMatrix != null) {
263 mMatrix = new Matrix(orig.mMatrix);
264 }
265 if (orig.mClipRect != null) {
266 mClipRect = new Rect(orig.mClipRect);
267 }
268 }
269 }
270
271 @Override
272 public Drawable newDrawable() {
273 return new MatrixClippedDrawable(this, null);
274 }
275
276 @Override
277 public Drawable newDrawable(Resources res) {
278 return new MatrixClippedDrawable(this, res);
279 }
280
281 @Override
282 public int getChangingConfigurations() {
283 return mChangingConfigurations;
284 }
285
286 boolean canConstantState() {
287 if (!mCheckedConstantState) {
288 mCanConstantState = mDrawable.getConstantState() != null;
289 mCheckedConstantState = true;
290 }
291
292 return mCanConstantState;
293 }
294 }
295
296 private MatrixClippedDrawable(ClippedMatrixState state, Resources res) {
297 mClippedMatrixState = new ClippedMatrixState(state, this, res);
298 }
299
300}