blob: be5d2211c67008c9b34536c6c478453f9bcd18b4 [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
Tor Norbye7b9c9122013-05-30 16:48:33 -070019import android.annotation.DrawableRes;
Siva Velusamy94a6d152015-05-05 15:07:00 -070020import android.annotation.NonNull;
Alan Viverette91174362014-06-17 14:51:45 -070021import android.annotation.Nullable;
Jiaquan He1dd48d02017-05-01 14:18:39 -070022import android.annotation.TestApi;
Mathew Inwood978c6e22018-08-21 15:58:55 +010023import android.annotation.UnsupportedAppUsage;
Bjorn Bringert0f8555b2009-11-27 12:42:28 +000024import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.Context;
Alan Viverette91174362014-06-17 14:51:45 -070026import android.content.res.ColorStateList;
Leon Scroggins III046a99e2018-01-31 14:59:29 -050027import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.content.res.TypedArray;
29import android.graphics.Bitmap;
Nader Jawad531db612019-04-14 21:58:04 -070030import android.graphics.BlendMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.Canvas;
32import android.graphics.ColorFilter;
Leon Scroggins III046a99e2018-01-31 14:59:29 -050033import android.graphics.ImageDecoder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.graphics.Matrix;
Alan Viverettee10dd532013-12-12 19:19:51 -080035import android.graphics.PixelFormat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.graphics.PorterDuff;
37import android.graphics.PorterDuffColorFilter;
Alan Viverettee10dd532013-12-12 19:19:51 -080038import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.graphics.RectF;
Adam Powell31049d72013-10-07 12:58:42 -070040import android.graphics.Xfermode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.graphics.drawable.BitmapDrawable;
42import android.graphics.drawable.Drawable;
Dan Sandlera22a3802015-05-13 00:12:47 -040043import android.graphics.drawable.Icon;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.net.Uri;
Adam Powell7da4b732012-12-07 15:28:33 -080045import android.os.Build;
Dan Sandlera22a3802015-05-13 00:12:47 -040046import android.os.Handler;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070047import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.util.AttributeSet;
49import android.util.Log;
Jeff Sharkey2b95c242010-02-08 17:40:30 -080050import android.view.RemotableViewMethod;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.view.View;
Joe Onoratofd52b182010-11-10 18:00:52 -080052import android.view.ViewDebug;
Siva Velusamy94a6d152015-05-05 15:07:00 -070053import android.view.ViewHierarchyEncoder;
Svetoslav Ganov6179ea32011-06-28 01:12:41 -070054import android.view.accessibility.AccessibilityEvent;
Ashley Rose55f9f922019-01-28 19:29:36 -050055import android.view.inspector.InspectableProperty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.widget.RemoteViews.RemoteView;
57
Alan Viverette91174362014-06-17 14:51:45 -070058import com.android.internal.R;
59
Romain Guy36143942012-12-03 10:10:22 -080060import java.io.IOException;
Romain Guy36143942012-12-03 10:10:22 -080061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062/**
Joe Fernandez704d43b2017-04-18 10:35:38 -070063 * Displays image resources, for example {@link android.graphics.Bitmap}
64 * or {@link android.graphics.drawable.Drawable} resources.
65 * ImageView is also commonly used to {@link #setImageTintMode(PorterDuff.Mode)
66 * apply tints to an image} and handle {@link #setScaleType(ScaleType) image scaling}.
67 *
68 * <p>
69 * The following XML snippet is a common example of using an ImageView to display an image resource:
70 * </p>
71 * <pre>
72 * &lt;LinearLayout
73 * xmlns:android="http://schemas.android.com/apk/res/android"
74 * android:layout_width="match_parent"
75 * android:layout_height="match_parent"&gt;
76 * &lt;ImageView
77 * android:layout_width="wrap_content"
78 * android:layout_height="wrap_content"
79 * android:src="@mipmap/ic_launcher"
80 * /&gt;
81 * &lt;/LinearLayout&gt;
82 * </pre>
83 *
84 * <p>
85 * To learn more about Drawables, see: <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.
Laura Davis31756962018-06-18 16:09:32 -070086 * To learn more about working with Bitmaps, see: <a href="{@docRoot}topic/performance/graphics/index.html">Handling Bitmaps</a>.
Joe Fernandez704d43b2017-04-18 10:35:38 -070087 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088 *
89 * @attr ref android.R.styleable#ImageView_adjustViewBounds
90 * @attr ref android.R.styleable#ImageView_src
91 * @attr ref android.R.styleable#ImageView_maxWidth
92 * @attr ref android.R.styleable#ImageView_maxHeight
93 * @attr ref android.R.styleable#ImageView_tint
94 * @attr ref android.R.styleable#ImageView_scaleType
95 * @attr ref android.R.styleable#ImageView_cropToPadding
96 */
97@RemoteView
98public class ImageView extends View {
Alan Viverette6aa92d12015-08-25 13:19:25 -040099 private static final String LOG_TAG = "ImageView";
100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 // settable by the client
Mathew Inwood978c6e22018-08-21 15:58:55 +0100102 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private Uri mUri;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100104 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private int mResource = 0;
106 private Matrix mMatrix;
107 private ScaleType mScaleType;
108 private boolean mHaveFrame = false;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100109 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 private boolean mAdjustViewBounds = false;
Clara Bayarri9e6588d2018-11-27 11:39:58 +0000111 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 private int mMaxWidth = Integer.MAX_VALUE;
Clara Bayarri9e6588d2018-11-27 11:39:58 +0000113 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 private int mMaxHeight = Integer.MAX_VALUE;
115
116 // these are applied to the drawable
Alan Viverette91174362014-06-17 14:51:45 -0700117 private ColorFilter mColorFilter = null;
118 private boolean mHasColorFilter = false;
Adam Powell31049d72013-10-07 12:58:42 -0700119 private Xfermode mXfermode;
Nader Jawade6a63212018-04-20 15:56:10 -0700120 private boolean mHasXfermode = false;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100121 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 private int mAlpha = 255;
Nader Jawade6a63212018-04-20 15:56:10 -0700123 private boolean mHasAlpha = false;
Alan Viverette6aa92d12015-08-25 13:19:25 -0400124 private final int mViewAlphaScale = 256;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
Mathew Inwood978c6e22018-08-21 15:58:55 +0100126 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127 private Drawable mDrawable = null;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100128 @UnsupportedAppUsage
Chris Craik82af13e2015-07-14 13:36:27 -0700129 private BitmapDrawable mRecycleableBitmapDrawable = null;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700130 private ColorStateList mDrawableTintList = null;
Nader Jawad531db612019-04-14 21:58:04 -0700131 private BlendMode mDrawableBlendMode = null;
Alan Viverette91174362014-06-17 14:51:45 -0700132 private boolean mHasDrawableTint = false;
Nader Jawad531db612019-04-14 21:58:04 -0700133 private boolean mHasDrawableBlendMode = false;
Alan Viverette91174362014-06-17 14:51:45 -0700134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 private int[] mState = null;
136 private boolean mMergeState = false;
137 private int mLevel = 0;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100138 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 private int mDrawableWidth;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100140 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 private int mDrawableHeight;
Rahul Ravikumarcd946ba2019-02-08 16:32:40 -0800142 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051687)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 private Matrix mDrawMatrix = null;
144
145 // Avoid allocations...
Alan Viverette6aa92d12015-08-25 13:19:25 -0400146 private final RectF mTempSrc = new RectF();
147 private final RectF mTempDst = new RectF();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
Mathew Inwood978c6e22018-08-21 15:58:55 +0100149 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 private boolean mCropToPadding;
151
Joe Onoratofd52b182010-11-10 18:00:52 -0800152 private int mBaseline = -1;
153 private boolean mBaselineAlignBottom = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154
Adam Powell06f9eb82016-08-24 17:09:01 -0700155 /** Compatibility modes dependent on targetSdkVersion of the app. */
156 private static boolean sCompatDone;
157
158 /** AdjustViewBounds behavior will be in compatibility mode for older apps. */
159 private static boolean sCompatAdjustViewBounds;
Adam Powell7da4b732012-12-07 15:28:33 -0800160
Alan Viverette270a3422015-08-25 13:25:16 -0400161 /** Whether to pass Resources when creating the source from a stream. */
Adam Powell06f9eb82016-08-24 17:09:01 -0700162 private static boolean sCompatUseCorrectStreamDensity;
163
164 /** Whether to use pre-Nougat drawable visibility dispatching conditions. */
165 private static boolean sCompatDrawableVisibilityDispatch;
Alan Viverette270a3422015-08-25 13:25:16 -0400166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 private static final ScaleType[] sScaleTypeArray = {
168 ScaleType.MATRIX,
169 ScaleType.FIT_XY,
170 ScaleType.FIT_START,
171 ScaleType.FIT_CENTER,
172 ScaleType.FIT_END,
173 ScaleType.CENTER,
174 ScaleType.CENTER_CROP,
175 ScaleType.CENTER_INSIDE
176 };
177
178 public ImageView(Context context) {
179 super(context);
180 initImageView();
181 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700182
Scott Kennedy76c382e2015-02-10 23:15:39 -0800183 public ImageView(Context context, @Nullable AttributeSet attrs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 this(context, attrs, 0);
185 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700186
Scott Kennedy76c382e2015-02-10 23:15:39 -0800187 public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
Alan Viverette617feb92013-09-09 18:09:13 -0700188 this(context, attrs, defStyleAttr, 0);
189 }
190
Scott Kennedy76c382e2015-02-10 23:15:39 -0800191 public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
192 int defStyleRes) {
Alan Viverette617feb92013-09-09 18:09:13 -0700193 super(context, attrs, defStyleAttr, defStyleRes);
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 initImageView();
196
Felipe Lemed04a6972017-03-02 12:56:18 -0800197 // ImageView is not important by default, unless app developer overrode attribute.
198 if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
199 setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO);
200 }
201
Alan Viverette617feb92013-09-09 18:09:13 -0700202 final TypedArray a = context.obtainStyledAttributes(
Alan Viverette6aa92d12015-08-25 13:19:25 -0400203 attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);
Aurimas Liutikasab324cf2019-02-07 16:46:38 -0800204 saveAttributeDataForStyleable(context, R.styleable.ImageView,
205 attrs, a, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206
Alan Viverette6aa92d12015-08-25 13:19:25 -0400207 final Drawable d = a.getDrawable(R.styleable.ImageView_src);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 if (d != null) {
209 setImageDrawable(d);
210 }
211
Alan Viverette6aa92d12015-08-25 13:19:25 -0400212 mBaselineAlignBottom = a.getBoolean(R.styleable.ImageView_baselineAlignBottom, false);
213 mBaseline = a.getDimensionPixelSize(R.styleable.ImageView_baseline, -1);
Joe Onoratofd52b182010-11-10 18:00:52 -0800214
Alan Viverette6aa92d12015-08-25 13:19:25 -0400215 setAdjustViewBounds(a.getBoolean(R.styleable.ImageView_adjustViewBounds, false));
216 setMaxWidth(a.getDimensionPixelSize(R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
217 setMaxHeight(a.getDimensionPixelSize(R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
Joe Onoratofd52b182010-11-10 18:00:52 -0800218
Alan Viverette6aa92d12015-08-25 13:19:25 -0400219 final int index = a.getInt(R.styleable.ImageView_scaleType, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 if (index >= 0) {
221 setScaleType(sScaleTypeArray[index]);
222 }
223
Alan Viverette91174362014-06-17 14:51:45 -0700224 if (a.hasValue(R.styleable.ImageView_tint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700225 mDrawableTintList = a.getColorStateList(R.styleable.ImageView_tint);
Alan Viverette91174362014-06-17 14:51:45 -0700226 mHasDrawableTint = true;
227
Alan Viverette38f93bc2014-09-15 16:25:09 -0700228 // Prior to L, this attribute would always set a color filter with
229 // blending mode SRC_ATOP. Preserve that default behavior.
Nader Jawad531db612019-04-14 21:58:04 -0700230 mDrawableBlendMode = BlendMode.SRC_ATOP;
231 mHasDrawableBlendMode = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 }
Alan Viverette91174362014-06-17 14:51:45 -0700233
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700234 if (a.hasValue(R.styleable.ImageView_tintMode)) {
Nader Jawad531db612019-04-14 21:58:04 -0700235 mDrawableBlendMode = Drawable.parseBlendMode(a.getInt(
236 R.styleable.ImageView_tintMode, -1), mDrawableBlendMode);
237 mHasDrawableBlendMode = true;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700238 }
239
240 applyImageTint();
241
Alan Viverette6aa92d12015-08-25 13:19:25 -0400242 final int alpha = a.getInt(R.styleable.ImageView_drawableAlpha, 255);
Chet Haaseba1fe8e2011-10-15 07:35:51 -0700243 if (alpha != 255) {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400244 setImageAlpha(alpha);
Chet Haaseba1fe8e2011-10-15 07:35:51 -0700245 }
246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 mCropToPadding = a.getBoolean(
Alan Viverette6aa92d12015-08-25 13:19:25 -0400248 R.styleable.ImageView_cropToPadding, false);
249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 a.recycle();
251
252 //need inflate syntax/reader for matrix
253 }
254
255 private void initImageView() {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400256 mMatrix = new Matrix();
257 mScaleType = ScaleType.FIT_CENTER;
Alan Viverette270a3422015-08-25 13:25:16 -0400258
Adam Powell06f9eb82016-08-24 17:09:01 -0700259 if (!sCompatDone) {
260 final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
261 sCompatAdjustViewBounds = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
262 sCompatUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
263 sCompatDrawableVisibilityDispatch = targetSdkVersion < Build.VERSION_CODES.N;
264 sCompatDone = true;
265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 }
267
268 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -0500269 protected boolean verifyDrawable(@NonNull Drawable dr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 return mDrawable == dr || super.verifyDrawable(dr);
271 }
Chet Haase8473f5a2015-06-17 14:43:30 -0700272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -0700274 public void jumpDrawablesToCurrentState() {
275 super.jumpDrawablesToCurrentState();
276 if (mDrawable != null) mDrawable.jumpToCurrentState();
277 }
278
279 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -0500280 public void invalidateDrawable(@NonNull Drawable dr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 if (dr == mDrawable) {
Chet Haase8473f5a2015-06-17 14:43:30 -0700282 if (dr != null) {
283 // update cached drawable dimensions if they've changed
284 final int w = dr.getIntrinsicWidth();
285 final int h = dr.getIntrinsicHeight();
286 if (w != mDrawableWidth || h != mDrawableHeight) {
287 mDrawableWidth = w;
288 mDrawableHeight = h;
Alan Viverette01320de2015-10-20 09:48:58 -0400289 // updates the matrix, which is dependent on the bounds
290 configureBounds();
Chet Haase8473f5a2015-06-17 14:43:30 -0700291 }
292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 /* we invalidate the whole view in this case because it's very
294 * hard to know where the drawable actually is. This is made
295 * complicated because of the offsets and transformations that
296 * can be applied. In theory we could get the drawable's bounds
297 * and run them through the transformation and offsets, but this
298 * is probably not worth the effort.
299 */
300 invalidate();
301 } else {
302 super.invalidateDrawable(dr);
303 }
304 }
Joe Onoratofd52b182010-11-10 18:00:52 -0800305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 @Override
Chet Haasedb8c9a62012-03-21 18:54:18 -0700307 public boolean hasOverlappingRendering() {
Michael Jurka0931a852013-03-21 16:07:45 +0100308 return (getBackground() != null && getBackground().getCurrent() != null);
Chet Haasedb8c9a62012-03-21 18:54:18 -0700309 }
310
Alan Viverettea54956a2015-01-07 16:05:02 -0800311 /** @hide */
Chet Haasedb8c9a62012-03-21 18:54:18 -0700312 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800313 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
314 super.onPopulateAccessibilityEventInternal(event);
Alan Viverette6aa92d12015-08-25 13:19:25 -0400315
316 final CharSequence contentDescription = getContentDescription();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700317 if (!TextUtils.isEmpty(contentDescription)) {
318 event.getText().add(contentDescription);
319 }
320 }
321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 /**
Philip Milneaac722a2012-03-26 13:30:26 -0700323 * True when ImageView is adjusting its bounds
324 * to preserve the aspect ratio of its drawable
325 *
326 * @return whether to adjust the bounds of this view
Alan Viverette6aa92d12015-08-25 13:19:25 -0400327 * to preserve the original aspect ratio of the drawable
Philip Milneaac722a2012-03-26 13:30:26 -0700328 *
329 * @see #setAdjustViewBounds(boolean)
330 *
331 * @attr ref android.R.styleable#ImageView_adjustViewBounds
332 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500333 @InspectableProperty
Philip Milneaac722a2012-03-26 13:30:26 -0700334 public boolean getAdjustViewBounds() {
335 return mAdjustViewBounds;
336 }
337
338 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 * Set this to true if you want the ImageView to adjust its bounds
340 * to preserve the aspect ratio of its drawable.
Adam Powell2c8cc972012-12-07 18:04:51 -0800341 *
342 * <p><strong>Note:</strong> If the application targets API level 17 or lower,
343 * adjustViewBounds will allow the drawable to shrink the view bounds, but not grow
344 * to fill available measured space in all cases. This is for compatibility with
345 * legacy {@link android.view.View.MeasureSpec MeasureSpec} and
346 * {@link android.widget.RelativeLayout RelativeLayout} behavior.</p>
347 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 * @param adjustViewBounds Whether to adjust the bounds of this view
Adam Powell2c8cc972012-12-07 18:04:51 -0800349 * to preserve the original aspect ratio of the drawable.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400350 *
Philip Milneaac722a2012-03-26 13:30:26 -0700351 * @see #getAdjustViewBounds()
352 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 * @attr ref android.R.styleable#ImageView_adjustViewBounds
354 */
355 @android.view.RemotableViewMethod
356 public void setAdjustViewBounds(boolean adjustViewBounds) {
357 mAdjustViewBounds = adjustViewBounds;
358 if (adjustViewBounds) {
359 setScaleType(ScaleType.FIT_CENTER);
360 }
361 }
Philip Milneaac722a2012-03-26 13:30:26 -0700362
363 /**
364 * The maximum width of this view.
365 *
366 * @return The maximum width of this view
367 *
368 * @see #setMaxWidth(int)
369 *
370 * @attr ref android.R.styleable#ImageView_maxWidth
371 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500372 @InspectableProperty
Philip Milneaac722a2012-03-26 13:30:26 -0700373 public int getMaxWidth() {
374 return mMaxWidth;
375 }
376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 /**
378 * An optional argument to supply a maximum width for this view. Only valid if
Romain Guy9fc27812011-04-27 14:21:41 -0700379 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a maximum
380 * of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
381 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
382 * layout params to WRAP_CONTENT.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400383 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 * <p>
385 * Note that this view could be still smaller than 100 x 100 using this approach if the original
386 * 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 -0700387 * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
388 * the image within the bounds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 * </p>
Alan Viverette6aa92d12015-08-25 13:19:25 -0400390 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 * @param maxWidth maximum width for this view
Philip Milneaac722a2012-03-26 13:30:26 -0700392 *
393 * @see #getMaxWidth()
394 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 * @attr ref android.R.styleable#ImageView_maxWidth
396 */
397 @android.view.RemotableViewMethod
398 public void setMaxWidth(int maxWidth) {
399 mMaxWidth = maxWidth;
400 }
Philip Milneaac722a2012-03-26 13:30:26 -0700401
402 /**
403 * The maximum height of this view.
404 *
405 * @return The maximum height of this view
406 *
407 * @see #setMaxHeight(int)
408 *
409 * @attr ref android.R.styleable#ImageView_maxHeight
410 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500411 @InspectableProperty
Philip Milneaac722a2012-03-26 13:30:26 -0700412 public int getMaxHeight() {
413 return mMaxHeight;
414 }
415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 /**
417 * An optional argument to supply a maximum height for this view. Only valid if
Romain Guy9fc27812011-04-27 14:21:41 -0700418 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a
419 * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
420 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
421 * layout params to WRAP_CONTENT.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400422 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 * <p>
424 * Note that this view could be still smaller than 100 x 100 using this approach if the original
425 * 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 -0700426 * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
427 * the image within the bounds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 * </p>
Alan Viverette6aa92d12015-08-25 13:19:25 -0400429 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 * @param maxHeight maximum height for this view
Philip Milneaac722a2012-03-26 13:30:26 -0700431 *
432 * @see #getMaxHeight()
433 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 * @attr ref android.R.styleable#ImageView_maxHeight
435 */
436 @android.view.RemotableViewMethod
437 public void setMaxHeight(int maxHeight) {
438 mMaxHeight = maxHeight;
439 }
440
Joe Fernandez704d43b2017-04-18 10:35:38 -0700441 /**
442 * Gets the current Drawable, or null if no Drawable has been
443 * assigned.
444 *
445 * @return the view's drawable, or null if no drawable has been
446 * assigned.
447 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500448 @InspectableProperty(name = "src")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 public Drawable getDrawable() {
Chet Haasebfa11e42015-08-05 21:44:42 -0700450 if (mDrawable == mRecycleableBitmapDrawable) {
451 // Consider our cached version dirty since app code now has a reference to it
452 mRecycleableBitmapDrawable = null;
453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 return mDrawable;
455 }
456
Sunny Goyaldd292f42015-12-02 14:29:27 -0800457 private class ImageDrawableCallback implements Runnable {
458
459 private final Drawable drawable;
460 private final Uri uri;
461 private final int resource;
462
463 ImageDrawableCallback(Drawable drawable, Uri uri, int resource) {
464 this.drawable = drawable;
465 this.uri = uri;
466 this.resource = resource;
467 }
468
469 @Override
470 public void run() {
471 setImageDrawable(drawable);
472 mUri = uri;
473 mResource = resource;
474 }
475 }
476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 /**
478 * Sets a drawable as the content of this ImageView.
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700479 * <p class="note">This does Bitmap reading and decoding on the UI
480 * thread, which can cause a latency hiccup. If that's a concern,
Romain Guy9fc27812011-04-27 14:21:41 -0700481 * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
482 * {@link #setImageBitmap(android.graphics.Bitmap)} and
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700483 * {@link android.graphics.BitmapFactory} instead.</p>
484 *
Chet Haase430742f2013-04-12 11:18:36 -0700485 * @param resId the resource identifier of the drawable
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700486 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 * @attr ref android.R.styleable#ImageView_src
488 */
Sunny Goyaldd292f42015-12-02 14:29:27 -0800489 @android.view.RemotableViewMethod(asyncImpl="setImageResourceAsync")
Tor Norbye7b9c9122013-05-30 16:48:33 -0700490 public void setImageResource(@DrawableRes int resId) {
Alan Viveretted739d7b2014-10-29 17:26:37 -0700491 // The resource configuration may have changed, so we should always
492 // try to load the resource even if the resId hasn't changed.
493 final int oldWidth = mDrawableWidth;
494 final int oldHeight = mDrawableHeight;
Alan Viverette4803bc12014-02-03 14:32:07 -0800495
Alan Viveretted739d7b2014-10-29 17:26:37 -0700496 updateDrawable(null);
497 mResource = resId;
498 mUri = null;
Adam Powellf96ce022012-08-09 15:08:33 -0700499
Alan Viveretted739d7b2014-10-29 17:26:37 -0700500 resolveUri();
Adam Powellf96ce022012-08-09 15:08:33 -0700501
Alan Viveretted739d7b2014-10-29 17:26:37 -0700502 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
503 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 }
Alan Viveretted739d7b2014-10-29 17:26:37 -0700505 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 }
507
Sunny Goyaldd292f42015-12-02 14:29:27 -0800508 /** @hide **/
Mathew Inwood978c6e22018-08-21 15:58:55 +0100509 @UnsupportedAppUsage
Sunny Goyaldd292f42015-12-02 14:29:27 -0800510 public Runnable setImageResourceAsync(@DrawableRes int resId) {
Sunny Goyal5c022632016-02-17 16:30:41 -0800511 Drawable d = null;
512 if (resId != 0) {
513 try {
514 d = getContext().getDrawable(resId);
515 } catch (Exception e) {
516 Log.w(LOG_TAG, "Unable to find resource: " + resId, e);
517 resId = 0;
518 }
519 }
520 return new ImageDrawableCallback(d, null, resId);
Sunny Goyaldd292f42015-12-02 14:29:27 -0800521 }
522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 /**
524 * Sets the content of this ImageView to the specified Uri.
Joe Fernandez704d43b2017-04-18 10:35:38 -0700525 * Note that you use this method to load images from a local Uri only.
526 * <p/>
527 * To learn how to display images from a remote Uri see: <a href="https://developer.android.com/topic/performance/graphics/index.html">Handling Bitmaps</a>
528 * <p/>
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700529 * <p class="note">This does Bitmap reading and decoding on the UI
530 * thread, which can cause a latency hiccup. If that's a concern,
Alan Viverette6ef129e2015-06-30 13:32:27 -0700531 * consider using {@link #setImageDrawable(Drawable)} or
Romain Guy9fc27812011-04-27 14:21:41 -0700532 * {@link #setImageBitmap(android.graphics.Bitmap)} and
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700533 * {@link android.graphics.BitmapFactory} instead.</p>
534 *
Alan Viveretteac21e562016-10-11 17:42:21 -0400535 * <p class="note">On devices running SDK < 24, this method will fail to
536 * apply correct density scaling to images loaded from
537 * {@link ContentResolver#SCHEME_CONTENT content} and
538 * {@link ContentResolver#SCHEME_FILE file} schemes. Applications running
539 * on devices with SDK >= 24 <strong>MUST</strong> specify the
540 * {@code targetSdkVersion} in their manifest as 24 or above for density
541 * scaling to be applied to images loaded from these schemes.</p>
542 *
Alan Viverette6ef129e2015-06-30 13:32:27 -0700543 * @param uri the Uri of an image, or {@code null} to clear the content
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 */
Sunny Goyaldd292f42015-12-02 14:29:27 -0800545 @android.view.RemotableViewMethod(asyncImpl="setImageURIAsync")
Alan Viverette6ef129e2015-06-30 13:32:27 -0700546 public void setImageURI(@Nullable Uri uri) {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400547 if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 updateDrawable(null);
549 mResource = 0;
550 mUri = uri;
Adam Powellf96ce022012-08-09 15:08:33 -0700551
552 final int oldWidth = mDrawableWidth;
553 final int oldHeight = mDrawableHeight;
554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 resolveUri();
Adam Powellf96ce022012-08-09 15:08:33 -0700556
557 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
558 requestLayout();
559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 invalidate();
561 }
562 }
563
Sunny Goyaldd292f42015-12-02 14:29:27 -0800564 /** @hide **/
Mathew Inwood978c6e22018-08-21 15:58:55 +0100565 @UnsupportedAppUsage
Sunny Goyaldd292f42015-12-02 14:29:27 -0800566 public Runnable setImageURIAsync(@Nullable Uri uri) {
567 if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) {
568 Drawable d = uri == null ? null : getDrawableFromUri(uri);
569 if (d == null) {
570 // Do not set the URI if the drawable couldn't be loaded.
571 uri = null;
572 }
573 return new ImageDrawableCallback(d, uri, 0);
574 }
575 return null;
576 }
577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 /**
579 * Sets a drawable as the content of this ImageView.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400580 *
Alan Viverette6ef129e2015-06-30 13:32:27 -0700581 * @param drawable the Drawable to set, or {@code null} to clear the
582 * content
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 */
Alan Viverette6ef129e2015-06-30 13:32:27 -0700584 public void setImageDrawable(@Nullable Drawable drawable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 if (mDrawable != drawable) {
586 mResource = 0;
587 mUri = null;
Romain Guy9e648c42011-08-17 20:04:27 -0700588
Adam Powellf96ce022012-08-09 15:08:33 -0700589 final int oldWidth = mDrawableWidth;
590 final int oldHeight = mDrawableHeight;
Romain Guy9e648c42011-08-17 20:04:27 -0700591
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 updateDrawable(drawable);
Adam Powell2a0e99d2011-08-04 10:55:03 -0700593
Romain Guy9e648c42011-08-17 20:04:27 -0700594 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
Adam Powell2a0e99d2011-08-04 10:55:03 -0700595 requestLayout();
596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 invalidate();
598 }
599 }
600
601 /**
Dan Sandlera22a3802015-05-13 00:12:47 -0400602 * Sets the content of this ImageView to the specified Icon.
603 *
Alan Viverette6ef129e2015-06-30 13:32:27 -0700604 * <p class="note">Depending on the Icon type, this may do Bitmap reading
605 * and decoding on the UI thread, which can cause UI jank. If that's a
606 * concern, consider using
Chris Banese695bb82015-05-14 10:12:20 +0100607 * {@link Icon#loadDrawableAsync(Context, Icon.OnDrawableLoadedListener, Handler)}
Alan Viverette6ef129e2015-06-30 13:32:27 -0700608 * and then {@link #setImageDrawable(android.graphics.drawable.Drawable)}
609 * instead.</p>
Dan Sandlera22a3802015-05-13 00:12:47 -0400610 *
Alan Viverette6ef129e2015-06-30 13:32:27 -0700611 * @param icon an Icon holding the desired image, or {@code null} to clear
612 * the content
Dan Sandlera22a3802015-05-13 00:12:47 -0400613 */
Sunny Goyaldd292f42015-12-02 14:29:27 -0800614 @android.view.RemotableViewMethod(asyncImpl="setImageIconAsync")
Alan Viverette6ef129e2015-06-30 13:32:27 -0700615 public void setImageIcon(@Nullable Icon icon) {
616 setImageDrawable(icon == null ? null : icon.loadDrawable(mContext));
Dan Sandlera22a3802015-05-13 00:12:47 -0400617 }
618
Sunny Goyaldd292f42015-12-02 14:29:27 -0800619 /** @hide **/
620 public Runnable setImageIconAsync(@Nullable Icon icon) {
621 return new ImageDrawableCallback(icon == null ? null : icon.loadDrawable(mContext), null, 0);
622 }
623
Dan Sandlera22a3802015-05-13 00:12:47 -0400624 /**
Alan Viverette91174362014-06-17 14:51:45 -0700625 * Applies a tint to the image drawable. Does not modify the current tint
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700626 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -0700627 * <p>
628 * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
629 * mutate the drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700630 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette2b4e14c2016-07-21 16:25:13 -0400631 * <p>
632 * <em>Note:</em> The default tint mode used by this setter is NOT
633 * consistent with the default tint mode used by the
634 * {@link android.R.styleable#ImageView_tint android:tint}
635 * attribute. If the {@code android:tint} attribute is specified, the
636 * default tint mode will be set to {@link PorterDuff.Mode#SRC_ATOP} to
637 * ensure consistency with earlier versions of the platform.
Alan Viverette91174362014-06-17 14:51:45 -0700638 *
639 * @param tint the tint to apply, may be {@code null} to clear tint
640 *
641 * @attr ref android.R.styleable#ImageView_tint
Alan Viverettea4264452014-07-28 16:02:55 -0700642 * @see #getImageTintList()
643 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700644 */
Alan Viverettea4264452014-07-28 16:02:55 -0700645 public void setImageTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700646 mDrawableTintList = tint;
Alan Viverette4f64c042014-07-21 17:49:13 -0700647 mHasDrawableTint = true;
648
Alan Viverettea4264452014-07-28 16:02:55 -0700649 applyImageTint();
Alan Viverette91174362014-06-17 14:51:45 -0700650 }
651
652 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -0700653 * Get the current {@link android.content.res.ColorStateList} used to tint the image Drawable,
654 * or null if no tint is applied.
655 *
Alan Viverette91174362014-06-17 14:51:45 -0700656 * @return the tint applied to the image drawable
657 * @attr ref android.R.styleable#ImageView_tint
Alan Viverettea4264452014-07-28 16:02:55 -0700658 * @see #setImageTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700659 */
660 @Nullable
Ashley Rose55f9f922019-01-28 19:29:36 -0500661 @InspectableProperty(name = "tint")
Alan Viverettea4264452014-07-28 16:02:55 -0700662 public ColorStateList getImageTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700663 return mDrawableTintList;
Alan Viverette91174362014-06-17 14:51:45 -0700664 }
665
666 /**
667 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -0700668 * {@link #setImageTintList(ColorStateList)}} to the image drawable. The default
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700669 * mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -0700670 *
671 * @param tintMode the blending mode used to apply the tint, may be
672 * {@code null} to clear tint
673 * @attr ref android.R.styleable#ImageView_tintMode
Alan Viverettea4264452014-07-28 16:02:55 -0700674 * @see #getImageTintMode()
675 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700676 */
Alan Viverettea4264452014-07-28 16:02:55 -0700677 public void setImageTintMode(@Nullable PorterDuff.Mode tintMode) {
Nader Jawad531db612019-04-14 21:58:04 -0700678 setImageTintBlendMode(tintMode != null ? BlendMode.fromValue(tintMode.nativeInt) : null);
679 }
680
681 /**
682 * Specifies the blending mode used to apply the tint specified by
683 * {@link #setImageTintList(ColorStateList)}} to the image drawable. The default
684 * mode is {@link BlendMode#SRC_IN}.
685 *
686 * @param blendMode the blending mode used to apply the tint, may be
687 * {@code null} to clear tint
688 * @attr ref android.R.styleable#ImageView_tintMode
689 * @see #getImageTintMode()
690 * @see Drawable#setTintBlendMode(BlendMode)
691 */
692 public void setImageTintBlendMode(@Nullable BlendMode blendMode) {
693 mDrawableBlendMode = blendMode;
694 mHasDrawableBlendMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700695
Alan Viverettea4264452014-07-28 16:02:55 -0700696 applyImageTint();
Alan Viverette91174362014-06-17 14:51:45 -0700697 }
698
699 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -0700700 * Gets the blending mode used to apply the tint to the image Drawable
701 * @return the blending mode used to apply the tint to the image Drawable
Alan Viverette91174362014-06-17 14:51:45 -0700702 * @attr ref android.R.styleable#ImageView_tintMode
Alan Viverettea4264452014-07-28 16:02:55 -0700703 * @see #setImageTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700704 */
705 @Nullable
Ashley Rose55f9f922019-01-28 19:29:36 -0500706 @InspectableProperty(name = "tintMode")
Alan Viverettea4264452014-07-28 16:02:55 -0700707 public PorterDuff.Mode getImageTintMode() {
Nader Jawad531db612019-04-14 21:58:04 -0700708 return mDrawableBlendMode != null
709 ? BlendMode.blendModeToPorterDuffMode(mDrawableBlendMode) : null;
710 }
711
712 /**
713 * Gets the blending mode used to apply the tint to the image Drawable
714 * @return the blending mode used to apply the tint to the image Drawable
715 * @attr ref android.R.styleable#ImageView_tintMode
716 * @see #setImageTintBlendMode(BlendMode)
717 */
718 @Nullable
719 @InspectableProperty(name = "blendMode", attributeId = android.R.styleable.ImageView_tintMode)
720 public BlendMode getImageTintBlendMode() {
721 return mDrawableBlendMode;
Alan Viverette91174362014-06-17 14:51:45 -0700722 }
723
Alan Viverettea4264452014-07-28 16:02:55 -0700724 private void applyImageTint() {
Nader Jawad531db612019-04-14 21:58:04 -0700725 if (mDrawable != null && (mHasDrawableTint || mHasDrawableBlendMode)) {
Alan Viverette91174362014-06-17 14:51:45 -0700726 mDrawable = mDrawable.mutate();
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700727
728 if (mHasDrawableTint) {
729 mDrawable.setTintList(mDrawableTintList);
730 }
731
Nader Jawad531db612019-04-14 21:58:04 -0700732 if (mHasDrawableBlendMode) {
733 mDrawable.setTintBlendMode(mDrawableBlendMode);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700734 }
Alan Viveretted5133792014-10-28 14:41:36 -0700735
736 // The drawable (or one of its children) may not have been
737 // stateful before applying the tint, so let's try again.
738 if (mDrawable.isStateful()) {
739 mDrawable.setState(getDrawableState());
740 }
Alan Viverette91174362014-06-17 14:51:45 -0700741 }
742 }
743
744 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 * Sets a Bitmap as the content of this ImageView.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400746 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 * @param bm The bitmap to set
748 */
749 @android.view.RemotableViewMethod
750 public void setImageBitmap(Bitmap bm) {
John Reck5a135692015-07-10 10:02:58 -0700751 // Hacky fix to force setImageDrawable to do a full setImageDrawable
752 // instead of doing an object reference comparison
753 mDrawable = null;
754 if (mRecycleableBitmapDrawable == null) {
Chris Craik82af13e2015-07-14 13:36:27 -0700755 mRecycleableBitmapDrawable = new BitmapDrawable(mContext.getResources(), bm);
John Reckb7ba1222015-07-09 17:37:34 -0700756 } else {
John Reck5a135692015-07-10 10:02:58 -0700757 mRecycleableBitmapDrawable.setBitmap(bm);
John Reckb7ba1222015-07-09 17:37:34 -0700758 }
John Reck5a135692015-07-10 10:02:58 -0700759 setImageDrawable(mRecycleableBitmapDrawable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 }
761
Joe Fernandez704d43b2017-04-18 10:35:38 -0700762 /**
763 * Set the state of the current {@link android.graphics.drawable.StateListDrawable}.
764 * For more information about State List Drawables, see: <a href="https://developer.android.com/guide/topics/resources/drawable-resource.html#StateList">the Drawable Resource Guide</a>.
765 *
766 * @param state the state to set for the StateListDrawable
767 * @param merge if true, merges the state values for the state you specify into the current state
768 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 public void setImageState(int[] state, boolean merge) {
770 mState = state;
771 mMergeState = merge;
772 if (mDrawable != null) {
773 refreshDrawableState();
774 resizeFromDrawable();
775 }
776 }
777
778 @Override
779 public void setSelected(boolean selected) {
780 super.setSelected(selected);
781 resizeFromDrawable();
782 }
783
The Android Open Source Project4df24232009-03-05 14:34:35 -0800784 /**
Alan Viverette6aa92d12015-08-25 13:19:25 -0400785 * Sets the image level, when it is constructed from a
The Android Open Source Project4df24232009-03-05 14:34:35 -0800786 * {@link android.graphics.drawable.LevelListDrawable}.
787 *
788 * @param level The new level for the image.
789 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 @android.view.RemotableViewMethod
791 public void setImageLevel(int level) {
792 mLevel = level;
793 if (mDrawable != null) {
794 mDrawable.setLevel(level);
795 resizeFromDrawable();
796 }
797 }
798
799 /**
800 * Options for scaling the bounds of an image to the bounds of this view.
801 */
802 public enum ScaleType {
803 /**
804 * Scale using the image matrix when drawing. The image matrix can be set using
805 * {@link ImageView#setImageMatrix(Matrix)}. From XML, use this syntax:
806 * <code>android:scaleType="matrix"</code>.
807 */
808 MATRIX (0),
809 /**
810 * Scale the image using {@link Matrix.ScaleToFit#FILL}.
811 * From XML, use this syntax: <code>android:scaleType="fitXY"</code>.
812 */
813 FIT_XY (1),
814 /**
815 * Scale the image using {@link Matrix.ScaleToFit#START}.
816 * From XML, use this syntax: <code>android:scaleType="fitStart"</code>.
817 */
818 FIT_START (2),
819 /**
820 * Scale the image using {@link Matrix.ScaleToFit#CENTER}.
821 * From XML, use this syntax:
822 * <code>android:scaleType="fitCenter"</code>.
823 */
824 FIT_CENTER (3),
825 /**
826 * Scale the image using {@link Matrix.ScaleToFit#END}.
827 * From XML, use this syntax: <code>android:scaleType="fitEnd"</code>.
828 */
829 FIT_END (4),
830 /**
831 * Center the image in the view, but perform no scaling.
832 * From XML, use this syntax: <code>android:scaleType="center"</code>.
833 */
834 CENTER (5),
835 /**
836 * Scale the image uniformly (maintain the image's aspect ratio) so
837 * that both dimensions (width and height) of the image will be equal
838 * to or larger than the corresponding dimension of the view
839 * (minus padding). The image is then centered in the view.
840 * From XML, use this syntax: <code>android:scaleType="centerCrop"</code>.
841 */
842 CENTER_CROP (6),
843 /**
844 * Scale the image uniformly (maintain the image's aspect ratio) so
845 * that both dimensions (width and height) of the image will be equal
846 * to or less than the corresponding dimension of the view
847 * (minus padding). The image is then centered in the view.
848 * From XML, use this syntax: <code>android:scaleType="centerInside"</code>.
849 */
850 CENTER_INSIDE (7);
Alan Viverette6aa92d12015-08-25 13:19:25 -0400851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 ScaleType(int ni) {
853 nativeInt = ni;
854 }
855 final int nativeInt;
856 }
857
858 /**
859 * Controls how the image should be resized or moved to match the size
860 * of this ImageView.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400861 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 * @param scaleType The desired scaling mode.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400863 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 * @attr ref android.R.styleable#ImageView_scaleType
865 */
866 public void setScaleType(ScaleType scaleType) {
867 if (scaleType == null) {
868 throw new NullPointerException();
869 }
870
871 if (mScaleType != scaleType) {
872 mScaleType = scaleType;
873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 requestLayout();
875 invalidate();
876 }
877 }
Alan Viverette6aa92d12015-08-25 13:19:25 -0400878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -0700880 * Returns the current ScaleType that is used to scale the bounds of an image to the bounds of the ImageView.
881 * @return The ScaleType used to scale the image.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 * @see ImageView.ScaleType
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 * @attr ref android.R.styleable#ImageView_scaleType
884 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500885 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 public ScaleType getScaleType() {
887 return mScaleType;
888 }
889
Joe Fernandez704d43b2017-04-18 10:35:38 -0700890 /** Returns the view's optional matrix. This is applied to the
John Spurlock0196e562014-02-03 09:00:35 -0500891 view's drawable when it is drawn. If there is no matrix,
Romain Guy53704052013-01-30 16:25:50 -0800892 this method will return an identity matrix.
893 Do not change this matrix in place but make a copy.
894 If you want a different matrix applied to the drawable,
895 be sure to call setImageMatrix().
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 */
897 public Matrix getImageMatrix() {
Dake Gu1ee60172013-01-03 15:11:43 -0800898 if (mDrawMatrix == null) {
Romain Guy53704052013-01-30 16:25:50 -0800899 return new Matrix(Matrix.IDENTITY_MATRIX);
Dake Gu1ee60172013-01-03 15:11:43 -0800900 }
901 return mDrawMatrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
903
Joseph Cooperd96fdbd2015-04-03 14:00:31 -0700904 /**
905 * Adds a transformation {@link Matrix} that is applied
906 * to the view's drawable when it is drawn. Allows custom scaling,
907 * translation, and perspective distortion.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400908 *
Joe Fernandez704d43b2017-04-18 10:35:38 -0700909 * @param matrix The transformation parameters in matrix form.
Joseph Cooperd96fdbd2015-04-03 14:00:31 -0700910 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 public void setImageMatrix(Matrix matrix) {
Joseph Cooperd96fdbd2015-04-03 14:00:31 -0700912 // collapse null and identity to just null
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 if (matrix != null && matrix.isIdentity()) {
914 matrix = null;
915 }
Joseph Cooperd96fdbd2015-04-03 14:00:31 -0700916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 // don't invalidate unless we're actually changing our matrix
918 if (matrix == null && !mMatrix.isIdentity() ||
919 matrix != null && !mMatrix.equals(matrix)) {
920 mMatrix.set(matrix);
Chih-Chung Changf8887262009-07-30 15:36:13 +0800921 configureBounds();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922 invalidate();
923 }
924 }
Philip Milneaac722a2012-03-26 13:30:26 -0700925
926 /**
927 * Return whether this ImageView crops to padding.
928 *
929 * @return whether this ImageView crops to padding
930 *
931 * @see #setCropToPadding(boolean)
932 *
933 * @attr ref android.R.styleable#ImageView_cropToPadding
934 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500935 @InspectableProperty
Philip Milneaac722a2012-03-26 13:30:26 -0700936 public boolean getCropToPadding() {
937 return mCropToPadding;
938 }
939
940 /**
941 * Sets whether this ImageView will crop to padding.
942 *
943 * @param cropToPadding whether this ImageView will crop to padding
944 *
945 * @see #getCropToPadding()
946 *
947 * @attr ref android.R.styleable#ImageView_cropToPadding
948 */
949 public void setCropToPadding(boolean cropToPadding) {
950 if (mCropToPadding != cropToPadding) {
951 mCropToPadding = cropToPadding;
952 requestLayout();
953 invalidate();
954 }
955 }
956
Mathew Inwood978c6e22018-08-21 15:58:55 +0100957 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 private void resolveUri() {
959 if (mDrawable != null) {
960 return;
961 }
962
Sunny Goyaldd292f42015-12-02 14:29:27 -0800963 if (getResources() == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 return;
965 }
966
967 Drawable d = null;
968
969 if (mResource != 0) {
970 try {
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800971 d = mContext.getDrawable(mResource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 } catch (Exception e) {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400973 Log.w(LOG_TAG, "Unable to find resource: " + mResource, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 // Don't try again.
Sunny Goyal5c022632016-02-17 16:30:41 -0800975 mResource = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 }
977 } else if (mUri != null) {
Sunny Goyaldd292f42015-12-02 14:29:27 -0800978 d = getDrawableFromUri(mUri);
Alan Viverette6aa92d12015-08-25 13:19:25 -0400979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 if (d == null) {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400981 Log.w(LOG_TAG, "resolveUri failed on bad bitmap uri: " + mUri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 // Don't try again.
983 mUri = null;
984 }
985 } else {
986 return;
987 }
988
989 updateDrawable(d);
990 }
991
Sunny Goyaldd292f42015-12-02 14:29:27 -0800992 private Drawable getDrawableFromUri(Uri uri) {
993 final String scheme = uri.getScheme();
994 if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
995 try {
996 // Load drawable through Resources, to get the source density information
997 ContentResolver.OpenResourceIdResult r =
998 mContext.getContentResolver().getResourceId(uri);
999 return r.r.getDrawable(r.id, mContext.getTheme());
1000 } catch (Exception e) {
1001 Log.w(LOG_TAG, "Unable to open content: " + uri, e);
1002 }
1003 } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
1004 || ContentResolver.SCHEME_FILE.equals(scheme)) {
Sunny Goyaldd292f42015-12-02 14:29:27 -08001005 try {
Leon Scroggins III046a99e2018-01-31 14:59:29 -05001006 Resources res = sCompatUseCorrectStreamDensity ? getResources() : null;
1007 ImageDecoder.Source src = ImageDecoder.createSource(mContext.getContentResolver(),
1008 uri, res);
1009 return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
1010 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
1011 });
1012 } catch (IOException e) {
Sunny Goyaldd292f42015-12-02 14:29:27 -08001013 Log.w(LOG_TAG, "Unable to open content: " + uri, e);
Sunny Goyaldd292f42015-12-02 14:29:27 -08001014 }
1015 } else {
1016 return Drawable.createFromPath(uri.toString());
1017 }
1018 return null;
1019 }
1020
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 @Override
1022 public int[] onCreateDrawableState(int extraSpace) {
1023 if (mState == null) {
1024 return super.onCreateDrawableState(extraSpace);
1025 } else if (!mMergeState) {
1026 return mState;
1027 } else {
1028 return mergeDrawableStates(
1029 super.onCreateDrawableState(extraSpace + mState.length), mState);
1030 }
1031 }
1032
Mathew Inwood978c6e22018-08-21 15:58:55 +01001033 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 private void updateDrawable(Drawable d) {
John Reck5a135692015-07-10 10:02:58 -07001035 if (d != mRecycleableBitmapDrawable && mRecycleableBitmapDrawable != null) {
1036 mRecycleableBitmapDrawable.setBitmap(null);
1037 }
1038
Adam Powell06f9eb82016-08-24 17:09:01 -07001039 boolean sameDrawable = false;
1040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 if (mDrawable != null) {
Adam Powell06f9eb82016-08-24 17:09:01 -07001042 sameDrawable = mDrawable == d;
Adam Powell35e2ea02016-03-22 10:40:29 -07001043 mDrawable.setCallback(null);
1044 unscheduleDrawable(mDrawable);
Adam Powell06f9eb82016-08-24 17:09:01 -07001045 if (!sCompatDrawableVisibilityDispatch && !sameDrawable && isAttachedToWindow()) {
Adam Powell4b2e12c2016-03-31 15:35:35 -07001046 mDrawable.setVisible(false, false);
1047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 }
Alan Viverette91174362014-06-17 14:51:45 -07001049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 mDrawable = d;
Alan Viverette91174362014-06-17 14:51:45 -07001051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 if (d != null) {
1053 d.setCallback(this);
Alan Viverette91174362014-06-17 14:51:45 -07001054 d.setLayoutDirection(getLayoutDirection());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 if (d.isStateful()) {
1056 d.setState(getDrawableState());
1057 }
Adam Powell06f9eb82016-08-24 17:09:01 -07001058 if (!sameDrawable || sCompatDrawableVisibilityDispatch) {
1059 final boolean visible = sCompatDrawableVisibilityDispatch
1060 ? getVisibility() == VISIBLE
1061 : isAttachedToWindow() && getWindowVisibility() == VISIBLE && isShown();
1062 d.setVisible(visible, true);
1063 }
Alan Viverette91174362014-06-17 14:51:45 -07001064 d.setLevel(mLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 mDrawableWidth = d.getIntrinsicWidth();
1066 mDrawableHeight = d.getIntrinsicHeight();
Alan Viverettea4264452014-07-28 16:02:55 -07001067 applyImageTint();
Nader Jawade6a63212018-04-20 15:56:10 -07001068 applyColorFilter();
1069 applyAlpha();
1070 applyXfermode();
Alan Viveretted5133792014-10-28 14:41:36 -07001071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 configureBounds();
Romain Guy9e648c42011-08-17 20:04:27 -07001073 } else {
1074 mDrawableWidth = mDrawableHeight = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 }
1076 }
1077
Mathew Inwood978c6e22018-08-21 15:58:55 +01001078 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001079 private void resizeFromDrawable() {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001080 final Drawable d = mDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 if (d != null) {
1082 int w = d.getIntrinsicWidth();
1083 if (w < 0) w = mDrawableWidth;
1084 int h = d.getIntrinsicHeight();
1085 if (h < 0) h = mDrawableHeight;
1086 if (w != mDrawableWidth || h != mDrawableHeight) {
1087 mDrawableWidth = w;
1088 mDrawableHeight = h;
1089 requestLayout();
1090 }
1091 }
1092 }
1093
Fabrice Di Meglio3f5a90b2013-06-24 19:22:25 -07001094 @Override
1095 public void onRtlPropertiesChanged(int layoutDirection) {
1096 super.onRtlPropertiesChanged(layoutDirection);
1097
1098 if (mDrawable != null) {
1099 mDrawable.setLayoutDirection(layoutDirection);
1100 }
1101 }
1102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 private static final Matrix.ScaleToFit[] sS2FArray = {
1104 Matrix.ScaleToFit.FILL,
1105 Matrix.ScaleToFit.START,
1106 Matrix.ScaleToFit.CENTER,
1107 Matrix.ScaleToFit.END
1108 };
1109
Mathew Inwood978c6e22018-08-21 15:58:55 +01001110 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 private static Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType st) {
1112 // ScaleToFit enum to their corresponding Matrix.ScaleToFit values
1113 return sS2FArray[st.nativeInt - 1];
Alan Viverette6aa92d12015-08-25 13:19:25 -04001114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115
1116 @Override
1117 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1118 resolveUri();
1119 int w;
1120 int h;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001121
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 // Desired aspect ratio of the view's contents (not including padding)
1123 float desiredAspect = 0.0f;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 // We are allowed to change the view's width
1126 boolean resizeWidth = false;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 // We are allowed to change the view's height
1129 boolean resizeHeight = false;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001130
Adam Powell2a0e99d2011-08-04 10:55:03 -07001131 final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
1132 final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
1133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 if (mDrawable == null) {
1135 // If no drawable, its intrinsic size is 0.
1136 mDrawableWidth = -1;
1137 mDrawableHeight = -1;
1138 w = h = 0;
1139 } else {
1140 w = mDrawableWidth;
1141 h = mDrawableHeight;
1142 if (w <= 0) w = 1;
1143 if (h <= 0) h = 1;
Romain Guy9e648c42011-08-17 20:04:27 -07001144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 // We are supposed to adjust view bounds to match the aspect
1146 // ratio of our drawable. See if that is possible.
1147 if (mAdjustViewBounds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
1149 resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001150
Romain Guy9e648c42011-08-17 20:04:27 -07001151 desiredAspect = (float) w / (float) h;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 }
1153 }
Alan Viverette6aa92d12015-08-25 13:19:25 -04001154
1155 final int pleft = mPaddingLeft;
1156 final int pright = mPaddingRight;
1157 final int ptop = mPaddingTop;
1158 final int pbottom = mPaddingBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159
1160 int widthSize;
1161 int heightSize;
1162
1163 if (resizeWidth || resizeHeight) {
1164 /* If we get here, it means we want to resize to match the
1165 drawables aspect ratio, and we have the freedom to change at
Alan Viverette6aa92d12015-08-25 13:19:25 -04001166 least one dimension.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 */
1168
1169 // Get the max possible width given our constraints
Romain Guy9e648c42011-08-17 20:04:27 -07001170 widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);
1171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 // Get the max possible height given our constraints
Romain Guy9e648c42011-08-17 20:04:27 -07001173 heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);
1174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001175 if (desiredAspect != 0.0f) {
1176 // See what our actual aspect ratio is
Alan Viverette6aa92d12015-08-25 13:19:25 -04001177 final float actualAspect = (float)(widthSize - pleft - pright) /
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 (heightSize - ptop - pbottom);
Alan Viverette6aa92d12015-08-25 13:19:25 -04001179
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 boolean done = false;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 // Try adjusting width to be proportional to height
1185 if (resizeWidth) {
Romain Guy9e648c42011-08-17 20:04:27 -07001186 int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
1187 pleft + pright;
Adam Powelld5edc772012-09-26 15:21:39 -07001188
1189 // Allow the width to outgrow its original estimate if height is fixed.
Adam Powell06f9eb82016-08-24 17:09:01 -07001190 if (!resizeHeight && !sCompatAdjustViewBounds) {
Adam Powelld5edc772012-09-26 15:21:39 -07001191 widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
1192 }
1193
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 if (newWidth <= widthSize) {
1195 widthSize = newWidth;
1196 done = true;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001197 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 }
Alan Viverette6aa92d12015-08-25 13:19:25 -04001199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 // Try adjusting height to be proportional to width
1201 if (!done && resizeHeight) {
Romain Guy9e648c42011-08-17 20:04:27 -07001202 int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
1203 ptop + pbottom;
Adam Powelld5edc772012-09-26 15:21:39 -07001204
1205 // Allow the height to outgrow its original estimate if width is fixed.
Adam Powell06f9eb82016-08-24 17:09:01 -07001206 if (!resizeWidth && !sCompatAdjustViewBounds) {
Adam Powelld5edc772012-09-26 15:21:39 -07001207 heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
1208 heightMeasureSpec);
1209 }
1210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 if (newHeight <= heightSize) {
1212 heightSize = newHeight;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001213 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001214 }
1215 }
1216 }
1217 } else {
1218 /* We are either don't want to preserve the drawables aspect ratio,
1219 or we are not allowed to change view dimensions. Just measure in
1220 the normal way.
1221 */
1222 w += pleft + pright;
1223 h += ptop + pbottom;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 w = Math.max(w, getSuggestedMinimumWidth());
1226 h = Math.max(h, getSuggestedMinimumHeight());
1227
Dianne Hackborn189ee182010-12-02 21:48:53 -08001228 widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
1229 heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 }
1231
1232 setMeasuredDimension(widthSize, heightSize);
1233 }
1234
1235 private int resolveAdjustedSize(int desiredSize, int maxSize,
1236 int measureSpec) {
1237 int result = desiredSize;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001238 final int specMode = MeasureSpec.getMode(measureSpec);
1239 final int specSize = MeasureSpec.getSize(measureSpec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 switch (specMode) {
1241 case MeasureSpec.UNSPECIFIED:
1242 /* Parent says we can be as big as we want. Just don't be larger
1243 than max size imposed on ourselves.
1244 */
1245 result = Math.min(desiredSize, maxSize);
1246 break;
1247 case MeasureSpec.AT_MOST:
Alan Viverette6aa92d12015-08-25 13:19:25 -04001248 // Parent says we can be as big as we want, up to specSize.
1249 // Don't be larger than specSize, and don't be larger than
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 // the max size imposed on ourselves.
1251 result = Math.min(Math.min(desiredSize, specSize), maxSize);
1252 break;
1253 case MeasureSpec.EXACTLY:
1254 // No choice. Do what we are told.
1255 result = specSize;
1256 break;
1257 }
1258 return result;
1259 }
1260
1261 @Override
1262 protected boolean setFrame(int l, int t, int r, int b) {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001263 final boolean changed = super.setFrame(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 mHaveFrame = true;
1265 configureBounds();
1266 return changed;
1267 }
1268
1269 private void configureBounds() {
1270 if (mDrawable == null || !mHaveFrame) {
1271 return;
1272 }
1273
Alan Viverette6aa92d12015-08-25 13:19:25 -04001274 final int dwidth = mDrawableWidth;
1275 final int dheight = mDrawableHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276
Alan Viverette6aa92d12015-08-25 13:19:25 -04001277 final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
1278 final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279
Alan Viverette6aa92d12015-08-25 13:19:25 -04001280 final boolean fits = (dwidth < 0 || vwidth == dwidth)
1281 && (dheight < 0 || vheight == dheight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282
1283 if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
1284 /* If the drawable has no intrinsic size, or we're told to
1285 scaletofit, then we just fill our entire view.
1286 */
1287 mDrawable.setBounds(0, 0, vwidth, vheight);
1288 mDrawMatrix = null;
1289 } else {
1290 // We need to do the scaling ourself, so have the drawable
1291 // use its native size.
1292 mDrawable.setBounds(0, 0, dwidth, dheight);
1293
1294 if (ScaleType.MATRIX == mScaleType) {
1295 // Use the specified matrix as-is.
1296 if (mMatrix.isIdentity()) {
1297 mDrawMatrix = null;
1298 } else {
1299 mDrawMatrix = mMatrix;
1300 }
1301 } else if (fits) {
1302 // The bitmap fits exactly, no transform needed.
1303 mDrawMatrix = null;
1304 } else if (ScaleType.CENTER == mScaleType) {
1305 // Center bitmap in view, no scaling.
1306 mDrawMatrix = mMatrix;
Adam Powell14d1f1382015-06-04 12:56:00 -07001307 mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
1308 Math.round((vheight - dheight) * 0.5f));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 } else if (ScaleType.CENTER_CROP == mScaleType) {
1310 mDrawMatrix = mMatrix;
1311
1312 float scale;
1313 float dx = 0, dy = 0;
1314
1315 if (dwidth * vheight > vwidth * dheight) {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001316 scale = (float) vheight / (float) dheight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 dx = (vwidth - dwidth * scale) * 0.5f;
1318 } else {
1319 scale = (float) vwidth / (float) dwidth;
1320 dy = (vheight - dheight * scale) * 0.5f;
1321 }
1322
1323 mDrawMatrix.setScale(scale, scale);
Adam Powell14d1f1382015-06-04 12:56:00 -07001324 mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325 } else if (ScaleType.CENTER_INSIDE == mScaleType) {
1326 mDrawMatrix = mMatrix;
1327 float scale;
1328 float dx;
1329 float dy;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 if (dwidth <= vwidth && dheight <= vheight) {
1332 scale = 1.0f;
1333 } else {
Romain Guy9e648c42011-08-17 20:04:27 -07001334 scale = Math.min((float) vwidth / (float) dwidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 (float) vheight / (float) dheight);
1336 }
Alan Viverette6aa92d12015-08-25 13:19:25 -04001337
Adam Powell14d1f1382015-06-04 12:56:00 -07001338 dx = Math.round((vwidth - dwidth * scale) * 0.5f);
1339 dy = Math.round((vheight - dheight * scale) * 0.5f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340
1341 mDrawMatrix.setScale(scale, scale);
1342 mDrawMatrix.postTranslate(dx, dy);
1343 } else {
1344 // Generate the required transform.
1345 mTempSrc.set(0, 0, dwidth, dheight);
1346 mTempDst.set(0, 0, vwidth, vheight);
Alan Viverette6aa92d12015-08-25 13:19:25 -04001347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 mDrawMatrix = mMatrix;
Romain Guy9e648c42011-08-17 20:04:27 -07001349 mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 }
1351 }
1352 }
1353
1354 @Override
1355 protected void drawableStateChanged() {
1356 super.drawableStateChanged();
Alan Viverette6aa92d12015-08-25 13:19:25 -04001357
Alan Viverettead0020f2015-09-04 10:10:42 -04001358 final Drawable drawable = mDrawable;
1359 if (drawable != null && drawable.isStateful()
1360 && drawable.setState(getDrawableState())) {
1361 invalidateDrawable(drawable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 }
1363 }
1364
Alan Viverettecebc6ba2014-06-13 15:52:13 -07001365 @Override
Alan Viverette8de14942014-06-18 18:05:15 -07001366 public void drawableHotspotChanged(float x, float y) {
1367 super.drawableHotspotChanged(x, y);
Alan Viverettecebc6ba2014-06-13 15:52:13 -07001368
1369 if (mDrawable != null) {
1370 mDrawable.setHotspot(x, y);
1371 }
1372 }
1373
Andrey Kulikov3ac312a2018-11-27 15:52:17 +00001374 /**
1375 * Applies a temporary transformation {@link Matrix} to the view's drawable when it is drawn.
1376 * Allows custom scaling, translation, and perspective distortion during an animation.
1377 *
1378 * This method is a lightweight analogue of {@link ImageView#setImageMatrix(Matrix)} to use
1379 * only during animations as this matrix will be cleared after the next drawable
1380 * update or view's bounds change.
1381 *
1382 * @param matrix The transformation parameters in matrix form.
1383 */
1384 public void animateTransform(@Nullable Matrix matrix) {
George Mountf6c763d2014-09-25 15:13:15 -07001385 if (mDrawable == null) {
1386 return;
1387 }
George Mount990205e2014-06-24 09:36:18 -07001388 if (matrix == null) {
Andrey Kulikov72be9742018-09-28 00:22:42 +01001389 final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
1390 final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
1391 mDrawable.setBounds(0, 0, vwidth, vheight);
Andrey Kulikov3ac312a2018-11-27 15:52:17 +00001392 mDrawMatrix = null;
George Mount990205e2014-06-24 09:36:18 -07001393 } else {
1394 mDrawable.setBounds(0, 0, mDrawableWidth, mDrawableHeight);
1395 if (mDrawMatrix == null) {
1396 mDrawMatrix = new Matrix();
1397 }
1398 mDrawMatrix.set(matrix);
1399 }
1400 invalidate();
1401 }
1402
Alan Viverettecebc6ba2014-06-13 15:52:13 -07001403 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 protected void onDraw(Canvas canvas) {
1405 super.onDraw(canvas);
1406
1407 if (mDrawable == null) {
1408 return; // couldn't resolve the URI
1409 }
1410
1411 if (mDrawableWidth == 0 || mDrawableHeight == 0) {
1412 return; // nothing to draw (empty bounds)
1413 }
1414
1415 if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
1416 mDrawable.draw(canvas);
1417 } else {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001418 final int saveCount = canvas.getSaveCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 canvas.save();
Alan Viverette6aa92d12015-08-25 13:19:25 -04001420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 if (mCropToPadding) {
1422 final int scrollX = mScrollX;
1423 final int scrollY = mScrollY;
1424 canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,
1425 scrollX + mRight - mLeft - mPaddingRight,
1426 scrollY + mBottom - mTop - mPaddingBottom);
1427 }
Alan Viverette6aa92d12015-08-25 13:19:25 -04001428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 canvas.translate(mPaddingLeft, mPaddingTop);
1430
1431 if (mDrawMatrix != null) {
1432 canvas.concat(mDrawMatrix);
1433 }
1434 mDrawable.draw(canvas);
1435 canvas.restoreToCount(saveCount);
1436 }
1437 }
1438
Joe Onoratofd52b182010-11-10 18:00:52 -08001439 /**
1440 * <p>Return the offset of the widget's text baseline from the widget's top
1441 * boundary. </p>
1442 *
1443 * @return the offset of the baseline within the widget's bounds or -1
1444 * if baseline alignment is not supported.
1445 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 @Override
Ashley Rose55f9f922019-01-28 19:29:36 -05001447 @InspectableProperty
Joe Onoratofd52b182010-11-10 18:00:52 -08001448 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001449 public int getBaseline() {
Joe Onoratofd52b182010-11-10 18:00:52 -08001450 if (mBaselineAlignBottom) {
1451 return getMeasuredHeight();
1452 } else {
1453 return mBaseline;
1454 }
1455 }
1456
1457 /**
1458 * <p>Set the offset of the widget's text baseline from the widget's top
Romain Guy9fc27812011-04-27 14:21:41 -07001459 * boundary. This value is overridden by the {@link #setBaselineAlignBottom(boolean)}
Joe Onoratofd52b182010-11-10 18:00:52 -08001460 * property.</p>
1461 *
1462 * @param baseline The baseline to use, or -1 if none is to be provided.
1463 *
Alan Viverette6aa92d12015-08-25 13:19:25 -04001464 * @see #setBaseline(int)
Joe Onoratofd52b182010-11-10 18:00:52 -08001465 * @attr ref android.R.styleable#ImageView_baseline
1466 */
1467 public void setBaseline(int baseline) {
1468 if (mBaseline != baseline) {
1469 mBaseline = baseline;
1470 requestLayout();
1471 }
1472 }
1473
1474 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -07001475 * Sets whether the baseline of this view to the bottom of the view.
Joe Onoratofd52b182010-11-10 18:00:52 -08001476 * Setting this value overrides any calls to setBaseline.
1477 *
Joe Fernandez704d43b2017-04-18 10:35:38 -07001478 * @param aligned If true, the image view will be baseline aligned by its bottom edge.
Joe Onoratofd52b182010-11-10 18:00:52 -08001479 *
1480 * @attr ref android.R.styleable#ImageView_baselineAlignBottom
1481 */
1482 public void setBaselineAlignBottom(boolean aligned) {
1483 if (mBaselineAlignBottom != aligned) {
1484 mBaselineAlignBottom = aligned;
1485 requestLayout();
1486 }
1487 }
1488
1489 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -07001490 * Checks whether this view's baseline is considered the bottom of the view.
Joe Onoratofd52b182010-11-10 18:00:52 -08001491 *
Joe Fernandez704d43b2017-04-18 10:35:38 -07001492 * @return True if the ImageView's baseline is considered the bottom of the view, false if otherwise.
Joe Onoratofd52b182010-11-10 18:00:52 -08001493 * @see #setBaselineAlignBottom(boolean)
1494 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001495 @InspectableProperty
Joe Onoratofd52b182010-11-10 18:00:52 -08001496 public boolean getBaselineAlignBottom() {
1497 return mBaselineAlignBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -07001501 * Sets a tinting option for the image.
Alan Viverette6aa92d12015-08-25 13:19:25 -04001502 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 * @param color Color tint to apply.
1504 * @param mode How to apply the color. The standard mode is
1505 * {@link PorterDuff.Mode#SRC_ATOP}
Alan Viverette6aa92d12015-08-25 13:19:25 -04001506 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 * @attr ref android.R.styleable#ImageView_tint
1508 */
1509 public final void setColorFilter(int color, PorterDuff.Mode mode) {
1510 setColorFilter(new PorterDuffColorFilter(color, mode));
1511 }
1512
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001513 /**
1514 * Set a tinting option for the image. Assumes
1515 * {@link PorterDuff.Mode#SRC_ATOP} blending mode.
1516 *
1517 * @param color Color tint to apply.
1518 * @attr ref android.R.styleable#ImageView_tint
1519 */
1520 @RemotableViewMethod
1521 public final void setColorFilter(int color) {
1522 setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
1523 }
1524
Joe Fernandez704d43b2017-04-18 10:35:38 -07001525 /**
1526 * Removes the image's {@link android.graphics.ColorFilter}.
1527 *
1528 * @see #setColorFilter(int)
1529 * @see #getColorFilter()
1530 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 public final void clearColorFilter() {
1532 setColorFilter(null);
1533 }
Philip Milneaac722a2012-03-26 13:30:26 -07001534
1535 /**
Adam Powell31049d72013-10-07 12:58:42 -07001536 * @hide Candidate for future API inclusion
1537 */
1538 public final void setXfermode(Xfermode mode) {
1539 if (mXfermode != mode) {
1540 mXfermode = mode;
Nader Jawade6a63212018-04-20 15:56:10 -07001541 mHasXfermode = true;
1542 applyXfermode();
Adam Powell31049d72013-10-07 12:58:42 -07001543 invalidate();
1544 }
1545 }
1546
1547 /**
Philip Milneaac722a2012-03-26 13:30:26 -07001548 * Returns the active color filter for this ImageView.
1549 *
1550 * @return the active color filter for this ImageView
1551 *
1552 * @see #setColorFilter(android.graphics.ColorFilter)
1553 */
1554 public ColorFilter getColorFilter() {
1555 return mColorFilter;
1556 }
1557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 /**
1559 * Apply an arbitrary colorfilter to the image.
1560 *
1561 * @param cf the colorfilter to apply (may be null)
Philip Milneaac722a2012-03-26 13:30:26 -07001562 *
1563 * @see #getColorFilter()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 */
1565 public void setColorFilter(ColorFilter cf) {
1566 if (mColorFilter != cf) {
1567 mColorFilter = cf;
Alan Viverette91174362014-06-17 14:51:45 -07001568 mHasColorFilter = true;
Nader Jawade6a63212018-04-20 15:56:10 -07001569 applyColorFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 invalidate();
1571 }
1572 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001573
Philip Milneaac722a2012-03-26 13:30:26 -07001574 /**
1575 * Returns the alpha that will be applied to the drawable of this ImageView.
1576 *
Kevin Hufnaglebdb308a2016-09-23 15:54:42 -07001577 * @return the alpha value that will be applied to the drawable of this
1578 * ImageView (between 0 and 255 inclusive, with 0 being transparent and
1579 * 255 being opaque)
Philip Milneaac722a2012-03-26 13:30:26 -07001580 *
1581 * @see #setImageAlpha(int)
1582 */
1583 public int getImageAlpha() {
1584 return mAlpha;
1585 }
1586
1587 /**
1588 * Sets the alpha value that should be applied to the image.
1589 *
Kevin Hufnaglebdb308a2016-09-23 15:54:42 -07001590 * @param alpha the alpha value that should be applied to the image (between
1591 * 0 and 255 inclusive, with 0 being transparent and 255 being opaque)
Philip Milneaac722a2012-03-26 13:30:26 -07001592 *
1593 * @see #getImageAlpha()
1594 */
1595 @RemotableViewMethod
1596 public void setImageAlpha(int alpha) {
1597 setAlpha(alpha);
1598 }
1599
1600 /**
1601 * Sets the alpha value that should be applied to the image.
1602 *
1603 * @param alpha the alpha value that should be applied to the image
1604 *
1605 * @deprecated use #setImageAlpha(int) instead
1606 */
1607 @Deprecated
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001608 @RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 public void setAlpha(int alpha) {
1610 alpha &= 0xFF; // keep it legal
1611 if (mAlpha != alpha) {
1612 mAlpha = alpha;
Nader Jawade6a63212018-04-20 15:56:10 -07001613 mHasAlpha = true;
1614 applyAlpha();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 invalidate();
1616 }
1617 }
1618
Nader Jawade6a63212018-04-20 15:56:10 -07001619 private void applyXfermode() {
1620 if (mDrawable != null && mHasXfermode) {
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001621 mDrawable = mDrawable.mutate();
Adam Powell31049d72013-10-07 12:58:42 -07001622 mDrawable.setXfermode(mXfermode);
Nader Jawade6a63212018-04-20 15:56:10 -07001623 }
1624 }
1625
1626 private void applyColorFilter() {
1627 if (mDrawable != null && mHasColorFilter) {
1628 mDrawable = mDrawable.mutate();
1629 mDrawable.setColorFilter(mColorFilter);
1630 }
1631 }
1632
1633 private void applyAlpha() {
1634 if (mDrawable != null && mHasAlpha) {
1635 mDrawable = mDrawable.mutate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
1637 }
1638 }
Adam Powell37419d72011-11-10 11:32:09 -08001639
Alan Viverettee10dd532013-12-12 19:19:51 -08001640 @Override
1641 public boolean isOpaque() {
1642 return super.isOpaque() || mDrawable != null && mXfermode == null
1643 && mDrawable.getOpacity() == PixelFormat.OPAQUE
1644 && mAlpha * mViewAlphaScale >> 8 == 255
1645 && isFilledByImage();
1646 }
1647
1648 private boolean isFilledByImage() {
1649 if (mDrawable == null) {
1650 return false;
1651 }
1652
1653 final Rect bounds = mDrawable.getBounds();
1654 final Matrix matrix = mDrawMatrix;
1655 if (matrix == null) {
1656 return bounds.left <= 0 && bounds.top <= 0 && bounds.right >= getWidth()
1657 && bounds.bottom >= getHeight();
1658 } else if (matrix.rectStaysRect()) {
1659 final RectF boundsSrc = mTempSrc;
1660 final RectF boundsDst = mTempDst;
1661 boundsSrc.set(bounds);
1662 matrix.mapRect(boundsDst, boundsSrc);
1663 return boundsDst.left <= 0 && boundsDst.top <= 0 && boundsDst.right >= getWidth()
1664 && boundsDst.bottom >= getHeight();
1665 } else {
1666 // If the matrix doesn't map to a rectangle, assume the worst.
1667 return false;
1668 }
1669 }
1670
Adam Powell37419d72011-11-10 11:32:09 -08001671 @Override
Adam Powell9c146bf2016-03-15 17:35:00 -07001672 public void onVisibilityAggregated(boolean isVisible) {
1673 super.onVisibilityAggregated(isVisible);
Adam Powell06f9eb82016-08-24 17:09:01 -07001674 // Only do this for new apps post-Nougat
1675 if (mDrawable != null && !sCompatDrawableVisibilityDispatch) {
Adam Powell9c146bf2016-03-15 17:35:00 -07001676 mDrawable.setVisible(isVisible, false);
Adam Powell37419d72011-11-10 11:32:09 -08001677 }
1678 }
1679
Adam Powell06f9eb82016-08-24 17:09:01 -07001680 @RemotableViewMethod
1681 @Override
1682 public void setVisibility(int visibility) {
1683 super.setVisibility(visibility);
1684 // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
1685 if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
1686 mDrawable.setVisible(visibility == VISIBLE, false);
1687 }
1688 }
1689
1690 @Override
1691 protected void onAttachedToWindow() {
1692 super.onAttachedToWindow();
1693 // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
1694 if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
1695 mDrawable.setVisible(getVisibility() == VISIBLE, false);
1696 }
1697 }
1698
1699 @Override
1700 protected void onDetachedFromWindow() {
1701 super.onDetachedFromWindow();
1702 // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
1703 if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
1704 mDrawable.setVisible(false, false);
1705 }
1706 }
1707
Adam Powell37419d72011-11-10 11:32:09 -08001708 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08001709 public CharSequence getAccessibilityClassName() {
1710 return ImageView.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001711 }
Siva Velusamy94a6d152015-05-05 15:07:00 -07001712
1713 /** @hide */
1714 @Override
1715 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) {
1716 super.encodeProperties(stream);
1717 stream.addProperty("layout:baseline", getBaseline());
1718 }
Jiaquan He1dd48d02017-05-01 14:18:39 -07001719
1720 /** @hide */
1721 @Override
1722 @TestApi
1723 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) {
1724 final boolean lackFocusState = mDrawable == null || !mDrawable.isStateful()
1725 || !mDrawable.hasFocusStateSpecified();
1726 return super.isDefaultFocusHighlightNeeded(background, foreground) && lackFocusState;
1727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728}