blob: d62b979a2ed347dc575cc2c32111f4f505ce9609 [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.
Kevin Hufnagleb3586942019-08-14 17:50:17 -070065 * ImageView is also commonly used to
66 * <a href="#setImageTintMode(android.graphics.PorterDuff.Mode)">apply tints to an image</a> and
67 * handle <a href="#setScaleType(android.widget.ImageView.ScaleType)">image scaling</a>.
Joe Fernandez704d43b2017-04-18 10:35:38 -070068 *
69 * <p>
70 * The following XML snippet is a common example of using an ImageView to display an image resource:
71 * </p>
72 * <pre>
73 * &lt;LinearLayout
74 * xmlns:android="http://schemas.android.com/apk/res/android"
75 * android:layout_width="match_parent"
76 * android:layout_height="match_parent"&gt;
77 * &lt;ImageView
78 * android:layout_width="wrap_content"
79 * android:layout_height="wrap_content"
Kevin Hufnagleb3586942019-08-14 17:50:17 -070080 * android:src="@drawable/my_image"
81 * android:contentDescription="@string/my_image_description"
Joe Fernandez704d43b2017-04-18 10:35:38 -070082 * /&gt;
83 * &lt;/LinearLayout&gt;
84 * </pre>
85 *
86 * <p>
87 * 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 -070088 * 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 -070089 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 *
91 * @attr ref android.R.styleable#ImageView_adjustViewBounds
92 * @attr ref android.R.styleable#ImageView_src
93 * @attr ref android.R.styleable#ImageView_maxWidth
94 * @attr ref android.R.styleable#ImageView_maxHeight
95 * @attr ref android.R.styleable#ImageView_tint
96 * @attr ref android.R.styleable#ImageView_scaleType
97 * @attr ref android.R.styleable#ImageView_cropToPadding
98 */
99@RemoteView
100public class ImageView extends View {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400101 private static final String LOG_TAG = "ImageView";
102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 // settable by the client
Mathew Inwood978c6e22018-08-21 15:58:55 +0100104 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 private Uri mUri;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100106 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private int mResource = 0;
108 private Matrix mMatrix;
109 private ScaleType mScaleType;
110 private boolean mHaveFrame = false;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100111 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112 private boolean mAdjustViewBounds = false;
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 mMaxWidth = Integer.MAX_VALUE;
Clara Bayarri9e6588d2018-11-27 11:39:58 +0000115 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 private int mMaxHeight = Integer.MAX_VALUE;
117
118 // these are applied to the drawable
Alan Viverette91174362014-06-17 14:51:45 -0700119 private ColorFilter mColorFilter = null;
120 private boolean mHasColorFilter = false;
Adam Powell31049d72013-10-07 12:58:42 -0700121 private Xfermode mXfermode;
Nader Jawade6a63212018-04-20 15:56:10 -0700122 private boolean mHasXfermode = false;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100123 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 private int mAlpha = 255;
Nader Jawade6a63212018-04-20 15:56:10 -0700125 private boolean mHasAlpha = false;
Alan Viverette6aa92d12015-08-25 13:19:25 -0400126 private final int mViewAlphaScale = 256;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127
Mathew Inwood978c6e22018-08-21 15:58:55 +0100128 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 private Drawable mDrawable = null;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100130 @UnsupportedAppUsage
Chris Craik82af13e2015-07-14 13:36:27 -0700131 private BitmapDrawable mRecycleableBitmapDrawable = null;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700132 private ColorStateList mDrawableTintList = null;
Nader Jawad531db612019-04-14 21:58:04 -0700133 private BlendMode mDrawableBlendMode = null;
Alan Viverette91174362014-06-17 14:51:45 -0700134 private boolean mHasDrawableTint = false;
Nader Jawad531db612019-04-14 21:58:04 -0700135 private boolean mHasDrawableBlendMode = false;
Alan Viverette91174362014-06-17 14:51:45 -0700136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 private int[] mState = null;
138 private boolean mMergeState = false;
139 private int mLevel = 0;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100140 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 private int mDrawableWidth;
Mathew Inwood978c6e22018-08-21 15:58:55 +0100142 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 private int mDrawableHeight;
Rahul Ravikumarcd946ba2019-02-08 16:32:40 -0800144 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051687)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 private Matrix mDrawMatrix = null;
146
147 // Avoid allocations...
Alan Viverette6aa92d12015-08-25 13:19:25 -0400148 private final RectF mTempSrc = new RectF();
149 private final RectF mTempDst = new RectF();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150
Mathew Inwood978c6e22018-08-21 15:58:55 +0100151 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 private boolean mCropToPadding;
153
Joe Onoratofd52b182010-11-10 18:00:52 -0800154 private int mBaseline = -1;
155 private boolean mBaselineAlignBottom = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156
Adam Powell06f9eb82016-08-24 17:09:01 -0700157 /** Compatibility modes dependent on targetSdkVersion of the app. */
158 private static boolean sCompatDone;
159
160 /** AdjustViewBounds behavior will be in compatibility mode for older apps. */
161 private static boolean sCompatAdjustViewBounds;
Adam Powell7da4b732012-12-07 15:28:33 -0800162
Alan Viverette270a3422015-08-25 13:25:16 -0400163 /** Whether to pass Resources when creating the source from a stream. */
Adam Powell06f9eb82016-08-24 17:09:01 -0700164 private static boolean sCompatUseCorrectStreamDensity;
165
166 /** Whether to use pre-Nougat drawable visibility dispatching conditions. */
167 private static boolean sCompatDrawableVisibilityDispatch;
Alan Viverette270a3422015-08-25 13:25:16 -0400168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 private static final ScaleType[] sScaleTypeArray = {
170 ScaleType.MATRIX,
171 ScaleType.FIT_XY,
172 ScaleType.FIT_START,
173 ScaleType.FIT_CENTER,
174 ScaleType.FIT_END,
175 ScaleType.CENTER,
176 ScaleType.CENTER_CROP,
177 ScaleType.CENTER_INSIDE
178 };
179
180 public ImageView(Context context) {
181 super(context);
182 initImageView();
183 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700184
Scott Kennedy76c382e2015-02-10 23:15:39 -0800185 public ImageView(Context context, @Nullable AttributeSet attrs) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 this(context, attrs, 0);
187 }
Svetoslav Ganov42138042012-03-20 11:51:39 -0700188
Scott Kennedy76c382e2015-02-10 23:15:39 -0800189 public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
Alan Viverette617feb92013-09-09 18:09:13 -0700190 this(context, attrs, defStyleAttr, 0);
191 }
192
Scott Kennedy76c382e2015-02-10 23:15:39 -0800193 public ImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
194 int defStyleRes) {
Alan Viverette617feb92013-09-09 18:09:13 -0700195 super(context, attrs, defStyleAttr, defStyleRes);
196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 initImageView();
198
Felipe Lemed04a6972017-03-02 12:56:18 -0800199 // ImageView is not important by default, unless app developer overrode attribute.
200 if (getImportantForAutofill() == IMPORTANT_FOR_AUTOFILL_AUTO) {
201 setImportantForAutofill(IMPORTANT_FOR_AUTOFILL_NO);
202 }
203
Alan Viverette617feb92013-09-09 18:09:13 -0700204 final TypedArray a = context.obtainStyledAttributes(
Alan Viverette6aa92d12015-08-25 13:19:25 -0400205 attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);
Aurimas Liutikasab324cf2019-02-07 16:46:38 -0800206 saveAttributeDataForStyleable(context, R.styleable.ImageView,
207 attrs, a, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208
Alan Viverette6aa92d12015-08-25 13:19:25 -0400209 final Drawable d = a.getDrawable(R.styleable.ImageView_src);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 if (d != null) {
211 setImageDrawable(d);
212 }
213
Alan Viverette6aa92d12015-08-25 13:19:25 -0400214 mBaselineAlignBottom = a.getBoolean(R.styleable.ImageView_baselineAlignBottom, false);
215 mBaseline = a.getDimensionPixelSize(R.styleable.ImageView_baseline, -1);
Joe Onoratofd52b182010-11-10 18:00:52 -0800216
Alan Viverette6aa92d12015-08-25 13:19:25 -0400217 setAdjustViewBounds(a.getBoolean(R.styleable.ImageView_adjustViewBounds, false));
218 setMaxWidth(a.getDimensionPixelSize(R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
219 setMaxHeight(a.getDimensionPixelSize(R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
Joe Onoratofd52b182010-11-10 18:00:52 -0800220
Alan Viverette6aa92d12015-08-25 13:19:25 -0400221 final int index = a.getInt(R.styleable.ImageView_scaleType, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 if (index >= 0) {
223 setScaleType(sScaleTypeArray[index]);
224 }
225
Alan Viverette91174362014-06-17 14:51:45 -0700226 if (a.hasValue(R.styleable.ImageView_tint)) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700227 mDrawableTintList = a.getColorStateList(R.styleable.ImageView_tint);
Alan Viverette91174362014-06-17 14:51:45 -0700228 mHasDrawableTint = true;
229
Alan Viverette38f93bc2014-09-15 16:25:09 -0700230 // Prior to L, this attribute would always set a color filter with
231 // blending mode SRC_ATOP. Preserve that default behavior.
Nader Jawad531db612019-04-14 21:58:04 -0700232 mDrawableBlendMode = BlendMode.SRC_ATOP;
233 mHasDrawableBlendMode = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 }
Alan Viverette91174362014-06-17 14:51:45 -0700235
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700236 if (a.hasValue(R.styleable.ImageView_tintMode)) {
Nader Jawad531db612019-04-14 21:58:04 -0700237 mDrawableBlendMode = Drawable.parseBlendMode(a.getInt(
238 R.styleable.ImageView_tintMode, -1), mDrawableBlendMode);
239 mHasDrawableBlendMode = true;
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700240 }
241
242 applyImageTint();
243
Alan Viverette6aa92d12015-08-25 13:19:25 -0400244 final int alpha = a.getInt(R.styleable.ImageView_drawableAlpha, 255);
Chet Haaseba1fe8e2011-10-15 07:35:51 -0700245 if (alpha != 255) {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400246 setImageAlpha(alpha);
Chet Haaseba1fe8e2011-10-15 07:35:51 -0700247 }
248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 mCropToPadding = a.getBoolean(
Alan Viverette6aa92d12015-08-25 13:19:25 -0400250 R.styleable.ImageView_cropToPadding, false);
251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 a.recycle();
253
254 //need inflate syntax/reader for matrix
255 }
256
257 private void initImageView() {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400258 mMatrix = new Matrix();
259 mScaleType = ScaleType.FIT_CENTER;
Alan Viverette270a3422015-08-25 13:25:16 -0400260
Adam Powell06f9eb82016-08-24 17:09:01 -0700261 if (!sCompatDone) {
262 final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
263 sCompatAdjustViewBounds = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
264 sCompatUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
265 sCompatDrawableVisibilityDispatch = targetSdkVersion < Build.VERSION_CODES.N;
266 sCompatDone = true;
267 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 }
269
270 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -0500271 protected boolean verifyDrawable(@NonNull Drawable dr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 return mDrawable == dr || super.verifyDrawable(dr);
273 }
Chet Haase8473f5a2015-06-17 14:43:30 -0700274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -0700276 public void jumpDrawablesToCurrentState() {
277 super.jumpDrawablesToCurrentState();
278 if (mDrawable != null) mDrawable.jumpToCurrentState();
279 }
280
281 @Override
Alan Viverettef6d87ec2016-03-11 10:09:14 -0500282 public void invalidateDrawable(@NonNull Drawable dr) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 if (dr == mDrawable) {
Chet Haase8473f5a2015-06-17 14:43:30 -0700284 if (dr != null) {
285 // update cached drawable dimensions if they've changed
286 final int w = dr.getIntrinsicWidth();
287 final int h = dr.getIntrinsicHeight();
288 if (w != mDrawableWidth || h != mDrawableHeight) {
289 mDrawableWidth = w;
290 mDrawableHeight = h;
Alan Viverette01320de2015-10-20 09:48:58 -0400291 // updates the matrix, which is dependent on the bounds
292 configureBounds();
Chet Haase8473f5a2015-06-17 14:43:30 -0700293 }
294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295 /* we invalidate the whole view in this case because it's very
296 * hard to know where the drawable actually is. This is made
297 * complicated because of the offsets and transformations that
298 * can be applied. In theory we could get the drawable's bounds
299 * and run them through the transformation and offsets, but this
300 * is probably not worth the effort.
301 */
302 invalidate();
303 } else {
304 super.invalidateDrawable(dr);
305 }
306 }
Joe Onoratofd52b182010-11-10 18:00:52 -0800307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 @Override
Chet Haasedb8c9a62012-03-21 18:54:18 -0700309 public boolean hasOverlappingRendering() {
Michael Jurka0931a852013-03-21 16:07:45 +0100310 return (getBackground() != null && getBackground().getCurrent() != null);
Chet Haasedb8c9a62012-03-21 18:54:18 -0700311 }
312
Alan Viverettea54956a2015-01-07 16:05:02 -0800313 /** @hide */
Chet Haasedb8c9a62012-03-21 18:54:18 -0700314 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -0800315 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
316 super.onPopulateAccessibilityEventInternal(event);
Alan Viverette6aa92d12015-08-25 13:19:25 -0400317
318 final CharSequence contentDescription = getContentDescription();
Svetoslav Ganov6179ea32011-06-28 01:12:41 -0700319 if (!TextUtils.isEmpty(contentDescription)) {
320 event.getText().add(contentDescription);
321 }
322 }
323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 /**
Philip Milneaac722a2012-03-26 13:30:26 -0700325 * True when ImageView is adjusting its bounds
326 * to preserve the aspect ratio of its drawable
327 *
328 * @return whether to adjust the bounds of this view
Alan Viverette6aa92d12015-08-25 13:19:25 -0400329 * to preserve the original aspect ratio of the drawable
Philip Milneaac722a2012-03-26 13:30:26 -0700330 *
331 * @see #setAdjustViewBounds(boolean)
332 *
333 * @attr ref android.R.styleable#ImageView_adjustViewBounds
334 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500335 @InspectableProperty
Philip Milneaac722a2012-03-26 13:30:26 -0700336 public boolean getAdjustViewBounds() {
337 return mAdjustViewBounds;
338 }
339
340 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 * Set this to true if you want the ImageView to adjust its bounds
342 * to preserve the aspect ratio of its drawable.
Adam Powell2c8cc972012-12-07 18:04:51 -0800343 *
344 * <p><strong>Note:</strong> If the application targets API level 17 or lower,
345 * adjustViewBounds will allow the drawable to shrink the view bounds, but not grow
346 * to fill available measured space in all cases. This is for compatibility with
347 * legacy {@link android.view.View.MeasureSpec MeasureSpec} and
348 * {@link android.widget.RelativeLayout RelativeLayout} behavior.</p>
349 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 * @param adjustViewBounds Whether to adjust the bounds of this view
Adam Powell2c8cc972012-12-07 18:04:51 -0800351 * to preserve the original aspect ratio of the drawable.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400352 *
Philip Milneaac722a2012-03-26 13:30:26 -0700353 * @see #getAdjustViewBounds()
354 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 * @attr ref android.R.styleable#ImageView_adjustViewBounds
356 */
357 @android.view.RemotableViewMethod
358 public void setAdjustViewBounds(boolean adjustViewBounds) {
359 mAdjustViewBounds = adjustViewBounds;
360 if (adjustViewBounds) {
361 setScaleType(ScaleType.FIT_CENTER);
362 }
363 }
Philip Milneaac722a2012-03-26 13:30:26 -0700364
365 /**
366 * The maximum width of this view.
367 *
368 * @return The maximum width of this view
369 *
370 * @see #setMaxWidth(int)
371 *
372 * @attr ref android.R.styleable#ImageView_maxWidth
373 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500374 @InspectableProperty
Philip Milneaac722a2012-03-26 13:30:26 -0700375 public int getMaxWidth() {
376 return mMaxWidth;
377 }
378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 /**
380 * An optional argument to supply a maximum width for this view. Only valid if
Romain Guy9fc27812011-04-27 14:21:41 -0700381 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a maximum
382 * of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
383 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
384 * layout params to WRAP_CONTENT.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400385 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 * <p>
387 * Note that this view could be still smaller than 100 x 100 using this approach if the original
388 * 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 -0700389 * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
390 * the image within the bounds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 * </p>
Alan Viverette6aa92d12015-08-25 13:19:25 -0400392 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 * @param maxWidth maximum width for this view
Philip Milneaac722a2012-03-26 13:30:26 -0700394 *
395 * @see #getMaxWidth()
396 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 * @attr ref android.R.styleable#ImageView_maxWidth
398 */
399 @android.view.RemotableViewMethod
400 public void setMaxWidth(int maxWidth) {
401 mMaxWidth = maxWidth;
402 }
Philip Milneaac722a2012-03-26 13:30:26 -0700403
404 /**
405 * The maximum height of this view.
406 *
407 * @return The maximum height of this view
408 *
409 * @see #setMaxHeight(int)
410 *
411 * @attr ref android.R.styleable#ImageView_maxHeight
412 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500413 @InspectableProperty
Philip Milneaac722a2012-03-26 13:30:26 -0700414 public int getMaxHeight() {
415 return mMaxHeight;
416 }
417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 /**
419 * An optional argument to supply a maximum height for this view. Only valid if
Romain Guy9fc27812011-04-27 14:21:41 -0700420 * {@link #setAdjustViewBounds(boolean)} has been set to true. To set an image to be a
421 * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
422 * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
423 * layout params to WRAP_CONTENT.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400424 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800425 * <p>
426 * Note that this view could be still smaller than 100 x 100 using this approach if the original
427 * 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 -0700428 * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
429 * the image within the bounds.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 * </p>
Alan Viverette6aa92d12015-08-25 13:19:25 -0400431 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 * @param maxHeight maximum height for this view
Philip Milneaac722a2012-03-26 13:30:26 -0700433 *
434 * @see #getMaxHeight()
435 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 * @attr ref android.R.styleable#ImageView_maxHeight
437 */
438 @android.view.RemotableViewMethod
439 public void setMaxHeight(int maxHeight) {
440 mMaxHeight = maxHeight;
441 }
442
Joe Fernandez704d43b2017-04-18 10:35:38 -0700443 /**
444 * Gets the current Drawable, or null if no Drawable has been
445 * assigned.
446 *
447 * @return the view's drawable, or null if no drawable has been
448 * assigned.
449 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500450 @InspectableProperty(name = "src")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 public Drawable getDrawable() {
Chet Haasebfa11e42015-08-05 21:44:42 -0700452 if (mDrawable == mRecycleableBitmapDrawable) {
453 // Consider our cached version dirty since app code now has a reference to it
454 mRecycleableBitmapDrawable = null;
455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 return mDrawable;
457 }
458
Sunny Goyaldd292f42015-12-02 14:29:27 -0800459 private class ImageDrawableCallback implements Runnable {
460
461 private final Drawable drawable;
462 private final Uri uri;
463 private final int resource;
464
465 ImageDrawableCallback(Drawable drawable, Uri uri, int resource) {
466 this.drawable = drawable;
467 this.uri = uri;
468 this.resource = resource;
469 }
470
471 @Override
472 public void run() {
473 setImageDrawable(drawable);
474 mUri = uri;
475 mResource = resource;
476 }
477 }
478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 /**
480 * Sets a drawable as the content of this ImageView.
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700481 * <p class="note">This does Bitmap reading and decoding on the UI
482 * thread, which can cause a latency hiccup. If that's a concern,
Romain Guy9fc27812011-04-27 14:21:41 -0700483 * consider using {@link #setImageDrawable(android.graphics.drawable.Drawable)} or
484 * {@link #setImageBitmap(android.graphics.Bitmap)} and
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700485 * {@link android.graphics.BitmapFactory} instead.</p>
486 *
Chet Haase430742f2013-04-12 11:18:36 -0700487 * @param resId the resource identifier of the drawable
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700488 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 * @attr ref android.R.styleable#ImageView_src
490 */
Sunny Goyaldd292f42015-12-02 14:29:27 -0800491 @android.view.RemotableViewMethod(asyncImpl="setImageResourceAsync")
Tor Norbye7b9c9122013-05-30 16:48:33 -0700492 public void setImageResource(@DrawableRes int resId) {
Alan Viveretted739d7b2014-10-29 17:26:37 -0700493 // The resource configuration may have changed, so we should always
494 // try to load the resource even if the resId hasn't changed.
495 final int oldWidth = mDrawableWidth;
496 final int oldHeight = mDrawableHeight;
Alan Viverette4803bc12014-02-03 14:32:07 -0800497
Alan Viveretted739d7b2014-10-29 17:26:37 -0700498 updateDrawable(null);
499 mResource = resId;
500 mUri = null;
Adam Powellf96ce022012-08-09 15:08:33 -0700501
Alan Viveretted739d7b2014-10-29 17:26:37 -0700502 resolveUri();
Adam Powellf96ce022012-08-09 15:08:33 -0700503
Alan Viveretted739d7b2014-10-29 17:26:37 -0700504 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
505 requestLayout();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 }
Alan Viveretted739d7b2014-10-29 17:26:37 -0700507 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 }
509
Sunny Goyaldd292f42015-12-02 14:29:27 -0800510 /** @hide **/
Mathew Inwood978c6e22018-08-21 15:58:55 +0100511 @UnsupportedAppUsage
Sunny Goyaldd292f42015-12-02 14:29:27 -0800512 public Runnable setImageResourceAsync(@DrawableRes int resId) {
Sunny Goyal5c022632016-02-17 16:30:41 -0800513 Drawable d = null;
514 if (resId != 0) {
515 try {
516 d = getContext().getDrawable(resId);
517 } catch (Exception e) {
518 Log.w(LOG_TAG, "Unable to find resource: " + resId, e);
519 resId = 0;
520 }
521 }
522 return new ImageDrawableCallback(d, null, resId);
Sunny Goyaldd292f42015-12-02 14:29:27 -0800523 }
524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 /**
526 * Sets the content of this ImageView to the specified Uri.
Joe Fernandez704d43b2017-04-18 10:35:38 -0700527 * Note that you use this method to load images from a local Uri only.
528 * <p/>
529 * 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>
530 * <p/>
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700531 * <p class="note">This does Bitmap reading and decoding on the UI
532 * thread, which can cause a latency hiccup. If that's a concern,
Alan Viverette6ef129e2015-06-30 13:32:27 -0700533 * consider using {@link #setImageDrawable(Drawable)} or
Romain Guy9fc27812011-04-27 14:21:41 -0700534 * {@link #setImageBitmap(android.graphics.Bitmap)} and
Brad Fitzpatrickc6b0b772010-08-27 11:43:56 -0700535 * {@link android.graphics.BitmapFactory} instead.</p>
536 *
Alan Viveretteac21e562016-10-11 17:42:21 -0400537 * <p class="note">On devices running SDK < 24, this method will fail to
538 * apply correct density scaling to images loaded from
539 * {@link ContentResolver#SCHEME_CONTENT content} and
540 * {@link ContentResolver#SCHEME_FILE file} schemes. Applications running
541 * on devices with SDK >= 24 <strong>MUST</strong> specify the
542 * {@code targetSdkVersion} in their manifest as 24 or above for density
543 * scaling to be applied to images loaded from these schemes.</p>
544 *
Alan Viverette6ef129e2015-06-30 13:32:27 -0700545 * @param uri the Uri of an image, or {@code null} to clear the content
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 */
Sunny Goyaldd292f42015-12-02 14:29:27 -0800547 @android.view.RemotableViewMethod(asyncImpl="setImageURIAsync")
Alan Viverette6ef129e2015-06-30 13:32:27 -0700548 public void setImageURI(@Nullable Uri uri) {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400549 if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 updateDrawable(null);
551 mResource = 0;
552 mUri = uri;
Adam Powellf96ce022012-08-09 15:08:33 -0700553
554 final int oldWidth = mDrawableWidth;
555 final int oldHeight = mDrawableHeight;
556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 resolveUri();
Adam Powellf96ce022012-08-09 15:08:33 -0700558
559 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
560 requestLayout();
561 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 invalidate();
563 }
564 }
565
Sunny Goyaldd292f42015-12-02 14:29:27 -0800566 /** @hide **/
Mathew Inwood978c6e22018-08-21 15:58:55 +0100567 @UnsupportedAppUsage
Sunny Goyaldd292f42015-12-02 14:29:27 -0800568 public Runnable setImageURIAsync(@Nullable Uri uri) {
569 if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) {
570 Drawable d = uri == null ? null : getDrawableFromUri(uri);
571 if (d == null) {
572 // Do not set the URI if the drawable couldn't be loaded.
573 uri = null;
574 }
575 return new ImageDrawableCallback(d, uri, 0);
576 }
577 return null;
578 }
579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 /**
581 * Sets a drawable as the content of this ImageView.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400582 *
Alan Viverette6ef129e2015-06-30 13:32:27 -0700583 * @param drawable the Drawable to set, or {@code null} to clear the
584 * content
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 */
Alan Viverette6ef129e2015-06-30 13:32:27 -0700586 public void setImageDrawable(@Nullable Drawable drawable) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 if (mDrawable != drawable) {
588 mResource = 0;
589 mUri = null;
Romain Guy9e648c42011-08-17 20:04:27 -0700590
Adam Powellf96ce022012-08-09 15:08:33 -0700591 final int oldWidth = mDrawableWidth;
592 final int oldHeight = mDrawableHeight;
Romain Guy9e648c42011-08-17 20:04:27 -0700593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 updateDrawable(drawable);
Adam Powell2a0e99d2011-08-04 10:55:03 -0700595
Romain Guy9e648c42011-08-17 20:04:27 -0700596 if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
Adam Powell2a0e99d2011-08-04 10:55:03 -0700597 requestLayout();
598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 invalidate();
600 }
601 }
602
603 /**
Dan Sandlera22a3802015-05-13 00:12:47 -0400604 * Sets the content of this ImageView to the specified Icon.
605 *
Alan Viverette6ef129e2015-06-30 13:32:27 -0700606 * <p class="note">Depending on the Icon type, this may do Bitmap reading
607 * and decoding on the UI thread, which can cause UI jank. If that's a
608 * concern, consider using
Chris Banese695bb82015-05-14 10:12:20 +0100609 * {@link Icon#loadDrawableAsync(Context, Icon.OnDrawableLoadedListener, Handler)}
Alan Viverette6ef129e2015-06-30 13:32:27 -0700610 * and then {@link #setImageDrawable(android.graphics.drawable.Drawable)}
611 * instead.</p>
Dan Sandlera22a3802015-05-13 00:12:47 -0400612 *
Alan Viverette6ef129e2015-06-30 13:32:27 -0700613 * @param icon an Icon holding the desired image, or {@code null} to clear
614 * the content
Dan Sandlera22a3802015-05-13 00:12:47 -0400615 */
Sunny Goyaldd292f42015-12-02 14:29:27 -0800616 @android.view.RemotableViewMethod(asyncImpl="setImageIconAsync")
Alan Viverette6ef129e2015-06-30 13:32:27 -0700617 public void setImageIcon(@Nullable Icon icon) {
618 setImageDrawable(icon == null ? null : icon.loadDrawable(mContext));
Dan Sandlera22a3802015-05-13 00:12:47 -0400619 }
620
Sunny Goyaldd292f42015-12-02 14:29:27 -0800621 /** @hide **/
622 public Runnable setImageIconAsync(@Nullable Icon icon) {
623 return new ImageDrawableCallback(icon == null ? null : icon.loadDrawable(mContext), null, 0);
624 }
625
Dan Sandlera22a3802015-05-13 00:12:47 -0400626 /**
Alan Viverette91174362014-06-17 14:51:45 -0700627 * Applies a tint to the image drawable. Does not modify the current tint
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700628 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Alan Viverette91174362014-06-17 14:51:45 -0700629 * <p>
630 * Subsequent calls to {@link #setImageDrawable(Drawable)} will automatically
631 * mutate the drawable and apply the specified tint and tint mode using
Alan Viverettea4264452014-07-28 16:02:55 -0700632 * {@link Drawable#setTintList(ColorStateList)}.
Alan Viverette2b4e14c2016-07-21 16:25:13 -0400633 * <p>
634 * <em>Note:</em> The default tint mode used by this setter is NOT
635 * consistent with the default tint mode used by the
636 * {@link android.R.styleable#ImageView_tint android:tint}
637 * attribute. If the {@code android:tint} attribute is specified, the
638 * default tint mode will be set to {@link PorterDuff.Mode#SRC_ATOP} to
639 * ensure consistency with earlier versions of the platform.
Alan Viverette91174362014-06-17 14:51:45 -0700640 *
641 * @param tint the tint to apply, may be {@code null} to clear tint
642 *
643 * @attr ref android.R.styleable#ImageView_tint
Alan Viverettea4264452014-07-28 16:02:55 -0700644 * @see #getImageTintList()
645 * @see Drawable#setTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700646 */
Alan Viverettea4264452014-07-28 16:02:55 -0700647 public void setImageTintList(@Nullable ColorStateList tint) {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700648 mDrawableTintList = tint;
Alan Viverette4f64c042014-07-21 17:49:13 -0700649 mHasDrawableTint = true;
650
Alan Viverettea4264452014-07-28 16:02:55 -0700651 applyImageTint();
Alan Viverette91174362014-06-17 14:51:45 -0700652 }
653
654 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -0700655 * Get the current {@link android.content.res.ColorStateList} used to tint the image Drawable,
656 * or null if no tint is applied.
657 *
Alan Viverette91174362014-06-17 14:51:45 -0700658 * @return the tint applied to the image drawable
659 * @attr ref android.R.styleable#ImageView_tint
Alan Viverettea4264452014-07-28 16:02:55 -0700660 * @see #setImageTintList(ColorStateList)
Alan Viverette91174362014-06-17 14:51:45 -0700661 */
662 @Nullable
Ashley Rose55f9f922019-01-28 19:29:36 -0500663 @InspectableProperty(name = "tint")
Alan Viverettea4264452014-07-28 16:02:55 -0700664 public ColorStateList getImageTintList() {
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700665 return mDrawableTintList;
Alan Viverette91174362014-06-17 14:51:45 -0700666 }
667
668 /**
669 * Specifies the blending mode used to apply the tint specified by
Alan Viverettea4264452014-07-28 16:02:55 -0700670 * {@link #setImageTintList(ColorStateList)}} to the image drawable. The default
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700671 * mode is {@link PorterDuff.Mode#SRC_IN}.
Alan Viverette91174362014-06-17 14:51:45 -0700672 *
673 * @param tintMode the blending mode used to apply the tint, may be
674 * {@code null} to clear tint
675 * @attr ref android.R.styleable#ImageView_tintMode
Alan Viverettea4264452014-07-28 16:02:55 -0700676 * @see #getImageTintMode()
677 * @see Drawable#setTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700678 */
Alan Viverettea4264452014-07-28 16:02:55 -0700679 public void setImageTintMode(@Nullable PorterDuff.Mode tintMode) {
Nader Jawad531db612019-04-14 21:58:04 -0700680 setImageTintBlendMode(tintMode != null ? BlendMode.fromValue(tintMode.nativeInt) : null);
681 }
682
683 /**
684 * Specifies the blending mode used to apply the tint specified by
685 * {@link #setImageTintList(ColorStateList)}} to the image drawable. The default
686 * mode is {@link BlendMode#SRC_IN}.
687 *
688 * @param blendMode the blending mode used to apply the tint, may be
689 * {@code null} to clear tint
690 * @attr ref android.R.styleable#ImageView_tintMode
691 * @see #getImageTintMode()
692 * @see Drawable#setTintBlendMode(BlendMode)
693 */
694 public void setImageTintBlendMode(@Nullable BlendMode blendMode) {
695 mDrawableBlendMode = blendMode;
696 mHasDrawableBlendMode = true;
Alan Viverette4f64c042014-07-21 17:49:13 -0700697
Alan Viverettea4264452014-07-28 16:02:55 -0700698 applyImageTint();
Alan Viverette91174362014-06-17 14:51:45 -0700699 }
700
701 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -0700702 * Gets the blending mode used to apply the tint to the image Drawable
703 * @return the blending mode used to apply the tint to the image Drawable
Alan Viverette91174362014-06-17 14:51:45 -0700704 * @attr ref android.R.styleable#ImageView_tintMode
Alan Viverettea4264452014-07-28 16:02:55 -0700705 * @see #setImageTintMode(PorterDuff.Mode)
Alan Viverette91174362014-06-17 14:51:45 -0700706 */
707 @Nullable
Ashley Rose55f9f922019-01-28 19:29:36 -0500708 @InspectableProperty(name = "tintMode")
Alan Viverettea4264452014-07-28 16:02:55 -0700709 public PorterDuff.Mode getImageTintMode() {
Nader Jawad531db612019-04-14 21:58:04 -0700710 return mDrawableBlendMode != null
711 ? BlendMode.blendModeToPorterDuffMode(mDrawableBlendMode) : null;
712 }
713
714 /**
715 * Gets the blending mode used to apply the tint to the image Drawable
716 * @return the blending mode used to apply the tint to the image Drawable
717 * @attr ref android.R.styleable#ImageView_tintMode
718 * @see #setImageTintBlendMode(BlendMode)
719 */
720 @Nullable
721 @InspectableProperty(name = "blendMode", attributeId = android.R.styleable.ImageView_tintMode)
722 public BlendMode getImageTintBlendMode() {
723 return mDrawableBlendMode;
Alan Viverette91174362014-06-17 14:51:45 -0700724 }
725
Alan Viverettea4264452014-07-28 16:02:55 -0700726 private void applyImageTint() {
Nader Jawad531db612019-04-14 21:58:04 -0700727 if (mDrawable != null && (mHasDrawableTint || mHasDrawableBlendMode)) {
Alan Viverette91174362014-06-17 14:51:45 -0700728 mDrawable = mDrawable.mutate();
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700729
730 if (mHasDrawableTint) {
731 mDrawable.setTintList(mDrawableTintList);
732 }
733
Nader Jawad531db612019-04-14 21:58:04 -0700734 if (mHasDrawableBlendMode) {
735 mDrawable.setTintBlendMode(mDrawableBlendMode);
Alan Viveretteb56f5d22014-09-14 15:48:50 -0700736 }
Alan Viveretted5133792014-10-28 14:41:36 -0700737
738 // The drawable (or one of its children) may not have been
739 // stateful before applying the tint, so let's try again.
740 if (mDrawable.isStateful()) {
741 mDrawable.setState(getDrawableState());
742 }
Alan Viverette91174362014-06-17 14:51:45 -0700743 }
744 }
745
746 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 * Sets a Bitmap as the content of this ImageView.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400748 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 * @param bm The bitmap to set
750 */
751 @android.view.RemotableViewMethod
752 public void setImageBitmap(Bitmap bm) {
John Reck5a135692015-07-10 10:02:58 -0700753 // Hacky fix to force setImageDrawable to do a full setImageDrawable
754 // instead of doing an object reference comparison
755 mDrawable = null;
756 if (mRecycleableBitmapDrawable == null) {
Chris Craik82af13e2015-07-14 13:36:27 -0700757 mRecycleableBitmapDrawable = new BitmapDrawable(mContext.getResources(), bm);
John Reckb7ba1222015-07-09 17:37:34 -0700758 } else {
John Reck5a135692015-07-10 10:02:58 -0700759 mRecycleableBitmapDrawable.setBitmap(bm);
John Reckb7ba1222015-07-09 17:37:34 -0700760 }
John Reck5a135692015-07-10 10:02:58 -0700761 setImageDrawable(mRecycleableBitmapDrawable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 }
763
Joe Fernandez704d43b2017-04-18 10:35:38 -0700764 /**
765 * Set the state of the current {@link android.graphics.drawable.StateListDrawable}.
766 * 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>.
767 *
768 * @param state the state to set for the StateListDrawable
769 * @param merge if true, merges the state values for the state you specify into the current state
770 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 public void setImageState(int[] state, boolean merge) {
772 mState = state;
773 mMergeState = merge;
774 if (mDrawable != null) {
775 refreshDrawableState();
776 resizeFromDrawable();
777 }
778 }
779
780 @Override
781 public void setSelected(boolean selected) {
782 super.setSelected(selected);
783 resizeFromDrawable();
784 }
785
The Android Open Source Project4df24232009-03-05 14:34:35 -0800786 /**
Alan Viverette6aa92d12015-08-25 13:19:25 -0400787 * Sets the image level, when it is constructed from a
The Android Open Source Project4df24232009-03-05 14:34:35 -0800788 * {@link android.graphics.drawable.LevelListDrawable}.
789 *
790 * @param level The new level for the image.
791 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 @android.view.RemotableViewMethod
793 public void setImageLevel(int level) {
794 mLevel = level;
795 if (mDrawable != null) {
796 mDrawable.setLevel(level);
797 resizeFromDrawable();
798 }
799 }
800
801 /**
802 * Options for scaling the bounds of an image to the bounds of this view.
803 */
804 public enum ScaleType {
805 /**
806 * Scale using the image matrix when drawing. The image matrix can be set using
807 * {@link ImageView#setImageMatrix(Matrix)}. From XML, use this syntax:
808 * <code>android:scaleType="matrix"</code>.
809 */
810 MATRIX (0),
811 /**
812 * Scale the image using {@link Matrix.ScaleToFit#FILL}.
813 * From XML, use this syntax: <code>android:scaleType="fitXY"</code>.
814 */
815 FIT_XY (1),
816 /**
817 * Scale the image using {@link Matrix.ScaleToFit#START}.
818 * From XML, use this syntax: <code>android:scaleType="fitStart"</code>.
819 */
820 FIT_START (2),
821 /**
822 * Scale the image using {@link Matrix.ScaleToFit#CENTER}.
823 * From XML, use this syntax:
824 * <code>android:scaleType="fitCenter"</code>.
825 */
826 FIT_CENTER (3),
827 /**
828 * Scale the image using {@link Matrix.ScaleToFit#END}.
829 * From XML, use this syntax: <code>android:scaleType="fitEnd"</code>.
830 */
831 FIT_END (4),
832 /**
833 * Center the image in the view, but perform no scaling.
834 * From XML, use this syntax: <code>android:scaleType="center"</code>.
835 */
836 CENTER (5),
837 /**
838 * Scale the image uniformly (maintain the image's aspect ratio) so
839 * that both dimensions (width and height) of the image will be equal
840 * to or larger than the corresponding dimension of the view
841 * (minus padding). The image is then centered in the view.
842 * From XML, use this syntax: <code>android:scaleType="centerCrop"</code>.
843 */
844 CENTER_CROP (6),
845 /**
846 * Scale the image uniformly (maintain the image's aspect ratio) so
847 * that both dimensions (width and height) of the image will be equal
848 * to or less than the corresponding dimension of the view
849 * (minus padding). The image is then centered in the view.
850 * From XML, use this syntax: <code>android:scaleType="centerInside"</code>.
851 */
852 CENTER_INSIDE (7);
Alan Viverette6aa92d12015-08-25 13:19:25 -0400853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 ScaleType(int ni) {
855 nativeInt = ni;
856 }
857 final int nativeInt;
858 }
859
860 /**
861 * Controls how the image should be resized or moved to match the size
862 * of this ImageView.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400863 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 * @param scaleType The desired scaling mode.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400865 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 * @attr ref android.R.styleable#ImageView_scaleType
867 */
868 public void setScaleType(ScaleType scaleType) {
869 if (scaleType == null) {
870 throw new NullPointerException();
871 }
872
873 if (mScaleType != scaleType) {
874 mScaleType = scaleType;
875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 requestLayout();
877 invalidate();
878 }
879 }
Alan Viverette6aa92d12015-08-25 13:19:25 -0400880
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -0700882 * Returns the current ScaleType that is used to scale the bounds of an image to the bounds of the ImageView.
883 * @return The ScaleType used to scale the image.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 * @see ImageView.ScaleType
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 * @attr ref android.R.styleable#ImageView_scaleType
886 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500887 @InspectableProperty
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 public ScaleType getScaleType() {
889 return mScaleType;
890 }
891
Joe Fernandez704d43b2017-04-18 10:35:38 -0700892 /** Returns the view's optional matrix. This is applied to the
John Spurlock0196e562014-02-03 09:00:35 -0500893 view's drawable when it is drawn. If there is no matrix,
Romain Guy53704052013-01-30 16:25:50 -0800894 this method will return an identity matrix.
895 Do not change this matrix in place but make a copy.
896 If you want a different matrix applied to the drawable,
897 be sure to call setImageMatrix().
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 */
899 public Matrix getImageMatrix() {
Dake Gu1ee60172013-01-03 15:11:43 -0800900 if (mDrawMatrix == null) {
Romain Guy53704052013-01-30 16:25:50 -0800901 return new Matrix(Matrix.IDENTITY_MATRIX);
Dake Gu1ee60172013-01-03 15:11:43 -0800902 }
903 return mDrawMatrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 }
905
Joseph Cooperd96fdbd2015-04-03 14:00:31 -0700906 /**
907 * Adds a transformation {@link Matrix} that is applied
908 * to the view's drawable when it is drawn. Allows custom scaling,
909 * translation, and perspective distortion.
Alan Viverette6aa92d12015-08-25 13:19:25 -0400910 *
Joe Fernandez704d43b2017-04-18 10:35:38 -0700911 * @param matrix The transformation parameters in matrix form.
Joseph Cooperd96fdbd2015-04-03 14:00:31 -0700912 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 public void setImageMatrix(Matrix matrix) {
Joseph Cooperd96fdbd2015-04-03 14:00:31 -0700914 // collapse null and identity to just null
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915 if (matrix != null && matrix.isIdentity()) {
916 matrix = null;
917 }
Joseph Cooperd96fdbd2015-04-03 14:00:31 -0700918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919 // don't invalidate unless we're actually changing our matrix
920 if (matrix == null && !mMatrix.isIdentity() ||
921 matrix != null && !mMatrix.equals(matrix)) {
922 mMatrix.set(matrix);
Chih-Chung Changf8887262009-07-30 15:36:13 +0800923 configureBounds();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 invalidate();
925 }
926 }
Philip Milneaac722a2012-03-26 13:30:26 -0700927
928 /**
929 * Return whether this ImageView crops to padding.
930 *
931 * @return whether this ImageView crops to padding
932 *
933 * @see #setCropToPadding(boolean)
934 *
935 * @attr ref android.R.styleable#ImageView_cropToPadding
936 */
Ashley Rose55f9f922019-01-28 19:29:36 -0500937 @InspectableProperty
Philip Milneaac722a2012-03-26 13:30:26 -0700938 public boolean getCropToPadding() {
939 return mCropToPadding;
940 }
941
942 /**
943 * Sets whether this ImageView will crop to padding.
944 *
945 * @param cropToPadding whether this ImageView will crop to padding
946 *
947 * @see #getCropToPadding()
948 *
949 * @attr ref android.R.styleable#ImageView_cropToPadding
950 */
951 public void setCropToPadding(boolean cropToPadding) {
952 if (mCropToPadding != cropToPadding) {
953 mCropToPadding = cropToPadding;
954 requestLayout();
955 invalidate();
956 }
957 }
958
Mathew Inwood978c6e22018-08-21 15:58:55 +0100959 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 private void resolveUri() {
961 if (mDrawable != null) {
962 return;
963 }
964
Sunny Goyaldd292f42015-12-02 14:29:27 -0800965 if (getResources() == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 return;
967 }
968
969 Drawable d = null;
970
971 if (mResource != 0) {
972 try {
Alan Viverette8eea3ea2014-02-03 18:40:20 -0800973 d = mContext.getDrawable(mResource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 } catch (Exception e) {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400975 Log.w(LOG_TAG, "Unable to find resource: " + mResource, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 // Don't try again.
Sunny Goyal5c022632016-02-17 16:30:41 -0800977 mResource = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 }
979 } else if (mUri != null) {
Sunny Goyaldd292f42015-12-02 14:29:27 -0800980 d = getDrawableFromUri(mUri);
Alan Viverette6aa92d12015-08-25 13:19:25 -0400981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 if (d == null) {
Alan Viverette6aa92d12015-08-25 13:19:25 -0400983 Log.w(LOG_TAG, "resolveUri failed on bad bitmap uri: " + mUri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 // Don't try again.
985 mUri = null;
986 }
987 } else {
988 return;
989 }
990
991 updateDrawable(d);
992 }
993
Sunny Goyaldd292f42015-12-02 14:29:27 -0800994 private Drawable getDrawableFromUri(Uri uri) {
995 final String scheme = uri.getScheme();
996 if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
997 try {
998 // Load drawable through Resources, to get the source density information
999 ContentResolver.OpenResourceIdResult r =
1000 mContext.getContentResolver().getResourceId(uri);
1001 return r.r.getDrawable(r.id, mContext.getTheme());
1002 } catch (Exception e) {
1003 Log.w(LOG_TAG, "Unable to open content: " + uri, e);
1004 }
1005 } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
1006 || ContentResolver.SCHEME_FILE.equals(scheme)) {
Sunny Goyaldd292f42015-12-02 14:29:27 -08001007 try {
Leon Scroggins III046a99e2018-01-31 14:59:29 -05001008 Resources res = sCompatUseCorrectStreamDensity ? getResources() : null;
1009 ImageDecoder.Source src = ImageDecoder.createSource(mContext.getContentResolver(),
1010 uri, res);
1011 return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
1012 decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
1013 });
1014 } catch (IOException e) {
Sunny Goyaldd292f42015-12-02 14:29:27 -08001015 Log.w(LOG_TAG, "Unable to open content: " + uri, e);
Sunny Goyaldd292f42015-12-02 14:29:27 -08001016 }
1017 } else {
1018 return Drawable.createFromPath(uri.toString());
1019 }
1020 return null;
1021 }
1022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 @Override
1024 public int[] onCreateDrawableState(int extraSpace) {
1025 if (mState == null) {
1026 return super.onCreateDrawableState(extraSpace);
1027 } else if (!mMergeState) {
1028 return mState;
1029 } else {
1030 return mergeDrawableStates(
1031 super.onCreateDrawableState(extraSpace + mState.length), mState);
1032 }
1033 }
1034
Mathew Inwood978c6e22018-08-21 15:58:55 +01001035 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036 private void updateDrawable(Drawable d) {
John Reck5a135692015-07-10 10:02:58 -07001037 if (d != mRecycleableBitmapDrawable && mRecycleableBitmapDrawable != null) {
1038 mRecycleableBitmapDrawable.setBitmap(null);
1039 }
1040
Adam Powell06f9eb82016-08-24 17:09:01 -07001041 boolean sameDrawable = false;
1042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 if (mDrawable != null) {
Adam Powell06f9eb82016-08-24 17:09:01 -07001044 sameDrawable = mDrawable == d;
Adam Powell35e2ea02016-03-22 10:40:29 -07001045 mDrawable.setCallback(null);
1046 unscheduleDrawable(mDrawable);
Adam Powell06f9eb82016-08-24 17:09:01 -07001047 if (!sCompatDrawableVisibilityDispatch && !sameDrawable && isAttachedToWindow()) {
Adam Powell4b2e12c2016-03-31 15:35:35 -07001048 mDrawable.setVisible(false, false);
1049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 }
Alan Viverette91174362014-06-17 14:51:45 -07001051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 mDrawable = d;
Alan Viverette91174362014-06-17 14:51:45 -07001053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 if (d != null) {
1055 d.setCallback(this);
Alan Viverette91174362014-06-17 14:51:45 -07001056 d.setLayoutDirection(getLayoutDirection());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 if (d.isStateful()) {
1058 d.setState(getDrawableState());
1059 }
Adam Powell06f9eb82016-08-24 17:09:01 -07001060 if (!sameDrawable || sCompatDrawableVisibilityDispatch) {
1061 final boolean visible = sCompatDrawableVisibilityDispatch
1062 ? getVisibility() == VISIBLE
1063 : isAttachedToWindow() && getWindowVisibility() == VISIBLE && isShown();
1064 d.setVisible(visible, true);
1065 }
Alan Viverette91174362014-06-17 14:51:45 -07001066 d.setLevel(mLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 mDrawableWidth = d.getIntrinsicWidth();
1068 mDrawableHeight = d.getIntrinsicHeight();
Alan Viverettea4264452014-07-28 16:02:55 -07001069 applyImageTint();
Nader Jawade6a63212018-04-20 15:56:10 -07001070 applyColorFilter();
1071 applyAlpha();
1072 applyXfermode();
Alan Viveretted5133792014-10-28 14:41:36 -07001073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 configureBounds();
Romain Guy9e648c42011-08-17 20:04:27 -07001075 } else {
1076 mDrawableWidth = mDrawableHeight = -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
1078 }
1079
Mathew Inwood978c6e22018-08-21 15:58:55 +01001080 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 private void resizeFromDrawable() {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001082 final Drawable d = mDrawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 if (d != null) {
1084 int w = d.getIntrinsicWidth();
1085 if (w < 0) w = mDrawableWidth;
1086 int h = d.getIntrinsicHeight();
1087 if (h < 0) h = mDrawableHeight;
1088 if (w != mDrawableWidth || h != mDrawableHeight) {
1089 mDrawableWidth = w;
1090 mDrawableHeight = h;
1091 requestLayout();
1092 }
1093 }
1094 }
1095
Fabrice Di Meglio3f5a90b2013-06-24 19:22:25 -07001096 @Override
1097 public void onRtlPropertiesChanged(int layoutDirection) {
1098 super.onRtlPropertiesChanged(layoutDirection);
1099
1100 if (mDrawable != null) {
1101 mDrawable.setLayoutDirection(layoutDirection);
1102 }
1103 }
1104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 private static final Matrix.ScaleToFit[] sS2FArray = {
1106 Matrix.ScaleToFit.FILL,
1107 Matrix.ScaleToFit.START,
1108 Matrix.ScaleToFit.CENTER,
1109 Matrix.ScaleToFit.END
1110 };
1111
Mathew Inwood978c6e22018-08-21 15:58:55 +01001112 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 private static Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType st) {
1114 // ScaleToFit enum to their corresponding Matrix.ScaleToFit values
1115 return sS2FArray[st.nativeInt - 1];
Alan Viverette6aa92d12015-08-25 13:19:25 -04001116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117
1118 @Override
1119 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
1120 resolveUri();
1121 int w;
1122 int h;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001124 // Desired aspect ratio of the view's contents (not including padding)
1125 float desiredAspect = 0.0f;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 // We are allowed to change the view's width
1128 boolean resizeWidth = false;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 // We are allowed to change the view's height
1131 boolean resizeHeight = false;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001132
Adam Powell2a0e99d2011-08-04 10:55:03 -07001133 final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
1134 final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
1135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 if (mDrawable == null) {
1137 // If no drawable, its intrinsic size is 0.
1138 mDrawableWidth = -1;
1139 mDrawableHeight = -1;
1140 w = h = 0;
1141 } else {
1142 w = mDrawableWidth;
1143 h = mDrawableHeight;
1144 if (w <= 0) w = 1;
1145 if (h <= 0) h = 1;
Romain Guy9e648c42011-08-17 20:04:27 -07001146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 // We are supposed to adjust view bounds to match the aspect
1148 // ratio of our drawable. See if that is possible.
1149 if (mAdjustViewBounds) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001150 resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
1151 resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001152
Romain Guy9e648c42011-08-17 20:04:27 -07001153 desiredAspect = (float) w / (float) h;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001154 }
1155 }
Alan Viverette6aa92d12015-08-25 13:19:25 -04001156
1157 final int pleft = mPaddingLeft;
1158 final int pright = mPaddingRight;
1159 final int ptop = mPaddingTop;
1160 final int pbottom = mPaddingBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161
1162 int widthSize;
1163 int heightSize;
1164
1165 if (resizeWidth || resizeHeight) {
1166 /* If we get here, it means we want to resize to match the
1167 drawables aspect ratio, and we have the freedom to change at
Alan Viverette6aa92d12015-08-25 13:19:25 -04001168 least one dimension.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 */
1170
1171 // Get the max possible width given our constraints
Romain Guy9e648c42011-08-17 20:04:27 -07001172 widthSize = resolveAdjustedSize(w + pleft + pright, mMaxWidth, widthMeasureSpec);
1173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 // Get the max possible height given our constraints
Romain Guy9e648c42011-08-17 20:04:27 -07001175 heightSize = resolveAdjustedSize(h + ptop + pbottom, mMaxHeight, heightMeasureSpec);
1176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 if (desiredAspect != 0.0f) {
1178 // See what our actual aspect ratio is
Alan Viverette6aa92d12015-08-25 13:19:25 -04001179 final float actualAspect = (float)(widthSize - pleft - pright) /
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 (heightSize - ptop - pbottom);
Alan Viverette6aa92d12015-08-25 13:19:25 -04001181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 boolean done = false;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001186 // Try adjusting width to be proportional to height
1187 if (resizeWidth) {
Romain Guy9e648c42011-08-17 20:04:27 -07001188 int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
1189 pleft + pright;
Adam Powelld5edc772012-09-26 15:21:39 -07001190
1191 // Allow the width to outgrow its original estimate if height is fixed.
Adam Powell06f9eb82016-08-24 17:09:01 -07001192 if (!resizeHeight && !sCompatAdjustViewBounds) {
Adam Powelld5edc772012-09-26 15:21:39 -07001193 widthSize = resolveAdjustedSize(newWidth, mMaxWidth, widthMeasureSpec);
1194 }
1195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 if (newWidth <= widthSize) {
1197 widthSize = newWidth;
1198 done = true;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001199 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 }
Alan Viverette6aa92d12015-08-25 13:19:25 -04001201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 // Try adjusting height to be proportional to width
1203 if (!done && resizeHeight) {
Romain Guy9e648c42011-08-17 20:04:27 -07001204 int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
1205 ptop + pbottom;
Adam Powelld5edc772012-09-26 15:21:39 -07001206
1207 // Allow the height to outgrow its original estimate if width is fixed.
Adam Powell06f9eb82016-08-24 17:09:01 -07001208 if (!resizeWidth && !sCompatAdjustViewBounds) {
Adam Powelld5edc772012-09-26 15:21:39 -07001209 heightSize = resolveAdjustedSize(newHeight, mMaxHeight,
1210 heightMeasureSpec);
1211 }
1212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 if (newHeight <= heightSize) {
1214 heightSize = newHeight;
Dianne Hackborn189ee182010-12-02 21:48:53 -08001215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216 }
1217 }
1218 }
1219 } else {
1220 /* We are either don't want to preserve the drawables aspect ratio,
1221 or we are not allowed to change view dimensions. Just measure in
1222 the normal way.
1223 */
1224 w += pleft + pright;
1225 h += ptop + pbottom;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 w = Math.max(w, getSuggestedMinimumWidth());
1228 h = Math.max(h, getSuggestedMinimumHeight());
1229
Dianne Hackborn189ee182010-12-02 21:48:53 -08001230 widthSize = resolveSizeAndState(w, widthMeasureSpec, 0);
1231 heightSize = resolveSizeAndState(h, heightMeasureSpec, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
1233
1234 setMeasuredDimension(widthSize, heightSize);
1235 }
1236
1237 private int resolveAdjustedSize(int desiredSize, int maxSize,
1238 int measureSpec) {
1239 int result = desiredSize;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001240 final int specMode = MeasureSpec.getMode(measureSpec);
1241 final int specSize = MeasureSpec.getSize(measureSpec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 switch (specMode) {
1243 case MeasureSpec.UNSPECIFIED:
1244 /* Parent says we can be as big as we want. Just don't be larger
1245 than max size imposed on ourselves.
1246 */
1247 result = Math.min(desiredSize, maxSize);
1248 break;
1249 case MeasureSpec.AT_MOST:
Alan Viverette6aa92d12015-08-25 13:19:25 -04001250 // Parent says we can be as big as we want, up to specSize.
1251 // Don't be larger than specSize, and don't be larger than
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 // the max size imposed on ourselves.
1253 result = Math.min(Math.min(desiredSize, specSize), maxSize);
1254 break;
1255 case MeasureSpec.EXACTLY:
1256 // No choice. Do what we are told.
1257 result = specSize;
1258 break;
1259 }
1260 return result;
1261 }
1262
1263 @Override
1264 protected boolean setFrame(int l, int t, int r, int b) {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001265 final boolean changed = super.setFrame(l, t, r, b);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 mHaveFrame = true;
1267 configureBounds();
1268 return changed;
1269 }
1270
1271 private void configureBounds() {
1272 if (mDrawable == null || !mHaveFrame) {
1273 return;
1274 }
1275
Alan Viverette6aa92d12015-08-25 13:19:25 -04001276 final int dwidth = mDrawableWidth;
1277 final int dheight = mDrawableHeight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278
Alan Viverette6aa92d12015-08-25 13:19:25 -04001279 final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
1280 final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281
Alan Viverette6aa92d12015-08-25 13:19:25 -04001282 final boolean fits = (dwidth < 0 || vwidth == dwidth)
1283 && (dheight < 0 || vheight == dheight);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284
1285 if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
1286 /* If the drawable has no intrinsic size, or we're told to
1287 scaletofit, then we just fill our entire view.
1288 */
1289 mDrawable.setBounds(0, 0, vwidth, vheight);
1290 mDrawMatrix = null;
1291 } else {
1292 // We need to do the scaling ourself, so have the drawable
1293 // use its native size.
1294 mDrawable.setBounds(0, 0, dwidth, dheight);
1295
1296 if (ScaleType.MATRIX == mScaleType) {
1297 // Use the specified matrix as-is.
1298 if (mMatrix.isIdentity()) {
1299 mDrawMatrix = null;
1300 } else {
1301 mDrawMatrix = mMatrix;
1302 }
1303 } else if (fits) {
1304 // The bitmap fits exactly, no transform needed.
1305 mDrawMatrix = null;
1306 } else if (ScaleType.CENTER == mScaleType) {
1307 // Center bitmap in view, no scaling.
1308 mDrawMatrix = mMatrix;
Adam Powell14d1f1382015-06-04 12:56:00 -07001309 mDrawMatrix.setTranslate(Math.round((vwidth - dwidth) * 0.5f),
1310 Math.round((vheight - dheight) * 0.5f));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 } else if (ScaleType.CENTER_CROP == mScaleType) {
1312 mDrawMatrix = mMatrix;
1313
1314 float scale;
1315 float dx = 0, dy = 0;
1316
1317 if (dwidth * vheight > vwidth * dheight) {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001318 scale = (float) vheight / (float) dheight;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001319 dx = (vwidth - dwidth * scale) * 0.5f;
1320 } else {
1321 scale = (float) vwidth / (float) dwidth;
1322 dy = (vheight - dheight * scale) * 0.5f;
1323 }
1324
1325 mDrawMatrix.setScale(scale, scale);
Adam Powell14d1f1382015-06-04 12:56:00 -07001326 mDrawMatrix.postTranslate(Math.round(dx), Math.round(dy));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 } else if (ScaleType.CENTER_INSIDE == mScaleType) {
1328 mDrawMatrix = mMatrix;
1329 float scale;
1330 float dx;
1331 float dy;
Alan Viverette6aa92d12015-08-25 13:19:25 -04001332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 if (dwidth <= vwidth && dheight <= vheight) {
1334 scale = 1.0f;
1335 } else {
Romain Guy9e648c42011-08-17 20:04:27 -07001336 scale = Math.min((float) vwidth / (float) dwidth,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 (float) vheight / (float) dheight);
1338 }
Alan Viverette6aa92d12015-08-25 13:19:25 -04001339
Adam Powell14d1f1382015-06-04 12:56:00 -07001340 dx = Math.round((vwidth - dwidth * scale) * 0.5f);
1341 dy = Math.round((vheight - dheight * scale) * 0.5f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342
1343 mDrawMatrix.setScale(scale, scale);
1344 mDrawMatrix.postTranslate(dx, dy);
1345 } else {
1346 // Generate the required transform.
1347 mTempSrc.set(0, 0, dwidth, dheight);
1348 mTempDst.set(0, 0, vwidth, vheight);
Alan Viverette6aa92d12015-08-25 13:19:25 -04001349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 mDrawMatrix = mMatrix;
Romain Guy9e648c42011-08-17 20:04:27 -07001351 mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 }
1353 }
1354 }
1355
1356 @Override
1357 protected void drawableStateChanged() {
1358 super.drawableStateChanged();
Alan Viverette6aa92d12015-08-25 13:19:25 -04001359
Alan Viverettead0020f2015-09-04 10:10:42 -04001360 final Drawable drawable = mDrawable;
1361 if (drawable != null && drawable.isStateful()
1362 && drawable.setState(getDrawableState())) {
1363 invalidateDrawable(drawable);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 }
1365 }
1366
Alan Viverettecebc6ba2014-06-13 15:52:13 -07001367 @Override
Alan Viverette8de14942014-06-18 18:05:15 -07001368 public void drawableHotspotChanged(float x, float y) {
1369 super.drawableHotspotChanged(x, y);
Alan Viverettecebc6ba2014-06-13 15:52:13 -07001370
1371 if (mDrawable != null) {
1372 mDrawable.setHotspot(x, y);
1373 }
1374 }
1375
Andrey Kulikov3ac312a2018-11-27 15:52:17 +00001376 /**
1377 * Applies a temporary transformation {@link Matrix} to the view's drawable when it is drawn.
1378 * Allows custom scaling, translation, and perspective distortion during an animation.
1379 *
1380 * This method is a lightweight analogue of {@link ImageView#setImageMatrix(Matrix)} to use
1381 * only during animations as this matrix will be cleared after the next drawable
1382 * update or view's bounds change.
1383 *
1384 * @param matrix The transformation parameters in matrix form.
1385 */
1386 public void animateTransform(@Nullable Matrix matrix) {
George Mountf6c763d2014-09-25 15:13:15 -07001387 if (mDrawable == null) {
1388 return;
1389 }
George Mount990205e2014-06-24 09:36:18 -07001390 if (matrix == null) {
Andrey Kulikov72be9742018-09-28 00:22:42 +01001391 final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
1392 final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
1393 mDrawable.setBounds(0, 0, vwidth, vheight);
Andrey Kulikov3ac312a2018-11-27 15:52:17 +00001394 mDrawMatrix = null;
George Mount990205e2014-06-24 09:36:18 -07001395 } else {
1396 mDrawable.setBounds(0, 0, mDrawableWidth, mDrawableHeight);
1397 if (mDrawMatrix == null) {
1398 mDrawMatrix = new Matrix();
1399 }
1400 mDrawMatrix.set(matrix);
1401 }
1402 invalidate();
1403 }
1404
Alan Viverettecebc6ba2014-06-13 15:52:13 -07001405 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 protected void onDraw(Canvas canvas) {
1407 super.onDraw(canvas);
1408
1409 if (mDrawable == null) {
1410 return; // couldn't resolve the URI
1411 }
1412
1413 if (mDrawableWidth == 0 || mDrawableHeight == 0) {
1414 return; // nothing to draw (empty bounds)
1415 }
1416
1417 if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
1418 mDrawable.draw(canvas);
1419 } else {
Alan Viverette6aa92d12015-08-25 13:19:25 -04001420 final int saveCount = canvas.getSaveCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 canvas.save();
Alan Viverette6aa92d12015-08-25 13:19:25 -04001422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 if (mCropToPadding) {
1424 final int scrollX = mScrollX;
1425 final int scrollY = mScrollY;
1426 canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,
1427 scrollX + mRight - mLeft - mPaddingRight,
1428 scrollY + mBottom - mTop - mPaddingBottom);
1429 }
Alan Viverette6aa92d12015-08-25 13:19:25 -04001430
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 canvas.translate(mPaddingLeft, mPaddingTop);
1432
1433 if (mDrawMatrix != null) {
1434 canvas.concat(mDrawMatrix);
1435 }
1436 mDrawable.draw(canvas);
1437 canvas.restoreToCount(saveCount);
1438 }
1439 }
1440
Joe Onoratofd52b182010-11-10 18:00:52 -08001441 /**
1442 * <p>Return the offset of the widget's text baseline from the widget's top
1443 * boundary. </p>
1444 *
1445 * @return the offset of the baseline within the widget's bounds or -1
1446 * if baseline alignment is not supported.
1447 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 @Override
Ashley Rose55f9f922019-01-28 19:29:36 -05001449 @InspectableProperty
Joe Onoratofd52b182010-11-10 18:00:52 -08001450 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 public int getBaseline() {
Joe Onoratofd52b182010-11-10 18:00:52 -08001452 if (mBaselineAlignBottom) {
1453 return getMeasuredHeight();
1454 } else {
1455 return mBaseline;
1456 }
1457 }
1458
1459 /**
1460 * <p>Set the offset of the widget's text baseline from the widget's top
Romain Guy9fc27812011-04-27 14:21:41 -07001461 * boundary. This value is overridden by the {@link #setBaselineAlignBottom(boolean)}
Joe Onoratofd52b182010-11-10 18:00:52 -08001462 * property.</p>
1463 *
1464 * @param baseline The baseline to use, or -1 if none is to be provided.
1465 *
Alan Viverette6aa92d12015-08-25 13:19:25 -04001466 * @see #setBaseline(int)
Joe Onoratofd52b182010-11-10 18:00:52 -08001467 * @attr ref android.R.styleable#ImageView_baseline
1468 */
1469 public void setBaseline(int baseline) {
1470 if (mBaseline != baseline) {
1471 mBaseline = baseline;
1472 requestLayout();
1473 }
1474 }
1475
1476 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -07001477 * Sets whether the baseline of this view to the bottom of the view.
Joe Onoratofd52b182010-11-10 18:00:52 -08001478 * Setting this value overrides any calls to setBaseline.
1479 *
Joe Fernandez704d43b2017-04-18 10:35:38 -07001480 * @param aligned If true, the image view will be baseline aligned by its bottom edge.
Joe Onoratofd52b182010-11-10 18:00:52 -08001481 *
1482 * @attr ref android.R.styleable#ImageView_baselineAlignBottom
1483 */
1484 public void setBaselineAlignBottom(boolean aligned) {
1485 if (mBaselineAlignBottom != aligned) {
1486 mBaselineAlignBottom = aligned;
1487 requestLayout();
1488 }
1489 }
1490
1491 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -07001492 * Checks whether this view's baseline is considered the bottom of the view.
Joe Onoratofd52b182010-11-10 18:00:52 -08001493 *
Joe Fernandez704d43b2017-04-18 10:35:38 -07001494 * @return True if the ImageView's baseline is considered the bottom of the view, false if otherwise.
Joe Onoratofd52b182010-11-10 18:00:52 -08001495 * @see #setBaselineAlignBottom(boolean)
1496 */
Ashley Rose55f9f922019-01-28 19:29:36 -05001497 @InspectableProperty
Joe Onoratofd52b182010-11-10 18:00:52 -08001498 public boolean getBaselineAlignBottom() {
1499 return mBaselineAlignBottom;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 /**
Joe Fernandez704d43b2017-04-18 10:35:38 -07001503 * Sets a tinting option for the image.
Alan Viverette6aa92d12015-08-25 13:19:25 -04001504 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001505 * @param color Color tint to apply.
1506 * @param mode How to apply the color. The standard mode is
1507 * {@link PorterDuff.Mode#SRC_ATOP}
Alan Viverette6aa92d12015-08-25 13:19:25 -04001508 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 * @attr ref android.R.styleable#ImageView_tint
1510 */
1511 public final void setColorFilter(int color, PorterDuff.Mode mode) {
1512 setColorFilter(new PorterDuffColorFilter(color, mode));
1513 }
1514
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001515 /**
1516 * Set a tinting option for the image. Assumes
1517 * {@link PorterDuff.Mode#SRC_ATOP} blending mode.
1518 *
1519 * @param color Color tint to apply.
1520 * @attr ref android.R.styleable#ImageView_tint
1521 */
1522 @RemotableViewMethod
1523 public final void setColorFilter(int color) {
1524 setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
1525 }
1526
Joe Fernandez704d43b2017-04-18 10:35:38 -07001527 /**
1528 * Removes the image's {@link android.graphics.ColorFilter}.
1529 *
1530 * @see #setColorFilter(int)
1531 * @see #getColorFilter()
1532 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 public final void clearColorFilter() {
1534 setColorFilter(null);
1535 }
Philip Milneaac722a2012-03-26 13:30:26 -07001536
1537 /**
Adam Powell31049d72013-10-07 12:58:42 -07001538 * @hide Candidate for future API inclusion
1539 */
1540 public final void setXfermode(Xfermode mode) {
1541 if (mXfermode != mode) {
1542 mXfermode = mode;
Nader Jawade6a63212018-04-20 15:56:10 -07001543 mHasXfermode = true;
1544 applyXfermode();
Adam Powell31049d72013-10-07 12:58:42 -07001545 invalidate();
1546 }
1547 }
1548
1549 /**
Philip Milneaac722a2012-03-26 13:30:26 -07001550 * Returns the active color filter for this ImageView.
1551 *
1552 * @return the active color filter for this ImageView
1553 *
1554 * @see #setColorFilter(android.graphics.ColorFilter)
1555 */
1556 public ColorFilter getColorFilter() {
1557 return mColorFilter;
1558 }
1559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 /**
1561 * Apply an arbitrary colorfilter to the image.
1562 *
1563 * @param cf the colorfilter to apply (may be null)
Philip Milneaac722a2012-03-26 13:30:26 -07001564 *
1565 * @see #getColorFilter()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 */
1567 public void setColorFilter(ColorFilter cf) {
1568 if (mColorFilter != cf) {
1569 mColorFilter = cf;
Alan Viverette91174362014-06-17 14:51:45 -07001570 mHasColorFilter = true;
Nader Jawade6a63212018-04-20 15:56:10 -07001571 applyColorFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 invalidate();
1573 }
1574 }
svetoslavganov75986cf2009-05-14 22:28:01 -07001575
Philip Milneaac722a2012-03-26 13:30:26 -07001576 /**
1577 * Returns the alpha that will be applied to the drawable of this ImageView.
1578 *
Kevin Hufnaglebdb308a2016-09-23 15:54:42 -07001579 * @return the alpha value that will be applied to the drawable of this
1580 * ImageView (between 0 and 255 inclusive, with 0 being transparent and
1581 * 255 being opaque)
Philip Milneaac722a2012-03-26 13:30:26 -07001582 *
1583 * @see #setImageAlpha(int)
1584 */
1585 public int getImageAlpha() {
1586 return mAlpha;
1587 }
1588
1589 /**
1590 * Sets the alpha value that should be applied to the image.
1591 *
Kevin Hufnaglebdb308a2016-09-23 15:54:42 -07001592 * @param alpha the alpha value that should be applied to the image (between
1593 * 0 and 255 inclusive, with 0 being transparent and 255 being opaque)
Philip Milneaac722a2012-03-26 13:30:26 -07001594 *
1595 * @see #getImageAlpha()
1596 */
1597 @RemotableViewMethod
1598 public void setImageAlpha(int alpha) {
1599 setAlpha(alpha);
1600 }
1601
1602 /**
1603 * Sets the alpha value that should be applied to the image.
1604 *
1605 * @param alpha the alpha value that should be applied to the image
1606 *
1607 * @deprecated use #setImageAlpha(int) instead
1608 */
1609 @Deprecated
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001610 @RemotableViewMethod
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 public void setAlpha(int alpha) {
1612 alpha &= 0xFF; // keep it legal
1613 if (mAlpha != alpha) {
1614 mAlpha = alpha;
Nader Jawade6a63212018-04-20 15:56:10 -07001615 mHasAlpha = true;
1616 applyAlpha();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 invalidate();
1618 }
1619 }
1620
Nader Jawade6a63212018-04-20 15:56:10 -07001621 private void applyXfermode() {
1622 if (mDrawable != null && mHasXfermode) {
Jeff Sharkey2b95c242010-02-08 17:40:30 -08001623 mDrawable = mDrawable.mutate();
Adam Powell31049d72013-10-07 12:58:42 -07001624 mDrawable.setXfermode(mXfermode);
Nader Jawade6a63212018-04-20 15:56:10 -07001625 }
1626 }
1627
1628 private void applyColorFilter() {
1629 if (mDrawable != null && mHasColorFilter) {
1630 mDrawable = mDrawable.mutate();
1631 mDrawable.setColorFilter(mColorFilter);
1632 }
1633 }
1634
1635 private void applyAlpha() {
1636 if (mDrawable != null && mHasAlpha) {
1637 mDrawable = mDrawable.mutate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 mDrawable.setAlpha(mAlpha * mViewAlphaScale >> 8);
1639 }
1640 }
Adam Powell37419d72011-11-10 11:32:09 -08001641
Alan Viverettee10dd532013-12-12 19:19:51 -08001642 @Override
1643 public boolean isOpaque() {
1644 return super.isOpaque() || mDrawable != null && mXfermode == null
1645 && mDrawable.getOpacity() == PixelFormat.OPAQUE
1646 && mAlpha * mViewAlphaScale >> 8 == 255
1647 && isFilledByImage();
1648 }
1649
1650 private boolean isFilledByImage() {
1651 if (mDrawable == null) {
1652 return false;
1653 }
1654
1655 final Rect bounds = mDrawable.getBounds();
1656 final Matrix matrix = mDrawMatrix;
1657 if (matrix == null) {
1658 return bounds.left <= 0 && bounds.top <= 0 && bounds.right >= getWidth()
1659 && bounds.bottom >= getHeight();
1660 } else if (matrix.rectStaysRect()) {
1661 final RectF boundsSrc = mTempSrc;
1662 final RectF boundsDst = mTempDst;
1663 boundsSrc.set(bounds);
1664 matrix.mapRect(boundsDst, boundsSrc);
1665 return boundsDst.left <= 0 && boundsDst.top <= 0 && boundsDst.right >= getWidth()
1666 && boundsDst.bottom >= getHeight();
1667 } else {
1668 // If the matrix doesn't map to a rectangle, assume the worst.
1669 return false;
1670 }
1671 }
1672
Adam Powell37419d72011-11-10 11:32:09 -08001673 @Override
Adam Powell9c146bf2016-03-15 17:35:00 -07001674 public void onVisibilityAggregated(boolean isVisible) {
1675 super.onVisibilityAggregated(isVisible);
Adam Powell06f9eb82016-08-24 17:09:01 -07001676 // Only do this for new apps post-Nougat
1677 if (mDrawable != null && !sCompatDrawableVisibilityDispatch) {
Adam Powell9c146bf2016-03-15 17:35:00 -07001678 mDrawable.setVisible(isVisible, false);
Adam Powell37419d72011-11-10 11:32:09 -08001679 }
1680 }
1681
Adam Powell06f9eb82016-08-24 17:09:01 -07001682 @RemotableViewMethod
1683 @Override
1684 public void setVisibility(int visibility) {
1685 super.setVisibility(visibility);
1686 // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
1687 if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
1688 mDrawable.setVisible(visibility == VISIBLE, false);
1689 }
1690 }
1691
1692 @Override
1693 protected void onAttachedToWindow() {
1694 super.onAttachedToWindow();
1695 // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
1696 if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
1697 mDrawable.setVisible(getVisibility() == VISIBLE, false);
1698 }
1699 }
1700
1701 @Override
1702 protected void onDetachedFromWindow() {
1703 super.onDetachedFromWindow();
1704 // Only do this for old apps pre-Nougat; new apps use onVisibilityAggregated
1705 if (mDrawable != null && sCompatDrawableVisibilityDispatch) {
1706 mDrawable.setVisible(false, false);
1707 }
1708 }
1709
Adam Powell37419d72011-11-10 11:32:09 -08001710 @Override
Dianne Hackborna7bb6fb2015-02-03 18:13:40 -08001711 public CharSequence getAccessibilityClassName() {
1712 return ImageView.class.getName();
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08001713 }
Siva Velusamy94a6d152015-05-05 15:07:00 -07001714
1715 /** @hide */
1716 @Override
1717 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) {
1718 super.encodeProperties(stream);
1719 stream.addProperty("layout:baseline", getBaseline());
1720 }
Jiaquan He1dd48d02017-05-01 14:18:39 -07001721
1722 /** @hide */
1723 @Override
1724 @TestApi
1725 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) {
1726 final boolean lackFocusState = mDrawable == null || !mDrawable.isStateful()
1727 || !mDrawable.hasFocusStateSpecified();
1728 return super.isDefaultFocusHighlightNeeded(background, foreground) && lackFocusState;
1729 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730}