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