1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.widget.cts;
18 
19 import static org.junit.Assert.assertArrayEquals;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertNotNull;
23 import static org.junit.Assert.assertNotSame;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertSame;
26 import static org.junit.Assert.assertTrue;
27 import static org.junit.Assert.fail;
28 import static org.mockito.Matchers.any;
29 import static org.mockito.Matchers.anyInt;
30 import static org.mockito.Mockito.atLeastOnce;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.spy;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 
36 import android.annotation.Nullable;
37 import android.app.Activity;
38 import android.content.Context;
39 import android.content.res.ColorStateList;
40 import android.graphics.Bitmap;
41 import android.graphics.BitmapFactory;
42 import android.graphics.BlendMode;
43 import android.graphics.BlendModeColorFilter;
44 import android.graphics.Canvas;
45 import android.graphics.Color;
46 import android.graphics.ColorFilter;
47 import android.graphics.Matrix;
48 import android.graphics.PixelFormat;
49 import android.graphics.PorterDuff;
50 import android.graphics.PorterDuff.Mode;
51 import android.graphics.PorterDuffColorFilter;
52 import android.graphics.PorterDuffXfermode;
53 import android.graphics.Rect;
54 import android.graphics.Xfermode;
55 import android.graphics.drawable.BitmapDrawable;
56 import android.graphics.drawable.ColorDrawable;
57 import android.graphics.drawable.Drawable;
58 import android.graphics.drawable.Icon;
59 import android.graphics.drawable.PaintDrawable;
60 import android.net.Uri;
61 import android.util.AttributeSet;
62 import android.util.Xml;
63 import android.view.View;
64 import android.widget.ImageView;
65 import android.widget.ImageView.ScaleType;
66 import android.widget.cts.util.TestUtils;
67 
68 import androidx.test.InstrumentationRegistry;
69 import androidx.test.annotation.UiThreadTest;
70 import androidx.test.filters.MediumTest;
71 import androidx.test.rule.ActivityTestRule;
72 import androidx.test.runner.AndroidJUnit4;
73 
74 import com.android.compatibility.common.util.WidgetTestUtils;
75 
76 import org.junit.Before;
77 import org.junit.Rule;
78 import org.junit.Test;
79 import org.junit.runner.RunWith;
80 import org.xmlpull.v1.XmlPullParser;
81 
82 import java.io.File;
83 import java.io.FileOutputStream;
84 import java.io.IOException;
85 import java.io.InputStream;
86 import java.io.OutputStream;
87 
88 /**
89  * Test {@link ImageView}.
90  */
91 @MediumTest
92 @RunWith(AndroidJUnit4.class)
93 public class ImageViewTest {
94     private Activity mActivity;
95     private ImageView mImageViewRegular;
96 
97     @Rule
98     public ActivityTestRule<ImageViewCtsActivity> mActivityRule =
99             new ActivityTestRule<>(ImageViewCtsActivity.class);
100 
101     @Before
setup()102     public void setup() {
103         mActivity = mActivityRule.getActivity();
104         mImageViewRegular = (ImageView) mActivity.findViewById(R.id.imageview_regular);
105     }
106 
107     /**
108      * Find the ImageView specified by id.
109      *
110      * @param id the id
111      * @return the ImageView
112      */
findImageViewById(int id)113     private ImageView findImageViewById(int id) {
114         return (ImageView) mActivity.findViewById(id);
115     }
116 
createSampleImage(File imagefile, int resid)117     private void createSampleImage(File imagefile, int resid) {
118         try (InputStream source = mActivity.getResources().openRawResource(resid);
119              OutputStream target = new FileOutputStream(imagefile)) {
120             byte[] buffer = new byte[1024];
121             for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
122                 target.write(buffer, 0, len);
123             }
124         } catch (IOException e) {
125             fail(e.getMessage());
126         }
127     }
128 
129     @Test
testConstructor()130     public void testConstructor() {
131         new ImageView(mActivity);
132 
133         new ImageView(mActivity, null);
134 
135         new ImageView(mActivity, null, 0);
136 
137         new ImageView(mActivity, null, 0, 0);
138 
139         XmlPullParser parser = mActivity.getResources().getXml(R.layout.imageview_layout);
140         AttributeSet attrs = Xml.asAttributeSet(parser);
141         new ImageView(mActivity, attrs);
142         new ImageView(mActivity, attrs, 0);
143     }
144 
145 
146     @Test(expected=NullPointerException.class)
testConstructorNullContext1()147     public void testConstructorNullContext1() {
148         new ImageView(null);
149     }
150 
151     @Test(expected=NullPointerException.class)
testConstructorNullContext2()152     public void testConstructorNullContext2() {
153         new ImageView(null, null);
154     }
155 
156     @Test(expected=NullPointerException.class)
testConstructorNullContext3()157     public void testConstructorNullContext3() {
158         new ImageView(null, null, -1);
159     }
160 
161     @UiThreadTest
162     @Test
testConstructorImportantForAutofill()163     public void testConstructorImportantForAutofill() {
164         ImageView imageView = new ImageView(mActivity);
165         assertEquals(View.IMPORTANT_FOR_AUTOFILL_NO, imageView.getImportantForAutofill());
166         assertFalse(imageView.isImportantForAutofill());
167 
168         imageView = new ImageView(mActivity, null);
169         assertEquals(View.IMPORTANT_FOR_AUTOFILL_NO, imageView.getImportantForAutofill());
170         assertFalse(imageView.isImportantForAutofill());
171 
172         imageView = mActivity.findViewById(R.id.imageview_important_auto);
173         assertEquals(View.IMPORTANT_FOR_AUTOFILL_NO, imageView.getImportantForAutofill());
174         assertFalse(imageView.isImportantForAutofill());
175 
176         imageView = mActivity.findViewById(R.id.imageview_important_no);
177         assertEquals(View.IMPORTANT_FOR_AUTOFILL_NO, imageView.getImportantForAutofill());
178         assertFalse(imageView.isImportantForAutofill());
179 
180         imageView = mActivity.findViewById(R.id.imageview_important_yes);
181         assertEquals(View.IMPORTANT_FOR_AUTOFILL_YES, imageView.getImportantForAutofill());
182         assertTrue(imageView.isImportantForAutofill());
183     }
184 
185     @UiThreadTest
186     @Test
testConstructorImportantForContentCapture()187     public void testConstructorImportantForContentCapture() {
188         ImageView imageView = new ImageView(mActivity);
189         assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES,
190                 imageView.getImportantForContentCapture());
191         assertTrue(imageView.isImportantForContentCapture());
192 
193         imageView = new ImageView(mActivity, null);
194         assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES,
195                 imageView.getImportantForContentCapture());
196         assertTrue(imageView.isImportantForContentCapture());
197 
198         imageView = mActivity.findViewById(R.id.imageview_important_auto);
199         assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES,
200                 imageView.getImportantForContentCapture());
201         assertTrue(imageView.isImportantForContentCapture());
202 
203         imageView = mActivity.findViewById(R.id.imageview_important_no);
204         assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_NO,
205                 imageView.getImportantForContentCapture());
206         assertFalse(imageView.isImportantForContentCapture());
207 
208         imageView = mActivity.findViewById(R.id.imageview_important_yes);
209         assertEquals(View.IMPORTANT_FOR_CONTENT_CAPTURE_YES,
210                 imageView.getImportantForContentCapture());
211         assertTrue(imageView.isImportantForContentCapture());
212     }
213 
214     @UiThreadTest
215     @Test
testInvalidateDrawable()216     public void testInvalidateDrawable() {
217         mImageViewRegular.invalidateDrawable(null);
218     }
219 
220     @UiThreadTest
221     @Test
testSetAdjustViewBounds()222     public void testSetAdjustViewBounds() {
223         mImageViewRegular.setScaleType(ScaleType.FIT_XY);
224 
225         mImageViewRegular.setAdjustViewBounds(false);
226         assertFalse(mImageViewRegular.getAdjustViewBounds());
227         assertEquals(ScaleType.FIT_XY, mImageViewRegular.getScaleType());
228 
229         mImageViewRegular.setAdjustViewBounds(true);
230         assertTrue(mImageViewRegular.getAdjustViewBounds());
231         assertEquals(ScaleType.FIT_CENTER, mImageViewRegular.getScaleType());
232     }
233 
234     @UiThreadTest
235     @Test
testSetMaxWidth()236     public void testSetMaxWidth() {
237         mImageViewRegular.setMaxWidth(120);
238         mImageViewRegular.setMaxWidth(-1);
239     }
240 
241     @UiThreadTest
242     @Test
testSetMaxHeight()243     public void testSetMaxHeight() {
244         mImageViewRegular.setMaxHeight(120);
245         mImageViewRegular.setMaxHeight(-1);
246     }
247 
248     @UiThreadTest
249     @Test
testGetDrawable()250     public void testGetDrawable() {
251         final PaintDrawable drawable1 = new PaintDrawable();
252         final PaintDrawable drawable2 = new PaintDrawable();
253 
254         assertNull(mImageViewRegular.getDrawable());
255 
256         mImageViewRegular.setImageDrawable(drawable1);
257         assertEquals(drawable1, mImageViewRegular.getDrawable());
258         assertNotSame(drawable2, mImageViewRegular.getDrawable());
259     }
260 
261     @UiThreadTest
262     @Test
testSetImageIcon()263     public void testSetImageIcon() {
264         mImageViewRegular.setImageIcon(null);
265         assertNull(mImageViewRegular.getDrawable());
266 
267         Icon icon = Icon.createWithResource(mActivity, R.drawable.testimage);
268         mImageViewRegular.setImageIcon(icon);
269         assertTrue(mImageViewRegular.isLayoutRequested());
270         assertNotNull(mImageViewRegular.getDrawable());
271         Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
272         BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
273         Drawable imageViewDrawable = mImageViewRegular.getDrawable();
274         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
275         WidgetTestUtils.assertEquals(testimageBitmap.getBitmap(), imageViewBitmap.getBitmap());
276     }
277 
278     @UiThreadTest
279     @Test
testSetImageResource()280     public void testSetImageResource() {
281         mImageViewRegular.setImageResource(-1);
282         assertNull(mImageViewRegular.getDrawable());
283 
284         mImageViewRegular.setImageResource(R.drawable.testimage);
285         assertTrue(mImageViewRegular.isLayoutRequested());
286         assertNotNull(mImageViewRegular.getDrawable());
287         Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
288         BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
289         Drawable imageViewDrawable = mImageViewRegular.getDrawable();
290         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
291         WidgetTestUtils.assertEquals(testimageBitmap.getBitmap(), imageViewBitmap.getBitmap());
292     }
293 
294     @UiThreadTest
295     @Test
testSetImageURI()296     public void testSetImageURI() {
297         mImageViewRegular.setImageURI(null);
298         assertNull(mImageViewRegular.getDrawable());
299 
300         File dbDir = mActivity.getDir("tests", Context.MODE_PRIVATE);
301         File imagefile = new File(dbDir, "tempimage.jpg");
302         if (imagefile.exists()) {
303             imagefile.delete();
304         }
305         createSampleImage(imagefile, R.raw.testimage);
306         final String path = imagefile.getPath();
307         mImageViewRegular.setImageURI(Uri.parse(path));
308         assertTrue(mImageViewRegular.isLayoutRequested());
309         assertNotNull(mImageViewRegular.getDrawable());
310 
311         Drawable imageViewDrawable = mImageViewRegular.getDrawable();
312         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
313         Bitmap.Config viewConfig = imageViewBitmap.getBitmap().getConfig();
314         Bitmap testimageBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(
315                 mActivity.getResources(), R.raw.testimage, viewConfig);
316 
317         WidgetTestUtils.assertEquals(testimageBitmap, imageViewBitmap.getBitmap());
318     }
319 
320     @UiThreadTest
321     @Test
testSetImageDrawable()322     public void testSetImageDrawable() {
323         mImageViewRegular.setImageDrawable(null);
324         assertNull(mImageViewRegular.getDrawable());
325 
326         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
327         mImageViewRegular.setImageDrawable(drawable);
328         assertTrue(mImageViewRegular.isLayoutRequested());
329         assertNotNull(mImageViewRegular.getDrawable());
330         BitmapDrawable testimageBitmap = (BitmapDrawable) drawable;
331         Drawable imageViewDrawable = mImageViewRegular.getDrawable();
332         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
333         WidgetTestUtils.assertEquals(testimageBitmap.getBitmap(), imageViewBitmap.getBitmap());
334     }
335 
336     @UiThreadTest
337     @Test
testSetImageBitmap()338     public void testSetImageBitmap() {
339         mImageViewRegular.setImageBitmap(null);
340         // A BitmapDrawable is always created for the ImageView.
341         assertNotNull(mImageViewRegular.getDrawable());
342 
343         final Bitmap bitmap =
344             BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.testimage);
345         mImageViewRegular.setImageBitmap(bitmap);
346         assertTrue(mImageViewRegular.isLayoutRequested());
347         assertNotNull(mImageViewRegular.getDrawable());
348         Drawable imageViewDrawable = mImageViewRegular.getDrawable();
349         BitmapDrawable imageViewBitmap = (BitmapDrawable) imageViewDrawable;
350         WidgetTestUtils.assertEquals(bitmap, imageViewBitmap.getBitmap());
351     }
352 
353     @UiThreadTest
354     @Test
testSetImageState()355     public void testSetImageState() {
356         int[] state = new int[8];
357         mImageViewRegular.setImageState(state, false);
358         assertSame(state, mImageViewRegular.onCreateDrawableState(0));
359     }
360 
361     @UiThreadTest
362     @Test
testSetSelected()363     public void testSetSelected() {
364         assertFalse(mImageViewRegular.isSelected());
365 
366         mImageViewRegular.setSelected(true);
367         assertTrue(mImageViewRegular.isSelected());
368 
369         mImageViewRegular.setSelected(false);
370         assertFalse(mImageViewRegular.isSelected());
371     }
372 
373     @UiThreadTest
374     @Test
testSetImageLevel()375     public void testSetImageLevel() {
376         PaintDrawable drawable = new PaintDrawable();
377         drawable.setLevel(0);
378 
379         mImageViewRegular.setImageDrawable(drawable);
380         mImageViewRegular.setImageLevel(1);
381         assertEquals(1, drawable.getLevel());
382     }
383 
384     @UiThreadTest
385     @Test
testAccessScaleType()386     public void testAccessScaleType() {
387         assertNotNull(mImageViewRegular.getScaleType());
388 
389         mImageViewRegular.setScaleType(ImageView.ScaleType.CENTER);
390         assertEquals(ImageView.ScaleType.CENTER, mImageViewRegular.getScaleType());
391 
392         mImageViewRegular.setScaleType(ImageView.ScaleType.MATRIX);
393         assertEquals(ImageView.ScaleType.MATRIX, mImageViewRegular.getScaleType());
394 
395         mImageViewRegular.setScaleType(ImageView.ScaleType.FIT_START);
396         assertEquals(ImageView.ScaleType.FIT_START, mImageViewRegular.getScaleType());
397 
398         mImageViewRegular.setScaleType(ImageView.ScaleType.FIT_END);
399         assertEquals(ImageView.ScaleType.FIT_END, mImageViewRegular.getScaleType());
400 
401         mImageViewRegular.setScaleType(ImageView.ScaleType.CENTER_CROP);
402         assertEquals(ImageView.ScaleType.CENTER_CROP, mImageViewRegular.getScaleType());
403 
404         mImageViewRegular.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
405         assertEquals(ImageView.ScaleType.CENTER_INSIDE, mImageViewRegular.getScaleType());
406     }
407 
408     @UiThreadTest
409     @Test(expected=NullPointerException.class)
testSetNullScaleType()410     public void testSetNullScaleType() {
411         mImageViewRegular.setScaleType(null);
412     }
413 
414     @UiThreadTest
415     @Test
testAccessImageMatrix()416     public void testAccessImageMatrix() {
417         mImageViewRegular.setImageMatrix(null);
418         assertNotNull(mImageViewRegular.getImageMatrix());
419 
420         final Matrix matrix = new Matrix();
421         mImageViewRegular.setImageMatrix(matrix);
422         assertEquals(matrix, mImageViewRegular.getImageMatrix());
423     }
424 
425     @UiThreadTest
426     @Test
testAccessBaseline()427     public void testAccessBaseline() {
428         mImageViewRegular.setImageDrawable(null);
429         assertNull(mImageViewRegular.getDrawable());
430 
431         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
432         mImageViewRegular.setImageDrawable(drawable);
433 
434         assertEquals(-1, mImageViewRegular.getBaseline());
435 
436         mImageViewRegular.setBaseline(50);
437         assertEquals(50, mImageViewRegular.getBaseline());
438 
439         mImageViewRegular.setBaselineAlignBottom(true);
440         assertTrue(mImageViewRegular.getBaselineAlignBottom());
441         assertEquals(mImageViewRegular.getMeasuredHeight(), mImageViewRegular.getBaseline());
442 
443         mImageViewRegular.setBaselineAlignBottom(false);
444         assertFalse(mImageViewRegular.getBaselineAlignBottom());
445         assertEquals(50, mImageViewRegular.getBaseline());
446     }
447 
448     @UiThreadTest
449     @Test
testSetColorFilter1()450     public void testSetColorFilter1() {
451         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
452         mImageViewRegular.setImageDrawable(drawable);
453 
454         mImageViewRegular.setColorFilter(null);
455         assertNull(drawable.getColorFilter());
456 
457         mImageViewRegular.setColorFilter(0, PorterDuff.Mode.CLEAR);
458         assertNotNull(drawable.getColorFilter());
459         assertNotNull(mImageViewRegular.getColorFilter());
460     }
461 
462     @UiThreadTest
463     @Test
testSetColorFilterTintBlendMode()464     public void testSetColorFilterTintBlendMode() {
465         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
466         mImageViewRegular.setImageDrawable(drawable);
467 
468         mImageViewRegular.setColorFilter(null);
469         assertNull(drawable.getColorFilter());
470 
471         mImageViewRegular.setColorFilter(new BlendModeColorFilter(0, BlendMode.CLEAR));
472         assertNotNull(drawable.getColorFilter());
473         assertNotNull(mImageViewRegular.getColorFilter());
474     }
475 
476     @UiThreadTest
477     @Test
testClearColorFilter()478     public void testClearColorFilter() {
479         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
480         mImageViewRegular.setImageDrawable(drawable);
481 
482         ColorFilter cf = new ColorFilter();
483         mImageViewRegular.setColorFilter(cf);
484 
485         mImageViewRegular.clearColorFilter();
486         assertNull(drawable.getColorFilter());
487         assertNull(mImageViewRegular.getColorFilter());
488     }
489 
490     @UiThreadTest
491     @Test
testSetColorFilter2()492     public void testSetColorFilter2() {
493         final Drawable drawable = mActivity.getDrawable(R.drawable.testimage);
494         mImageViewRegular.setImageDrawable(drawable);
495 
496         mImageViewRegular.setColorFilter(null);
497         assertNull(drawable.getColorFilter());
498         assertNull(mImageViewRegular.getColorFilter());
499 
500         ColorFilter cf = new ColorFilter();
501         mImageViewRegular.setColorFilter(cf);
502         assertSame(cf, drawable.getColorFilter());
503         assertSame(cf, mImageViewRegular.getColorFilter());
504     }
505 
506     @Test
testDrawableStateChanged()507     public void testDrawableStateChanged() {
508         MockImageView imageView = spy(new MockImageView(mActivity));
509         Drawable selectorDrawable = mActivity.getDrawable(R.drawable.statelistdrawable);
510         imageView.setImageDrawable(selectorDrawable);
511 
512         // We shouldn't have been called on state change yet
513         verify(imageView, never()).drawableStateChanged();
514         // Mark image view as selected. Since our selector drawable has an "entry" for selected
515         // state, that should cause a call to drawableStateChanged()
516         imageView.setSelected(true);
517         // Test that our image view has indeed called its own drawableStateChanged()
518         verify(imageView, times(1)).drawableStateChanged();
519         // And verify that image view's state matches that of our drawable
520         assertArrayEquals(imageView.getDrawableState(), selectorDrawable.getState());
521     }
522 
523     @Test
testOnCreateDrawableState()524     public void testOnCreateDrawableState() {
525         MockImageView mockImageView = new MockImageView(mActivity);
526 
527         assertArrayEquals(MockImageView.getEnabledStateSet(),
528                 mockImageView.onCreateDrawableState(0));
529 
530         int[] expected = new int[]{1, 2, 3};
531         mockImageView.setImageState(expected, false);
532         assertArrayEquals(expected, mockImageView.onCreateDrawableState(1));
533 
534         mockImageView.setImageState(expected, true);
535     }
536 
537     @Test(expected=IndexOutOfBoundsException.class)
testOnCreateDrawableStateInvalid()538     public void testOnCreateDrawableStateInvalid() {
539         MockImageView mockImageView = (MockImageView) findImageViewById(R.id.imageview_custom);
540         mockImageView.setImageState(new int[] {1, 2, 3}, true);
541         mockImageView.onCreateDrawableState(-1);
542     }
543 
544     @UiThreadTest
545     @Test
testOnDraw()546     public void testOnDraw() {
547         MockImageView mockImageView = (MockImageView) findImageViewById(R.id.imageview_custom);
548 
549         Drawable drawable = spy(mActivity.getDrawable(R.drawable.icon_red));
550         mockImageView.setImageDrawable(drawable);
551         mockImageView.onDraw(new Canvas());
552 
553         verify(drawable, atLeastOnce()).draw(any(Canvas.class));
554     }
555 
556     @UiThreadTest
557     @Test
testOnMeasure()558     public void testOnMeasure() {
559         mImageViewRegular.measure(200, 150);
560         assertTrue(mImageViewRegular.getMeasuredWidth() <= 200);
561         assertTrue(mImageViewRegular.getMeasuredHeight() <= 150);
562     }
563 
564     @Test
testSetFrame()565     public void testSetFrame() {
566         MockImageView mockImageView = spy(new MockImageView(mActivity));
567         verify(mockImageView, never()).onSizeChanged(anyInt(), anyInt(), anyInt(), anyInt());
568 
569         assertTrue(mockImageView.setFrame(5, 10, 100, 200));
570         assertEquals(5, mockImageView.getLeft());
571         assertEquals(10, mockImageView.getTop());
572         assertEquals(100, mockImageView.getRight());
573         assertEquals(200, mockImageView.getBottom());
574         verify(mockImageView, times(1)).onSizeChanged(95, 190, 0, 0);
575 
576         assertFalse(mockImageView.setFrame(5, 10, 100, 200));
577         // Verify that there were no more calls to onSizeChanged (since the new frame is the
578         // same frame as we had before).
579         verify(mockImageView, times(1)).onSizeChanged(anyInt(), anyInt(), anyInt(), anyInt());
580     }
581 
582     @Test
testSetColorFilterPreservesDrawableProperties()583     public void testSetColorFilterPreservesDrawableProperties() {
584         ImageView imageView = new ImageView(InstrumentationRegistry.getTargetContext());
585 
586         int colorAlpha = 128;
587         MockDrawable mockDrawable = new MockDrawable();
588         mockDrawable.setAlpha(colorAlpha);
589         mockDrawable.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
590 
591         imageView.setImageDrawable(mockDrawable);
592 
593         imageView.setColorFilter(Color.RED);
594         assertEquals(colorAlpha, mockDrawable.getAlpha());
595         assertNotNull(mockDrawable.getXfermode());
596     }
597 
598     @Test
testSetColorFilterPreservesDrawablePropertiesTintBlendMode()599     public void testSetColorFilterPreservesDrawablePropertiesTintBlendMode() {
600         ImageView imageView = new ImageView(InstrumentationRegistry.getTargetContext());
601 
602         int colorAlpha = 128;
603         MockDrawable mockDrawable = new MockDrawable();
604         mockDrawable.setAlpha(colorAlpha);
605         mockDrawable.setTintBlendMode(BlendMode.SRC_IN);
606 
607         imageView.setImageDrawable(mockDrawable);
608 
609         imageView.setColorFilter(Color.RED);
610         assertEquals(colorAlpha, mockDrawable.getAlpha());
611         assertNotNull(mockDrawable.getBlendMode());
612     }
613 
614     @Test
testImageViewSetColorFilterPropagatedToDrawable()615     public void testImageViewSetColorFilterPropagatedToDrawable() {
616         ImageView imageView = new ImageView(InstrumentationRegistry.getTargetContext());
617 
618         MockDrawable mockDrawable = new MockDrawable();
619         imageView.setImageDrawable(mockDrawable);
620         imageView.setColorFilter(Color.RED);
621 
622         ColorFilter imageViewColorFilter = imageView.getColorFilter();
623         assertTrue(imageViewColorFilter instanceof PorterDuffColorFilter);
624 
625         PorterDuffColorFilter imageViewPorterDuffFilter =
626                 (PorterDuffColorFilter) imageViewColorFilter;
627         assertEquals(Color.RED, imageViewPorterDuffFilter.getColor());
628         assertEquals(Mode.SRC_ATOP, imageViewPorterDuffFilter.getMode());
629 
630         ColorFilter colorFilter = mockDrawable.getColorFilter();
631         assertTrue(colorFilter instanceof PorterDuffColorFilter);
632 
633         PorterDuffColorFilter porterDuffColorFilter = (PorterDuffColorFilter) colorFilter;
634         assertEquals(Color.RED, porterDuffColorFilter.getColor());
635         assertEquals(PorterDuff.Mode.SRC_ATOP, porterDuffColorFilter.getMode());
636     }
637 
638     @UiThreadTest
639     @Test
testVerifyDrawable()640     public void testVerifyDrawable() {
641         MockImageView mockImageView = (MockImageView) findImageViewById(R.id.imageview_custom);
642 
643         Drawable drawable = new ColorDrawable(0xFFFF0000);
644         mockImageView.setImageDrawable(drawable);
645         Drawable backgroundDrawable = new ColorDrawable(0xFF0000FF);
646         mockImageView.setBackgroundDrawable(backgroundDrawable);
647 
648         assertFalse(mockImageView.verifyDrawable(new ColorDrawable(0xFF00FF00)));
649         assertTrue(mockImageView.verifyDrawable(drawable));
650         assertTrue(mockImageView.verifyDrawable(backgroundDrawable));
651     }
652 
653     @UiThreadTest
654     @Test
testImageTintBasics()655     public void testImageTintBasics() {
656         ImageView imageViewTinted = (ImageView) mActivity.findViewById(R.id.imageview_tint);
657 
658         assertEquals("Image tint inflated correctly",
659                 Color.WHITE, imageViewTinted.getImageTintList().getDefaultColor());
660         assertEquals("Image tint mode inflated correctly",
661                 PorterDuff.Mode.SRC_OVER, imageViewTinted.getImageTintMode());
662 
663         imageViewTinted.setImageTintMode(PorterDuff.Mode.SRC_IN);
664         assertEquals(PorterDuff.Mode.SRC_IN, imageViewTinted.getImageTintMode());
665     }
666 
667     @UiThreadTest
668     @Test
testImageTintBlendModeBasics()669     public void testImageTintBlendModeBasics() {
670         ImageView imageViewTinted = (ImageView) mActivity.findViewById(R.id.imageview_tint);
671 
672         assertEquals("Image tint inflated correctly",
673                 Color.WHITE, imageViewTinted.getImageTintList().getDefaultColor());
674         assertEquals("Image tint mode inflated correctly",
675                 BlendMode.SRC_OVER, imageViewTinted.getImageTintBlendMode());
676 
677         imageViewTinted.setImageTintMode(PorterDuff.Mode.SRC_IN);
678         assertEquals(BlendMode.SRC_IN, imageViewTinted.getImageTintBlendMode());
679     }
680 
681     @UiThreadTest
682     @Test
testImageTintDrawableUpdates()683     public void testImageTintDrawableUpdates() {
684         Drawable drawable = spy(mActivity.getDrawable(R.drawable.icon_red));
685 
686         mImageViewRegular.setImageDrawable(drawable);
687         // No image tint applied by default
688         verify(drawable, never()).setTintList(any(ColorStateList.class));
689 
690         mImageViewRegular.setImageTintList(ColorStateList.valueOf(Color.WHITE));
691         // Image tint applied when setImageTintList() called after setImageDrawable()
692         verify(drawable, times(1)).setTintList(any(ColorStateList.class));
693 
694         mImageViewRegular.setImageDrawable(null);
695         mImageViewRegular.setImageDrawable(drawable);
696         // Image tint applied when setImageTintList() called before setImageDrawable()
697         verify(drawable, times(2)).setTintList(any(ColorStateList.class));
698     }
699 
700     @UiThreadTest
701     @Test
testImageTintVisuals()702     public void testImageTintVisuals() {
703         ImageView imageViewTinted = (ImageView) mActivity.findViewById(
704                 R.id.imageview_tint_with_source);
705 
706         TestUtils.assertAllPixelsOfColor("All pixels should be white", imageViewTinted,
707                 0xFFFFFFFF, 1, false);
708 
709         // Use translucent white tint. Together with SRC_OVER mode (defined in XML) the end
710         // result should be a fully opaque image view with solid fill color in between red
711         // and white.
712         imageViewTinted.setImageTintList(ColorStateList.valueOf(0x80FFFFFF));
713         TestUtils.assertAllPixelsOfColor("All pixels should be light red", imageViewTinted,
714                 0xFFFF8080, 1, false);
715 
716         // Switch to SRC_IN mode. This should completely ignore the original drawable set on
717         // the image view and use the last set tint color (50% alpha white).
718         imageViewTinted.setImageTintMode(PorterDuff.Mode.SRC_IN);
719         TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha white", imageViewTinted,
720                 0x80FFFFFF, 1, false);
721 
722         // Switch to DST mode. This should completely ignore the last set tint color and use the
723         // the original drawable set on the image view.
724         imageViewTinted.setImageTintMode(PorterDuff.Mode.DST);
725         TestUtils.assertAllPixelsOfColor("All pixels should be red", imageViewTinted,
726                 0xFFFF0000, 1, false);
727     }
728 
729     @UiThreadTest
730     @Test
testImageTintBlendModeVisuals()731     public void testImageTintBlendModeVisuals() {
732         ImageView imageViewTinted = (ImageView) mActivity.findViewById(
733                 R.id.imageview_tint_with_source);
734 
735         TestUtils.assertAllPixelsOfColor("All pixels should be white", imageViewTinted,
736                 0xFFFFFFFF, 1, false);
737 
738         // Use translucent white tint. Together with SRC_OVER mode (defined in XML) the end
739         // result should be a fully opaque image view with solid fill color in between red
740         // and white.
741         imageViewTinted.setImageTintList(ColorStateList.valueOf(0x80FFFFFF));
742         TestUtils.assertAllPixelsOfColor("All pixels should be light red", imageViewTinted,
743                 0xFFFF8080, 1, false);
744 
745         // Switch to SRC_IN mode. This should completely ignore the original drawable set on
746         // the image view and use the last set tint color (50% alpha white).
747         imageViewTinted.setImageTintBlendMode(BlendMode.SRC_IN);
748         TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha white", imageViewTinted,
749                 0x80FFFFFF, 1, false);
750 
751         // Switch to DST mode. This should completely ignore the last set tint color and use the
752         // the original drawable set on the image view.
753         imageViewTinted.setImageTintBlendMode(BlendMode.DST);
754         TestUtils.assertAllPixelsOfColor("All pixels should be red", imageViewTinted,
755                 0xFFFF0000, 1, false);
756     }
757 
758     @UiThreadTest
759     @Test
testAlpha()760     public void testAlpha() {
761         mImageViewRegular.setImageResource(R.drawable.blue_fill);
762 
763         TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageViewRegular,
764                 0xFF0000FF, 1, false);
765 
766         mImageViewRegular.setAlpha(128);
767         TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha blue", mImageViewRegular,
768                 0x800000FF, 1, false);
769 
770         mImageViewRegular.setAlpha(0);
771         TestUtils.assertAllPixelsOfColor("All pixels should be transparent", mImageViewRegular,
772                 0x00000000, 1, false);
773 
774         mImageViewRegular.setAlpha(255);
775         TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageViewRegular,
776                 0xFF0000FF, 1, false);
777     }
778 
779     @UiThreadTest
780     @Test
testImageAlpha()781     public void testImageAlpha() {
782         mImageViewRegular.setImageResource(R.drawable.blue_fill);
783 
784         assertEquals(255, mImageViewRegular.getImageAlpha());
785         TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageViewRegular,
786                 0xFF0000FF, 1, false);
787 
788         mImageViewRegular.setImageAlpha(128);
789         assertEquals(128, mImageViewRegular.getImageAlpha());
790         TestUtils.assertAllPixelsOfColor("All pixels should be 50% alpha blue", mImageViewRegular,
791                 0x800000FF, 1, false);
792 
793         mImageViewRegular.setImageAlpha(0);
794         assertEquals(0, mImageViewRegular.getImageAlpha());
795         TestUtils.assertAllPixelsOfColor("All pixels should be transparent", mImageViewRegular,
796                 0x00000000, 1, false);
797 
798         mImageViewRegular.setImageAlpha(255);
799         assertEquals(255, mImageViewRegular.getImageAlpha());
800         TestUtils.assertAllPixelsOfColor("All pixels should be blue", mImageViewRegular,
801                 0xFF0000FF, 1, false);
802     }
803 
804     @UiThreadTest
805     @Test
testAnimateTransform()806     public void testAnimateTransform() {
807         Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8);
808         mImageViewRegular.setScaleType(ScaleType.FIT_XY);
809         mImageViewRegular.setImageBitmap(bitmap);
810         Rect viewRect = new Rect(0, 0, mImageViewRegular.getWidth(), mImageViewRegular.getHeight());
811         Rect bitmapRect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
812 
813         assertEquals(viewRect, mImageViewRegular.getDrawable().getBounds());
814         assertTrue(mImageViewRegular.getImageMatrix().isIdentity());
815 
816         Matrix matrix = new Matrix();
817         mImageViewRegular.animateTransform(matrix);
818 
819         assertEquals(bitmapRect, mImageViewRegular.getDrawable().getBounds());
820         assertEquals(matrix, mImageViewRegular.getImageMatrix());
821 
822         // clear temporary transformation
823         mImageViewRegular.setImageBitmap(bitmap);
824 
825         assertEquals(viewRect, mImageViewRegular.getDrawable().getBounds());
826         assertTrue(mImageViewRegular.getImageMatrix().isIdentity());
827     }
828 
829     @UiThreadTest
830     @Test
testAnimateTransformWithNullPassed()831     public void testAnimateTransformWithNullPassed() {
832         Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8);
833         mImageViewRegular.setScaleType(ScaleType.CENTER);
834         mImageViewRegular.setImageBitmap(bitmap);
835         Rect viewRect = new Rect(0, 0, mImageViewRegular.getWidth(), mImageViewRegular.getHeight());
836         Rect bitmapRect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
837 
838         assertEquals(bitmapRect, mImageViewRegular.getDrawable().getBounds());
839         assertFalse(mImageViewRegular.getImageMatrix().isIdentity());
840 
841         mImageViewRegular.animateTransform(null);
842 
843         assertEquals(viewRect, mImageViewRegular.getDrawable().getBounds());
844         assertTrue(mImageViewRegular.getImageMatrix().isIdentity());
845 
846         // clear temporary transformation
847         mImageViewRegular.setImageBitmap(bitmap);
848 
849         assertEquals(bitmapRect, mImageViewRegular.getDrawable().getBounds());
850         assertFalse(mImageViewRegular.getImageMatrix().isIdentity());
851     }
852 
853     public static class MockImageView extends ImageView {
MockImageView(Context context)854         public MockImageView(Context context) {
855             super(context);
856         }
857 
MockImageView(Context context, AttributeSet attrs)858         public MockImageView(Context context, AttributeSet attrs) {
859             super(context, attrs);
860         }
861 
MockImageView(Context context, AttributeSet attrs, int defStyle)862         public MockImageView(Context context, AttributeSet attrs, int defStyle) {
863             super(context, attrs, defStyle);
864         }
865 
getEnabledStateSet()866         public static int[] getEnabledStateSet() {
867             return ENABLED_STATE_SET;
868         }
869 
870         @Override
drawableStateChanged()871         protected void drawableStateChanged() {
872             super.drawableStateChanged();
873         }
874 
875         @Override
onDraw(Canvas canvas)876         protected void onDraw(Canvas canvas) {
877             super.onDraw(canvas);
878         }
879 
880         @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)881         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
882             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
883         }
884 
885         @Override
onSetAlpha(int alpha)886         protected boolean onSetAlpha(int alpha) {
887             return super.onSetAlpha(alpha);
888         }
889 
890         @Override
setFrame(int l, int t, int r, int b)891         protected boolean setFrame(int l, int t, int r, int b) {
892             return super.setFrame(l, t, r, b);
893         }
894 
895         @Override
verifyDrawable(Drawable dr)896         protected boolean verifyDrawable(Drawable dr) {
897             return super.verifyDrawable(dr);
898         }
899 
onSizeChanged(int w, int h, int oldw, int oldh)900         protected void onSizeChanged(int w, int h, int oldw, int oldh) {
901             super.onSizeChanged(w, h, oldw, oldh);
902         }
903     }
904 
905     public static class MockDrawable extends Drawable {
906 
907         private ColorFilter mFilter;
908         private int mAlpha;
909         private Xfermode mXfermode;
910         private BlendMode mBlendMode;
911 
912         @Override
draw(Canvas canvas)913         public void draw(Canvas canvas) {
914             // NO-OP
915         }
916 
917         @Override
setAlpha(int alpha)918         public void setAlpha(int alpha) {
919             mAlpha = alpha;
920         }
921 
getAlpha()922         public int getAlpha() {
923             return mAlpha;
924         }
925 
926         @Override
setColorFilter(ColorFilter colorFilter)927         public void setColorFilter(ColorFilter colorFilter) {
928             mFilter = colorFilter;
929         }
930 
931         @Override
setXfermode(Xfermode mode)932         public void setXfermode(Xfermode mode) {
933             mXfermode = mode;
934         }
935 
936         @Override
setTintBlendMode(BlendMode mode)937         public void setTintBlendMode(BlendMode mode) {
938             mBlendMode = mode;
939         }
940 
getXfermode()941         public @Nullable Xfermode getXfermode() {
942             return mXfermode;
943         }
944 
getBlendMode()945         public @Nullable BlendMode getBlendMode() {
946             return mBlendMode;
947         }
948 
949         @Override
getColorFilter()950         public @Nullable ColorFilter getColorFilter() {
951             return mFilter;
952         }
953 
954         @Override
getOpacity()955         public int getOpacity() {
956             return PixelFormat.TRANSLUCENT;
957         }
958     }
959 }
960