blob: f05179bb5883af172fc266ae5f2d5a09531fe319 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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 android.widget;
18
Bjorn Bringert0f8555b2009-11-27 12:42:28 +000019import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.Context;
21import android.content.res.Resources;
22import android.content.res.TypedArray;
23import android.graphics.Bitmap;
24import android.graphics.Canvas;
25import android.graphics.ColorFilter;
26import android.graphics.Matrix;
27import android.graphics.PorterDuff;
28import android.graphics.PorterDuffColorFilter;
29import android.graphics.RectF;
Adam Powell31049d72013-10-07 12:58:42 -070030import android.graphics.Xfermode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.drawable.BitmapDrawable;
32import android.graphics.drawable.Drawable;
33import android.net.Uri;
Adam Powell7da4b732012-12-07 15:28:33 -080034import android.os.Build;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070035import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.util.AttributeSet;
37import android.util.Log;
Jeff Sharkey2b95c242010-02-08 17:40:30 -080038import android.view.RemotableViewMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.view.View;
Joe Onoratofd52b182010-11-10 18:00:52 -080040import android.view.ViewDebug;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070041import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -080042import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.widget.RemoteViews.RemoteView;
44
Romain Guy36143942012-12-03 10:10:22 -080045import java.io.IOException;
46import java.io.InputStream;
47
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048/**
49 * Displays an arbitrary image, such as an icon. The ImageView class
50 * can load images from various sources (such as resources or content
51 * providers), takes care of computing its measurement from the image so that
52 * it can be used in any layout manager, and provides various display options
53 * such as scaling and tinting.
54 *
55 * @attr ref android.R.styleable#ImageView_adjustViewBounds
56 * @attr ref android.R.styleable#ImageView_src
57 * @attr ref android.R.styleable#ImageView_maxWidth
58 * @attr ref android.R.styleable#ImageView_maxHeight
59 * @attr ref android.R.styleable#ImageView_tint
60 * @attr ref android.R.styleable#ImageView_scaleType
61 * @attr ref android.R.styleable#ImageView_cropToPadding
62 */
63@RemoteView
64public class ImageView extends View {
65 // settable by the client
66 private Uri mUri;
67 private int mResource = 0;
68 private Matrix mMatrix;
69 private ScaleType mScaleType;
70 private boolean mHaveFrame = false;
71 private boolean mAdjustViewBounds = false;
72 private int mMaxWidth = Integer.MAX_VALUE;
73 private int mMaxHeight = Integer.MAX_VALUE;
74
75 // these are applied to the drawable
76 private ColorFilter mColorFilter;
Adam Powell31049d72013-10-07 12:58:42 -070077 private Xfermode mXfermode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 private int mAlpha = 255;
79 private int mViewAlphaScale = 256;
Jeff Sharkey2b95c242010-02-08 17:40:30 -080080 private boolean mColorMod = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081
82 private Drawable mDrawable = null;
83 private int[] mState = null;
84 private boolean mMergeState = false;
85 private int mLevel = 0;
86 private int mDrawableWidth;
87 private int mDrawableHeight;
88 private Matrix mDrawMatrix = null;
89
90 // Avoid allocations...
91 private RectF mTempSrc = new RectF();
92 private RectF mTempDst = new RectF();
93
94 private boolean mCropToPadding;
95
Joe Onoratofd52b182010-11-10 18:00:52 -080096 private int mBaseline = -1;
97 private boolean mBaselineAlignBottom = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098
Adam Powell7da4b732012-12-07 15:28:33 -080099 // AdjustViewBounds behavior will be in compatibility mode for older apps.
100 private boolean mAdjustViewBoundsCompat = false;
101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final ScaleType[] sScaleTypeArray = {
103 ScaleType.MATRIX,
104 ScaleType.FIT_XY,
105 ScaleType.FIT_START,
106 ScaleType.FIT_CENTER,
107 ScaleType.FIT_END,
108 ScaleType.CENTER,
109 ScaleType.CENTER_CROP,
110 ScaleType.CENTER_INSIDE
111 };
112
113 public ImageView(Context context) {
114 super(context);
115 initImageView();
116 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700117
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 public ImageView(Context context, AttributeSet attrs) {
119 this(context, attrs, 0);
120 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 public ImageView(Context context, AttributeSet attrs, int defStyle) {
123 super(context, attrs, defStyle);
124 initImageView();
125
126 TypedArray a = context.obtainStyledAttributes(attrs,
127 com.android.internal.R.styleable.ImageView, defStyle, 0);
128
129 Drawable d = a.getDrawable(com.android.internal.R.styleable.ImageView_src);
130 if (d != null) {
131 setImageDrawable(d);
132 }
133
Joe Onoratofd52b182010-11-10 18:00:52 -0800134 mBaselineAlignBottom = a.getBoolean(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 com.android.internal.R.styleable.ImageView_baselineAlignBottom, false);
Joe Onoratofd52b182010-11-10 18:00:52 -0800136
137 mBaseline = a.getDimensionPixelSize(
138 com.android.internal.R.styleable.ImageView_baseline, -1);
139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 setAdjustViewBounds(
141 a.getBoolean(com.android.internal.R.styleable.ImageView_adjustViewBounds,
142 false));
143
144 setMaxWidth(a.getDimensionPixelSize(
145 com.android.internal.R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
146
147 setMaxHeight(a.getDimensionPixelSize(
148 com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
149
150 int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
151 if (index >= 0) {
152 setScaleType(sScaleTypeArray[index]);
153 }
154
155 int tint = a.getInt(com.android.internal.R.styleable.ImageView_tint, 0);
156 if (tint != 0) {
Jeff Sharkey2b95c242010-02-08 17:40:30 -0800157 setColorFilter(tint);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 }
159
Chet Haaseba1fe8e2011-10-15 07:35:51 -0700160 int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
161 if (alpha != 255) {
162 setAlpha(alpha);
163 }
164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 mCropToPadding = a.getBoolean(
166 com.android.internal.R.styleable.ImageView_cropToPadding, false);
167
168 a.recycle();
169
170 //need inflate syntax/reader for matrix
171 }
172
173 private void initImageView() {
174 mMatrix = new Matrix();
175 mScaleType = ScaleType.FIT_CENTER;
Adam Powell7da4b732012-12-07 15:28:33 -0800176 mAdjustViewBoundsCompat = mContext.getApplicationInfo().targetSdkVersion <=
177 Build.VERSION_CODES.JELLY_BEAN_MR1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 }
179
180 @Override
181 protected boolean verifyDrawable(Drawable dr) {
182 return mDrawable == dr || super.verifyDrawable(dr);
183 }
184
185 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -0700186 public void jumpDrawablesToCurrentState() {
187 super.jumpDrawablesToCurrentState();
188 if (mDrawable != null) mDrawable.jumpToCurrentState();
189 }
190
191 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 public void invalidateDrawable(Drawable dr) {
193 if (dr == mDrawable) {
194 /* we invalidate the whole view in this case because it's very
195 * hard to know where the drawable actually is. This is made
196 * complicated because of the offsets and transformations that
197 * can be applied. In theory we could get the drawable's bounds
198 * and run them through the transformation and offsets, but this
199 * is probably not worth the effort.
200 */
201 invalidate();
202 } else {
203 super.invalidateDrawable(dr);
204 }
205 }
Joe Onoratofd52b182010-11-10 18:00:52 -0800206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 @Override
Chet Haasedb8c9a62012-03-21 18:54:18 -0700208 public boolean hasOverlappingRendering() {
Michael Jurka0931a852013-03-21 16:07:45 +0100209 return (getBackground() != null && getBackground().getCurrent() != null);
Chet Haasedb8c9a62012-03-21 18:54:18 -0700210 }
211
212 @Override
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700213 public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700214 super.onPopulateAccessibilityEvent(event);
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700215 CharSequence contentDescription = getContentDescription();
216 if (!TextUtils.isEmpty(contentDescription)) {
217 event.getText().add(contentDescription);
218 }
219 }
220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 /**
Philip Milneaac722a2012-03-26 13:30:26 -0700222 * True when ImageView is adjusting its bounds
223 * to preserve the aspect ratio of its drawable
224 *
225 * @return whether to adjust the bounds of this view
226 * to presrve the original aspect ratio of the drawable
227 *
228 * @see #setAdjustViewBounds(boolean)
229 *
230 * @attr ref android.R.styleable#ImageView_adjustViewBounds
231 */
232 public boolean getAdjustViewBounds() {
233 return mAdjustViewBounds;
234 }
235
236 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 * Set this to true if you want the ImageView to adjust its bounds
238 * to preserve the aspect ratio of its drawable.
Adam Powell2c8cc972012-12-07 18:04:51 -0800239 *
240 * <p><strong>Note:</strong> If the application targets API level 17 or lower,
241 * adjustViewBounds will allow the drawable to shrink the view bounds, but not grow
242 * to fill available measured space in all cases. This is for compatibility with
243 * legacy {@link android.view.View.MeasureSpec MeasureSpec} and
244 * {@link android.widget.RelativeLayout RelativeLayout} behavior.</p>
245 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 * @param adjustViewBounds Whether to adjust the bounds of this view
Adam Powell2c8cc972012-12-07 18:04:51 -0800247 * to preserve the original aspect ratio of the drawable.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 *
Philip Milneaac722a2012-03-26 13:30:26 -0700249 * @see #getAdjustViewBounds()
250 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 * @attr ref android.R.styleable#ImageView_adjustViewBounds
252 */
253 @android.view.RemotableViewMethod
254 public void setAdjustViewBounds(boolean adjustViewBounds) {
255 mAdjustViewBounds = adjustViewBounds;
256 if (adjustViewBounds) {
257 setScaleType(ScaleType.FIT_CENTER);
258 }
259 }
Philip Milneaac722a2012-03-26 13:30:26 -0700260
261 /**
262 * The maximum width of this view.
263 *
264 * @return The maximum width of this view
265 *
266 * @see #setMaxWidth(int)
267 *
268 * @attr ref android.R.styleable#ImageView_maxWidth
269 */
270 public int getMaxWidth() {
271 return mMaxWidth;
272 }
273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 /**
275 * An optional argument to supply a maximum width for this view. Only valid if
Romain Guy9fc27812011-04-27 14:21:41 -0700276 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a maximum
277 * of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
278 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
279 * layout params to WRAP_CONTENT.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 *
281 * <p>
282 * Note that this view could be still smaller than 100 x 100 using this approach if the original
283 * image is small. To set an image to a fixed size, specify that size in the layout params and
Romain Guy9fc27812011-04-27 14:21:41 -0700284 * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
285 * the image within the bounds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 * </p>
287 *
288 * @param maxWidth maximum width for this view
Philip Milneaac722a2012-03-26 13:30:26 -0700289 *
290 * @see #getMaxWidth()
291 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 * @attr ref android.R.styleable#ImageView_maxWidth
293 */
294 @android.view.RemotableViewMethod
295 public void setMaxWidth(int maxWidth) {
296 mMaxWidth = maxWidth;
297 }
Philip Milneaac722a2012-03-26 13:30:26 -0700298
299 /**
300 * The maximum height of this view.
301 *
302 * @return The maximum height of this view
303 *
304 * @see #setMaxHeight(int)
305 *
306 * @attr ref android.R.styleable#ImageView_maxHeight
307 */
308 public int getMaxHeight() {
309 return mMaxHeight;
310 }
311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 /**
313 * An optional argument to supply a maximum height for this view. Only valid if
Romain Guy9fc27812011-04-27 14:21:41 -0700314 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a
315 * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
316 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
317 * layout params to WRAP_CONTENT.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 *
319 * <p>
320 * Note that this view could be still smaller than 100 x 100 using this approach if the original
321 * image is small. To set an image to a fixed size, specify that size in the layout params and
Romain Guy9fc27812011-04-27 14:21:41 -0700322 * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
323 * the image within the bounds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 * </p>
325 *
326 * @param maxHeight maximum height for this view
Philip Milneaac722a2012-03-26 13:30:26 -0700327 *
328 * @see #getMaxHeight()
329 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 * @attr ref android.R.styleable#ImageView_maxHeight
331 */
332 @android.view.RemotableViewMethod
333 public void setMaxHeight(int maxHeight) {
334 mMaxHeight = maxHeight;
335 }
336
337 /** Return the view's drawable, or null if no drawable has been
338 assigned.
339 */
340 public Drawable getDrawable() {
341 return mDrawable;
342 }
343
344 /**
345 * Sets a drawable as the content of this ImageView.
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700346 *
347 * <p class="note">This does Bitmap reading and decoding on the UI
348 * thread, which can cause a latency hiccup. If that's a concern,
Romain Guy9fc27812011-04-27 14:21:41 -0700349 * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
350 * {@link #setImageBitmap(android.graphics.Bitmap)} and
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700351 * {@link android.graphics.BitmapFactory} instead.</p>
352 *
Chet Haase430742f2013-04-12 11:18:36 -0700353 * @param resId the resource identifier of the drawable
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700354 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 * @attr ref android.R.styleable#ImageView_src
356 */
357 @android.view.RemotableViewMethod
358 public void setImageResource(int resId) {
359 if (mUri != null || mResource != resId) {
360 updateDrawable(null);
361 mResource = resId;
362 mUri = null;
Adam Powellf96ce022012-08-09 15:08:33 -0700363
364 final int oldWidth = mDrawableWidth;
365 final int oldHeight = mDrawableHeight;
366
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 resolveUri();
Adam Powellf96ce022012-08-09 15:08:33 -0700368
369 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
370 requestLayout();
371 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 invalidate();
373 }
374 }
375
376 /**
377 * Sets the content of this ImageView to the specified Uri.
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700378 *
379 * <p class="note">This does Bitmap reading and decoding on the UI
380 * thread, which can cause a latency hiccup. If that's a concern,
Romain Guy9fc27812011-04-27 14:21:41 -0700381 * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
382 * {@link #setImageBitmap(android.graphics.Bitmap)} and
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700383 * {@link android.graphics.BitmapFactory} instead.</p>
384 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 * @param uri The Uri of an image
386 */
387 @android.view.RemotableViewMethod
388 public void setImageURI(Uri uri) {
389 if (mResource != 0 ||
390 (mUri != uri &&
391 (uri == null || mUri == null || !uri.equals(mUri)))) {
392 updateDrawable(null);
393 mResource = 0;
394 mUri = uri;
Adam Powellf96ce022012-08-09 15:08:33 -0700395
396 final int oldWidth = mDrawableWidth;
397 final int oldHeight = mDrawableHeight;
398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 resolveUri();
Adam Powellf96ce022012-08-09 15:08:33 -0700400
401 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
402 requestLayout();
403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 invalidate();
405 }
406 }
407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 /**
409 * Sets a drawable as the content of this ImageView.
410 *
411 * @param drawable The drawable to set
412 */
413 public void setImageDrawable(Drawable drawable) {
414 if (mDrawable != drawable) {
415 mResource = 0;
416 mUri = null;
Romain Guy9e648c42011-08-17 20:04:27 -0700417
Adam Powellf96ce022012-08-09 15:08:33 -0700418 final int oldWidth = mDrawableWidth;
419 final int oldHeight = mDrawableHeight;
Romain Guy9e648c42011-08-17 20:04:27 -0700420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 updateDrawable(drawable);
Adam Powell2a0e99d2011-08-04 10:55:03 -0700422
Romain Guy9e648c42011-08-17 20:04:27 -0700423 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
Adam Powell2a0e99d2011-08-04 10:55:03 -0700424 requestLayout();
425 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 invalidate();
427 }
428 }
429
430 /**
431 * Sets a Bitmap as the content of this ImageView.
432 *
433 * @param bm The bitmap to set
434 */
435 @android.view.RemotableViewMethod
436 public void setImageBitmap(Bitmap bm) {
437 // if this is used frequently, may handle bitmaps explicitly
438 // to reduce the intermediate drawable object
Dianne Hackborn11ea3342009-07-22 21:48:55 -0700439 setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 }
441
442 public void setImageState(int[] state, boolean merge) {
443 mState = state;
444 mMergeState = merge;
445 if (mDrawable != null) {
446 refreshDrawableState();
447 resizeFromDrawable();
448 }
449 }
450
451 @Override
452 public void setSelected(boolean selected) {
453 super.setSelected(selected);
454 resizeFromDrawable();
455 }
456
The Android Open Source Project4df24232009-03-05 14:34:35 -0800457 /**
458 * Sets the image level, when it is constructed from a
459 * {@link android.graphics.drawable.LevelListDrawable}.
460 *
461 * @param level The new level for the image.
462 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 @android.view.RemotableViewMethod
464 public void setImageLevel(int level) {
465 mLevel = level;
466 if (mDrawable != null) {
467 mDrawable.setLevel(level);
468 resizeFromDrawable();
469 }
470 }
471
472 /**
473 * Options for scaling the bounds of an image to the bounds of this view.
474 */
475 public enum ScaleType {
476 /**
477 * Scale using the image matrix when drawing. The image matrix can be set using
478 * {@link ImageView#setImageMatrix(Matrix)}. From XML, use this syntax:
479 * <code>android:scaleType="matrix"</code>.
480 */
481 MATRIX (0),
482 /**
483 * Scale the image using {@link Matrix.ScaleToFit#FILL}.
484 * From XML, use this syntax: <code>android:scaleType="fitXY"</code>.
485 */
486 FIT_XY (1),
487 /**
488 * Scale the image using {@link Matrix.ScaleToFit#START}.
489 * From XML, use this syntax: <code>android:scaleType="fitStart"</code>.
490 */
491 FIT_START (2),
492 /**
493 * Scale the image using {@link Matrix.ScaleToFit#CENTER}.
494 * From XML, use this syntax:
495 * <code>android:scaleType="fitCenter"</code>.
496 */
497 FIT_CENTER (3),
498 /**
499 * Scale the image using {@link Matrix.ScaleToFit#END}.
500 * From XML, use this syntax: <code>android:scaleType="fitEnd"</code>.
501 */
502 FIT_END (4),
503 /**
504 * Center the image in the view, but perform no scaling.
505 * From XML, use this syntax: <code>android:scaleType="center"</code>.
506 */
507 CENTER (5),
508 /**
509 * Scale the image uniformly (maintain the image's aspect ratio) so
510 * that both dimensions (width and height) of the image will be equal
511 * to or larger than the corresponding dimension of the view
512 * (minus padding). The image is then centered in the view.
513 * From XML, use this syntax: <code>android:scaleType="centerCrop"</code>.
514 */
515 CENTER_CROP (6),
516 /**
517 * Scale the image uniformly (maintain the image's aspect ratio) so
518 * that both dimensions (width and height) of the image will be equal
519 * to or less than the corresponding dimension of the view
520 * (minus padding). The image is then centered in the view.
521 * From XML, use this syntax: <code>android:scaleType="centerInside"</code>.
522 */
523 CENTER_INSIDE (7);
524
525 ScaleType(int ni) {
526 nativeInt = ni;
527 }
528 final int nativeInt;
529 }
530
531 /**
532 * Controls how the image should be resized or moved to match the size
533 * of this ImageView.
534 *
535 * @param scaleType The desired scaling mode.
536 *
537 * @attr ref android.R.styleable#ImageView_scaleType
538 */
539 public void setScaleType(ScaleType scaleType) {
540 if (scaleType == null) {
541 throw new NullPointerException();
542 }
543
544 if (mScaleType != scaleType) {
545 mScaleType = scaleType;
546
547 setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);
548
549 requestLayout();
550 invalidate();
551 }
552 }
553
554 /**
555 * Return the current scale type in use by this ImageView.
556 *
557 * @see ImageView.ScaleType
558 *
559 * @attr ref android.R.styleable#ImageView_scaleType
560 */
561 public ScaleType getScaleType() {
562 return mScaleType;
563 }
564
565 /** Return the view's optional matrix. This is applied to the
John Spurlock0196e562014-02-03 09:00:35 -0500566 view's drawable when it is drawn. If there is no matrix,
Romain Guy53704052013-01-30 16:25:50 -0800567 this method will return an identity matrix.
568 Do not change this matrix in place but make a copy.
569 If you want a different matrix applied to the drawable,
570 be sure to call setImageMatrix().
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 */
572 public Matrix getImageMatrix() {
Dake Gu1ee60172013-01-03 15:11:43 -0800573 if (mDrawMatrix == null) {
Romain Guy53704052013-01-30 16:25:50 -0800574 return new Matrix(Matrix.IDENTITY_MATRIX);
Dake Gu1ee60172013-01-03 15:11:43 -0800575 }
576 return mDrawMatrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578
579 public void setImageMatrix(Matrix matrix) {
580 // collaps null and identity to just null
581 if (matrix != null && matrix.isIdentity()) {
582 matrix = null;
583 }
584
585 // don't invalidate unless we're actually changing our matrix
586 if (matrix == null && !mMatrix.isIdentity() ||
587 matrix != null && !mMatrix.equals(matrix)) {
588 mMatrix.set(matrix);
Chih-Chung Changf8887262009-07-30 15:36:13 +0800589 configureBounds();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 invalidate();
591 }
592 }
Philip Milneaac722a2012-03-26 13:30:26 -0700593
594 /**
595 * Return whether this ImageView crops to padding.
596 *
597 * @return whether this ImageView crops to padding
598 *
599 * @see #setCropToPadding(boolean)
600 *
601 * @attr ref android.R.styleable#ImageView_cropToPadding
602 */
603 public boolean getCropToPadding() {
604 return mCropToPadding;
605 }
606
607 /**
608 * Sets whether this ImageView will crop to padding.
609 *
610 * @param cropToPadding whether this ImageView will crop to padding
611 *
612 * @see #getCropToPadding()
613 *
614 * @attr ref android.R.styleable#ImageView_cropToPadding
615 */
616 public void setCropToPadding(boolean cropToPadding) {
617 if (mCropToPadding != cropToPadding) {
618 mCropToPadding = cropToPadding;
619 requestLayout();
620 invalidate();
621 }
622 }
623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 private void resolveUri() {
625 if (mDrawable != null) {
626 return;
627 }
628
629 Resources rsrc = getResources();
630 if (rsrc == null) {
631 return;
632 }
633
634 Drawable d = null;
635
636 if (mResource != 0) {
637 try {
638 d = rsrc.getDrawable(mResource);
639 } catch (Exception e) {
640 Log.w("ImageView", "Unable to find resource: " + mResource, e);
641 // Don't try again.
642 mUri = null;
643 }
644 } else if (mUri != null) {
Bjorn Bringert0f8555b2009-11-27 12:42:28 +0000645 String scheme = mUri.getScheme();
Bjorn Bringert9d8d9c22010-01-06 22:52:41 +0000646 if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
647 try {
648 // Load drawable through Resources, to get the source density information
649 ContentResolver.OpenResourceIdResult r =
650 mContext.getContentResolver().getResourceId(mUri);
651 d = r.r.getDrawable(r.id);
652 } catch (Exception e) {
653 Log.w("ImageView", "Unable to open content: " + mUri, e);
654 }
655 } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
Bjorn Bringert0f8555b2009-11-27 12:42:28 +0000656 || ContentResolver.SCHEME_FILE.equals(scheme)) {
Romain Guy36143942012-12-03 10:10:22 -0800657 InputStream stream = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 try {
Romain Guy36143942012-12-03 10:10:22 -0800659 stream = mContext.getContentResolver().openInputStream(mUri);
660 d = Drawable.createFromStream(stream, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 } catch (Exception e) {
662 Log.w("ImageView", "Unable to open content: " + mUri, e);
Romain Guy36143942012-12-03 10:10:22 -0800663 } finally {
664 if (stream != null) {
665 try {
666 stream.close();
667 } catch (IOException e) {
668 Log.w("ImageView", "Unable to close content: " + mUri, e);
669 }
670 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 }
Romain Guy36143942012-12-03 10:10:22 -0800672 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 d = Drawable.createFromPath(mUri.toString());
674 }
675
676 if (d == null) {
Romain Guy36143942012-12-03 10:10:22 -0800677 System.out.println("resolveUri failed on bad bitmap uri: " + mUri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 // Don't try again.
679 mUri = null;
680 }
681 } else {
682 return;
683 }
684
685 updateDrawable(d);
686 }
687
688 @Override
689 public int[] onCreateDrawableState(int extraSpace) {
690 if (mState == null) {
691 return super.onCreateDrawableState(extraSpace);
692 } else if (!mMergeState) {
693 return mState;
694 } else {
695 return mergeDrawableStates(
696 super.onCreateDrawableState(extraSpace + mState.length), mState);
697 }
698 }
699
700 private void updateDrawable(Drawable d) {
701 if (mDrawable != null) {
702 mDrawable.setCallback(null);
703 unscheduleDrawable(mDrawable);
704 }
705 mDrawable = d;
706 if (d != null) {
707 d.setCallback(this);
708 if (d.isStateful()) {
709 d.setState(getDrawableState());
710 }
711 d.setLevel(mLevel);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -0700712 d.setLayoutDirection(getLayoutDirection());
Jeff Browne2126ba2013-11-08 13:55:55 -0800713 d.setVisible(getVisibility() == VISIBLE, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 mDrawableWidth = d.getIntrinsicWidth();
715 mDrawableHeight = d.getIntrinsicHeight();
716 applyColorMod();
717 configureBounds();
Romain Guy9e648c42011-08-17 20:04:27 -0700718 } else {
719 mDrawableWidth = mDrawableHeight = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 }
721 }
722
723 private void resizeFromDrawable() {
724 Drawable d = mDrawable;
725 if (d != null) {
726 int w = d.getIntrinsicWidth();
727 if (w < 0) w = mDrawableWidth;
728 int h = d.getIntrinsicHeight();
729 if (h < 0) h = mDrawableHeight;
730 if (w != mDrawableWidth || h != mDrawableHeight) {
731 mDrawableWidth = w;
732 mDrawableHeight = h;
733 requestLayout();
734 }
735 }
736 }
737
Fabrice Di Meglio3f5a90b2013-06-24 19:22:25 -0700738 @Override
739 public void onRtlPropertiesChanged(int layoutDirection) {
740 super.onRtlPropertiesChanged(layoutDirection);
741
742 if (mDrawable != null) {
743 mDrawable.setLayoutDirection(layoutDirection);
744 }
745 }
746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 private static final Matrix.ScaleToFit[] sS2FArray = {
748 Matrix.ScaleToFit.FILL,
749 Matrix.ScaleToFit.START,
750 Matrix.ScaleToFit.CENTER,
751 Matrix.ScaleToFit.END
752 };
753
754 private static Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType st) {
755 // ScaleToFit enum to their corresponding Matrix.ScaleToFit values
756 return sS2FArray[st.nativeInt - 1];
757 }
758
759 @Override
760 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
761 resolveUri();
762 int w;
763 int h;
764
765 // Desired aspect ratio of the view's contents (not including padding)
766 float desiredAspect = 0.0f;
767
768 // We are allowed to change the view's width
769 boolean resizeWidth = false;
770
771 // We are allowed to change the view's height
772 boolean resizeHeight = false;
773
Adam Powell2a0e99d2011-08-04 10:55:03 -0700774 final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
775 final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
776
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 if (mDrawable == null) {
778 // If no drawable, its intrinsic size is 0.
779 mDrawableWidth = -1;
780 mDrawableHeight = -1;
781 w = h = 0;
782 } else {
783 w = mDrawableWidth;
784 h = mDrawableHeight;
785 if (w <= 0) w = 1;
786 if (h <= 0) h = 1;
Romain Guy9e648c42011-08-17 20:04:27 -0700787
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 // We are supposed to adjust view bounds to match the aspect
789 // ratio of our drawable. See if that is possible.
790 if (mAdjustViewBounds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
792 resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
793
Romain Guy9e648c42011-08-17 20:04:27 -0700794 desiredAspect = (float) w / (float) h;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 }
796 }
797
798 int pleft = mPaddingLeft;
799 int pright = mPaddingRight;
800 int ptop = mPaddingTop;
801 int pbottom = mPaddingBottom;
802
803 int widthSize;
804 int heightSize;
805
806 if (resizeWidth || resizeHeight) {
807 /* If we get here, it means we want to resize to match the
808 drawables aspect ratio, and we have the freedom to change at
809 least one dimension.
810 */
811
812 // Get the max possible width given our constraints
Romain Guy9e648c42011-08-17 20:04:27 -0700813 widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);
814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 // Get the max possible height given our constraints
Romain Guy9e648c42011-08-17 20:04:27 -0700816 heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);
817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 if (desiredAspect != 0.0f) {
819 // See what our actual aspect ratio is
820 float actualAspect = (float)(widthSize - pleft - pright) /
821 (heightSize - ptop - pbottom);
822
823 if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
824
825 boolean done = false;
826
827 // Try adjusting width to be proportional to height
828 if (resizeWidth) {
Romain Guy9e648c42011-08-17 20:04:27 -0700829 int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
830 pleft + pright;
Adam Powelld5edc772012-09-26 15:21:39 -0700831
832 // Allow the width to outgrow its original estimate if height is fixed.
Adam Powell7da4b732012-12-07 15:28:33 -0800833 if (!resizeHeight && !mAdjustViewBoundsCompat) {
Adam Powelld5edc772012-09-26 15:21:39 -0700834 widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
835 }
836
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 if (newWidth <= widthSize) {
838 widthSize = newWidth;
839 done = true;
840 }
841 }
842
843 // Try adjusting height to be proportional to width
844 if (!done && resizeHeight) {
Romain Guy9e648c42011-08-17 20:04:27 -0700845 int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
846 ptop + pbottom;
Adam Powelld5edc772012-09-26 15:21:39 -0700847
848 // Allow the height to outgrow its original estimate if width is fixed.
Adam Powell7da4b732012-12-07 15:28:33 -0800849 if (!resizeWidth && !mAdjustViewBoundsCompat) {
Adam Powelld5edc772012-09-26 15:21:39 -0700850 heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
851 heightMeasureSpec);
852 }
853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 if (newHeight <= heightSize) {
855 heightSize = newHeight;
Dianne Hackborn189ee182010-12-02 21:48:53 -0800856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 }
858 }
859 }
860 } else {
861 /* We are either don't want to preserve the drawables aspect ratio,
862 or we are not allowed to change view dimensions. Just measure in
863 the normal way.
864 */
865 w += pleft + pright;
866 h += ptop + pbottom;
867
868 w = Math.max(w, getSuggestedMinimumWidth());
869 h = Math.max(h, getSuggestedMinimumHeight());
870
Dianne Hackborn189ee182010-12-02 21:48:53 -0800871 widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
872 heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 }
874
875 setMeasuredDimension(widthSize, heightSize);
876 }
877
878 private int resolveAdjustedSize(int desiredSize, int maxSize,
879 int measureSpec) {
880 int result = desiredSize;
881 int specMode = MeasureSpec.getMode(measureSpec);
882 int specSize = MeasureSpec.getSize(measureSpec);
883 switch (specMode) {
884 case MeasureSpec.UNSPECIFIED:
885 /* Parent says we can be as big as we want. Just don't be larger
886 than max size imposed on ourselves.
887 */
888 result = Math.min(desiredSize, maxSize);
889 break;
890 case MeasureSpec.AT_MOST:
891 // Parent says we can be as big as we want, up to specSize.
892 // Don't be larger than specSize, and don't be larger than
893 // the max size imposed on ourselves.
894 result = Math.min(Math.min(desiredSize, specSize), maxSize);
895 break;
896 case MeasureSpec.EXACTLY:
897 // No choice. Do what we are told.
898 result = specSize;
899 break;
900 }
901 return result;
902 }
903
904 @Override
905 protected boolean setFrame(int l, int t, int r, int b) {
906 boolean changed = super.setFrame(l, t, r, b);
907 mHaveFrame = true;
908 configureBounds();
909 return changed;
910 }
911
912 private void configureBounds() {
913 if (mDrawable == null || !mHaveFrame) {
914 return;
915 }
916
917 int dwidth = mDrawableWidth;
918 int dheight = mDrawableHeight;
919
920 int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
921 int vheight = getHeight() - mPaddingTop - mPaddingBottom;
922
923 boolean fits = (dwidth < 0 || vwidth == dwidth) &&
924 (dheight < 0 || vheight == dheight);
925
926 if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
927 /* If the drawable has no intrinsic size, or we're told to
928 scaletofit, then we just fill our entire view.
929 */
930 mDrawable.setBounds(0, 0, vwidth, vheight);
931 mDrawMatrix = null;
932 } else {
933 // We need to do the scaling ourself, so have the drawable
934 // use its native size.
935 mDrawable.setBounds(0, 0, dwidth, dheight);
936
937 if (ScaleType.MATRIX == mScaleType) {
938 // Use the specified matrix as-is.
939 if (mMatrix.isIdentity()) {
940 mDrawMatrix = null;
941 } else {
942 mDrawMatrix = mMatrix;
943 }
944 } else if (fits) {
945 // The bitmap fits exactly, no transform needed.
946 mDrawMatrix = null;
947 } else if (ScaleType.CENTER == mScaleType) {
948 // Center bitmap in view, no scaling.
949 mDrawMatrix = mMatrix;
Romain Guyb4938202010-03-15 17:53:37 -0700950 mDrawMatrix.setTranslate((int) ((vwidth - dwidth) * 0.5f + 0.5f),
951 (int) ((vheight - dheight) * 0.5f + 0.5f));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 } else if (ScaleType.CENTER_CROP == mScaleType) {
953 mDrawMatrix = mMatrix;
954
955 float scale;
956 float dx = 0, dy = 0;
957
958 if (dwidth * vheight > vwidth * dheight) {
959 scale = (float) vheight / (float) dheight;
960 dx = (vwidth - dwidth * scale) * 0.5f;
961 } else {
962 scale = (float) vwidth / (float) dwidth;
963 dy = (vheight - dheight * scale) * 0.5f;
964 }
965
966 mDrawMatrix.setScale(scale, scale);
Romain Guyb4938202010-03-15 17:53:37 -0700967 mDrawMatrix.postTranslate((int) (dx + 0.5f), (int) (dy + 0.5f));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 } else if (ScaleType.CENTER_INSIDE == mScaleType) {
969 mDrawMatrix = mMatrix;
970 float scale;
971 float dx;
972 float dy;
973
974 if (dwidth <= vwidth && dheight <= vheight) {
975 scale = 1.0f;
976 } else {
Romain Guy9e648c42011-08-17 20:04:27 -0700977 scale = Math.min((float) vwidth / (float) dwidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 (float) vheight / (float) dheight);
979 }
980
Romain Guyb4938202010-03-15 17:53:37 -0700981 dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f);
982 dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983
984 mDrawMatrix.setScale(scale, scale);
985 mDrawMatrix.postTranslate(dx, dy);
986 } else {
987 // Generate the required transform.
988 mTempSrc.set(0, 0, dwidth, dheight);
989 mTempDst.set(0, 0, vwidth, vheight);
990
991 mDrawMatrix = mMatrix;
Romain Guy9e648c42011-08-17 20:04:27 -0700992 mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 }
994 }
995 }
996
997 @Override
998 protected void drawableStateChanged() {
999 super.drawableStateChanged();
1000 Drawable d = mDrawable;
1001 if (d != null && d.isStateful()) {
1002 d.setState(getDrawableState());
1003 }
1004 }
1005
1006 @Override
1007 protected void onDraw(Canvas canvas) {
1008 super.onDraw(canvas);
1009
1010 if (mDrawable == null) {
1011 return; // couldn't resolve the URI
1012 }
1013
1014 if (mDrawableWidth == 0 || mDrawableHeight == 0) {
1015 return; // nothing to draw (empty bounds)
1016 }
1017
1018 if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
1019 mDrawable.draw(canvas);
1020 } else {
1021 int saveCount = canvas.getSaveCount();
1022 canvas.save();
1023
1024 if (mCropToPadding) {
1025 final int scrollX = mScrollX;
1026 final int scrollY = mScrollY;
1027 canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,
1028 scrollX + mRight - mLeft - mPaddingRight,
1029 scrollY + mBottom - mTop - mPaddingBottom);
1030 }
1031
1032 canvas.translate(mPaddingLeft, mPaddingTop);
1033
1034 if (mDrawMatrix != null) {
1035 canvas.concat(mDrawMatrix);
1036 }
1037 mDrawable.draw(canvas);
1038 canvas.restoreToCount(saveCount);
1039 }
1040 }
1041
Joe Onoratofd52b182010-11-10 18:00:52 -08001042 /**
1043 * <p>Return the offset of the widget's text baseline from the widget's top
1044 * boundary. </p>
1045 *
1046 * @return the offset of the baseline within the widget's bounds or -1
1047 * if baseline alignment is not supported.
1048 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 @Override
Joe Onoratofd52b182010-11-10 18:00:52 -08001050 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 public int getBaseline() {
Joe Onoratofd52b182010-11-10 18:00:52 -08001052 if (mBaselineAlignBottom) {
1053 return getMeasuredHeight();
1054 } else {
1055 return mBaseline;
1056 }
1057 }
1058
1059 /**
1060 * <p>Set the offset of the widget's text baseline from the widget's top
Romain Guy9fc27812011-04-27 14:21:41 -07001061 * boundary. This value is overridden by the {@link #setBaselineAlignBottom(boolean)}
Joe Onoratofd52b182010-11-10 18:00:52 -08001062 * property.</p>
1063 *
1064 * @param baseline The baseline to use, or -1 if none is to be provided.
1065 *
Romain Guy9fc27812011-04-27 14:21:41 -07001066 * @see #setBaseline(int)
Joe Onoratofd52b182010-11-10 18:00:52 -08001067 * @attr ref android.R.styleable#ImageView_baseline
1068 */
1069 public void setBaseline(int baseline) {
1070 if (mBaseline != baseline) {
1071 mBaseline = baseline;
1072 requestLayout();
1073 }
1074 }
1075
1076 /**
1077 * Set whether to set the baseline of this view to the bottom of the view.
1078 * Setting this value overrides any calls to setBaseline.
1079 *
1080 * @param aligned If true, the image view will be baseline aligned with
1081 * based on its bottom edge.
1082 *
1083 * @attr ref android.R.styleable#ImageView_baselineAlignBottom
1084 */
1085 public void setBaselineAlignBottom(boolean aligned) {
1086 if (mBaselineAlignBottom != aligned) {
1087 mBaselineAlignBottom = aligned;
1088 requestLayout();
1089 }
1090 }
1091
1092 /**
1093 * Return whether this view's baseline will be considered the bottom of the view.
1094 *
1095 * @see #setBaselineAlignBottom(boolean)
1096 */
1097 public boolean getBaselineAlignBottom() {
1098 return mBaselineAlignBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001099 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 /**
1102 * Set a tinting option for the image.
1103 *
1104 * @param color Color tint to apply.
1105 * @param mode How to apply the color. The standard mode is
1106 * {@link PorterDuff.Mode#SRC_ATOP}
1107 *
1108 * @attr ref android.R.styleable#ImageView_tint
1109 */
1110 public final void setColorFilter(int color, PorterDuff.Mode mode) {
1111 setColorFilter(new PorterDuffColorFilter(color, mode));
1112 }
1113
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001114 /**
1115 * Set a tinting option for the image. Assumes
1116 * {@link PorterDuff.Mode#SRC_ATOP} blending mode.
1117 *
1118 * @param color Color tint to apply.
1119 * @attr ref android.R.styleable#ImageView_tint
1120 */
1121 @RemotableViewMethod
1122 public final void setColorFilter(int color) {
1123 setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
1124 }
1125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 public final void clearColorFilter() {
1127 setColorFilter(null);
1128 }
Philip Milneaac722a2012-03-26 13:30:26 -07001129
1130 /**
Adam Powell31049d72013-10-07 12:58:42 -07001131 * @hide Candidate for future API inclusion
1132 */
1133 public final void setXfermode(Xfermode mode) {
1134 if (mXfermode != mode) {
1135 mXfermode = mode;
1136 mColorMod = true;
1137 applyColorMod();
1138 invalidate();
1139 }
1140 }
1141
1142 /**
Philip Milneaac722a2012-03-26 13:30:26 -07001143 * Returns the active color filter for this ImageView.
1144 *
1145 * @return the active color filter for this ImageView
1146 *
1147 * @see #setColorFilter(android.graphics.ColorFilter)
1148 */
1149 public ColorFilter getColorFilter() {
1150 return mColorFilter;
1151 }
1152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 /**
1154 * Apply an arbitrary colorfilter to the image.
1155 *
1156 * @param cf the colorfilter to apply (may be null)
Philip Milneaac722a2012-03-26 13:30:26 -07001157 *
1158 * @see #getColorFilter()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 */
1160 public void setColorFilter(ColorFilter cf) {
1161 if (mColorFilter != cf) {
1162 mColorFilter = cf;
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001163 mColorMod = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 applyColorMod();
1165 invalidate();
1166 }
1167 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001168
Philip Milneaac722a2012-03-26 13:30:26 -07001169 /**
1170 * Returns the alpha that will be applied to the drawable of this ImageView.
1171 *
1172 * @return the alpha that will be applied to the drawable of this ImageView
1173 *
1174 * @see #setImageAlpha(int)
1175 */
1176 public int getImageAlpha() {
1177 return mAlpha;
1178 }
1179
1180 /**
1181 * Sets the alpha value that should be applied to the image.
1182 *
1183 * @param alpha the alpha value that should be applied to the image
1184 *
1185 * @see #getImageAlpha()
1186 */
1187 @RemotableViewMethod
1188 public void setImageAlpha(int alpha) {
1189 setAlpha(alpha);
1190 }
1191
1192 /**
1193 * Sets the alpha value that should be applied to the image.
1194 *
1195 * @param alpha the alpha value that should be applied to the image
1196 *
1197 * @deprecated use #setImageAlpha(int) instead
1198 */
1199 @Deprecated
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001200 @RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 public void setAlpha(int alpha) {
1202 alpha &= 0xFF; // keep it legal
1203 if (mAlpha != alpha) {
1204 mAlpha = alpha;
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001205 mColorMod = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 applyColorMod();
1207 invalidate();
1208 }
1209 }
1210
1211 private void applyColorMod() {
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001212 // Only mutate and apply when modifications have occurred. This should
1213 // not reset the mColorMod flag, since these filters need to be
1214 // re-applied if the Drawable is changed.
1215 if (mDrawable != null && mColorMod) {
1216 mDrawable = mDrawable.mutate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 mDrawable.setColorFilter(mColorFilter);
Adam Powell31049d72013-10-07 12:58:42 -07001218 mDrawable.setXfermode(mXfermode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
1220 }
1221 }
Adam Powell37419d72011-11-10 11:32:09 -08001222
Adam Powellb241b4c2011-11-10 19:48:23 -08001223 @RemotableViewMethod
Adam Powell37419d72011-11-10 11:32:09 -08001224 @Override
1225 public void setVisibility(int visibility) {
1226 super.setVisibility(visibility);
1227 if (mDrawable != null) {
1228 mDrawable.setVisible(visibility == VISIBLE, false);
1229 }
1230 }
1231
1232 @Override
Adam Powell6a939ae2011-11-10 14:11:51 -08001233 protected void onAttachedToWindow() {
Adam Powell37419d72011-11-10 11:32:09 -08001234 super.onAttachedToWindow();
1235 if (mDrawable != null) {
1236 mDrawable.setVisible(getVisibility() == VISIBLE, false);
1237 }
1238 }
1239
1240 @Override
Adam Powell6a939ae2011-11-10 14:11:51 -08001241 protected void onDetachedFromWindow() {
Adam Powell37419d72011-11-10 11:32:09 -08001242 super.onDetachedFromWindow();
1243 if (mDrawable != null) {
1244 mDrawable.setVisible(false, false);
1245 }
1246 }
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001247
1248 @Override
1249 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1250 super.onInitializeAccessibilityEvent(event);
1251 event.setClassName(ImageView.class.getName());
1252 }
1253
1254 @Override
1255 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1256 super.onInitializeAccessibilityNodeInfo(info);
1257 info.setClassName(ImageView.class.getName());
1258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259}