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