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.graphics.drawable.cts;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertNotNull;
22 import static org.junit.Assert.assertNotSame;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertSame;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27 import static org.mockito.ArgumentMatchers.anyInt;
28 import static org.mockito.Matchers.any;
29 import static org.mockito.Matchers.anyBoolean;
30 import static org.mockito.Matchers.anyLong;
31 import static org.mockito.Mockito.doAnswer;
32 import static org.mockito.Mockito.doNothing;
33 import static org.mockito.Mockito.doReturn;
34 import static org.mockito.Mockito.mock;
35 import static org.mockito.Mockito.never;
36 import static org.mockito.Mockito.reset;
37 import static org.mockito.Mockito.spy;
38 import static org.mockito.Mockito.times;
39 import static org.mockito.Mockito.verify;
40 
41 import android.content.Context;
42 import android.content.res.ColorStateList;
43 import android.content.res.Resources;
44 import android.content.res.Resources.Theme;
45 import android.content.res.XmlResourceParser;
46 import android.graphics.BitmapFactory;
47 import android.graphics.Canvas;
48 import android.graphics.Color;
49 import android.graphics.ColorFilter;
50 import android.graphics.PixelFormat;
51 import android.graphics.PorterDuff;
52 import android.graphics.Rect;
53 import android.graphics.cts.R;
54 import android.graphics.drawable.BitmapDrawable;
55 import android.graphics.drawable.ColorDrawable;
56 import android.graphics.drawable.Drawable;
57 import android.graphics.drawable.Drawable.ConstantState;
58 import android.graphics.drawable.GradientDrawable;
59 import android.graphics.drawable.LayerDrawable;
60 import android.graphics.drawable.RippleDrawable;
61 import android.graphics.drawable.RotateDrawable;
62 import android.graphics.drawable.ShapeDrawable;
63 import android.graphics.drawable.StateListDrawable;
64 import android.util.AttributeSet;
65 import android.util.StateSet;
66 import android.util.Xml;
67 import android.view.Gravity;
68 import android.view.View;
69 
70 import androidx.test.InstrumentationRegistry;
71 import androidx.test.filters.SmallTest;
72 import androidx.test.runner.AndroidJUnit4;
73 
74 import org.junit.Before;
75 import org.junit.Test;
76 import org.junit.runner.RunWith;
77 import org.xmlpull.v1.XmlPullParserException;
78 
79 import java.io.IOException;
80 
81 @SmallTest
82 @RunWith(AndroidJUnit4.class)
83 public class LayerDrawableTest {
84     private Context mContext;
85     private ColorDrawable mColorDrawable;
86     private BitmapDrawable mBitmapDrawable;
87 
88     @Before
setup()89     public void setup() {
90         mContext = InstrumentationRegistry.getTargetContext();
91         Resources resources = mContext.getResources();
92         mColorDrawable = new ColorDrawable(Color.BLUE);
93         mBitmapDrawable = new BitmapDrawable(resources,
94                 BitmapFactory.decodeResource(resources, R.drawable.icon_blue));
95     }
96 
97     @Test
testConstructor()98     public void testConstructor() {
99         Drawable[] array = new Drawable[]{mBitmapDrawable, mColorDrawable};
100         LayerDrawable layerDrawable = new LayerDrawable(array);
101         assertEquals(array.length, layerDrawable.getNumberOfLayers());
102         assertSame(mBitmapDrawable, layerDrawable.getDrawable(0));
103         assertSame(mColorDrawable, layerDrawable.getDrawable(1));
104 
105         array = new Drawable[0];
106         layerDrawable = new LayerDrawable(array);
107         assertEquals(0, layerDrawable.getNumberOfLayers());
108     }
109 
110     @Test(expected=IllegalArgumentException.class)
testConstructorNull()111     public void testConstructorNull() {
112         new LayerDrawable(null);
113     }
114 
115     @Test
testInflate()116     public void testInflate() throws XmlPullParserException, IOException {
117         Drawable[] array = new Drawable[0];
118         LayerDrawable layerDrawable = new LayerDrawable(array);
119 
120         XmlResourceParser parser = mContext.getResources().getXml(R.xml.layerdrawable);
121         AttributeSet attrs = DrawableTestUtils.getAttributeSet(parser, "layer-list_full");
122 
123         layerDrawable.inflate(mContext.getResources(), parser, attrs);
124 
125         assertEquals(4, layerDrawable.getNumberOfLayers());
126         assertEquals(ColorDrawable.class, layerDrawable.getDrawable(0).getClass());
127         assertEquals(0x88, layerDrawable.getDrawable(0).getAlpha());
128         assertEquals(View.NO_ID, layerDrawable.getId(0));
129         assertEquals(BitmapDrawable.class, layerDrawable.getDrawable(1).getClass());
130         assertEquals(View.NO_ID, layerDrawable.getId(1));
131         assertEquals(RotateDrawable.class, layerDrawable.getDrawable(2).getClass());
132         assertEquals(View.NO_ID, layerDrawable.getId(2));
133         assertEquals(GradientDrawable.class, layerDrawable.getDrawable(3).getClass());
134         assertEquals(R.id.background, layerDrawable.getId(3));
135 
136         layerDrawable = new LayerDrawable(array);
137         parser = mContext.getResources().getXml(R.xml.layerdrawable);
138         attrs = DrawableTestUtils.getAttributeSet(parser, "layer-list_empty");
139         layerDrawable.inflate(mContext.getResources(), parser, attrs);
140         assertEquals(0, layerDrawable.getNumberOfLayers());
141 
142         parser = mContext.getResources().getXml(R.xml.layerdrawable);
143         attrs = DrawableTestUtils.getAttributeSet(parser, "layer-list_exception");
144         try {
145             layerDrawable.inflate(mContext.getResources(), parser, attrs);
146             fail("Should throw XmlPullParserException if neither 'drawable' attribute" +
147                     " nor child tag defining a drawable in <item> tag.");
148         } catch (XmlPullParserException e) {
149         }
150 
151         try {
152             layerDrawable.inflate(null, parser, attrs);
153             fail("Should throw NullPointerException if resource is null");
154         } catch (NullPointerException e) {
155         }
156 
157         try {
158             layerDrawable.inflate(mContext.getResources(), null, attrs);
159             fail("Should throw NullPointerException if parser is null");
160         } catch (NullPointerException e) {
161         }
162 
163         try {
164             layerDrawable.inflate(mContext.getResources(), parser, null);
165             fail("Should throw NullPointerException if attribute set is null");
166         } catch (NullPointerException e) {
167         }
168     }
169 
170     @Test
testFindDrawableByLayerId()171     public void testFindDrawableByLayerId() {
172         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
173         LayerDrawable layerDrawable = new LayerDrawable(array);
174 
175         layerDrawable.setId(0, 10);
176         layerDrawable.setId(1, 20);
177         assertSame(mBitmapDrawable, layerDrawable.findDrawableByLayerId(10));
178         assertSame(mColorDrawable, layerDrawable.findDrawableByLayerId(20));
179         assertNull(layerDrawable.findDrawableByLayerId(30));
180 
181         layerDrawable.setId(0, Integer.MIN_VALUE);
182         layerDrawable.setId(1, Integer.MAX_VALUE);
183         assertSame(mBitmapDrawable, layerDrawable.findDrawableByLayerId(Integer.MIN_VALUE));
184         assertSame(mColorDrawable, layerDrawable.findDrawableByLayerId(Integer.MAX_VALUE));
185 
186         layerDrawable.setId(0, 10);
187         layerDrawable.setId(1, 10);
188         assertSame(mColorDrawable, layerDrawable.findDrawableByLayerId(10));
189         assertNull(layerDrawable.findDrawableByLayerId(30));
190     }
191 
192     @Test
testAccessId()193     public void testAccessId() {
194         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
195         LayerDrawable layerDrawable = new LayerDrawable(array);
196 
197         layerDrawable.setId(0, 10);
198         layerDrawable.setId(1, 20);
199         assertEquals(10, layerDrawable.getId(0));
200         assertEquals(20, layerDrawable.getId(1));
201 
202         layerDrawable.setId(0, Integer.MIN_VALUE);
203         layerDrawable.setId(1, Integer.MAX_VALUE);
204         assertEquals(Integer.MIN_VALUE, layerDrawable.getId(0));
205         assertEquals(Integer.MAX_VALUE, layerDrawable.getId(1));
206     }
207 
208     @Test(expected=IndexOutOfBoundsException.class)
testSetIdIndexTooLow()209     public void testSetIdIndexTooLow() {
210         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
211         LayerDrawable layerDrawable = new LayerDrawable(array);
212         layerDrawable.setId(-1, 20);
213     }
214 
215     @Test(expected=IndexOutOfBoundsException.class)
testSetIdIndexTooHigh()216     public void testSetIdIndexTooHigh() {
217         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
218         LayerDrawable layerDrawable = new LayerDrawable(array);
219         layerDrawable.setId(layerDrawable.getNumberOfLayers(), 20);
220     }
221 
222     @Test(expected=IndexOutOfBoundsException.class)
testGetIdIndexTooLow()223     public void testGetIdIndexTooLow() {
224         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
225         LayerDrawable layerDrawable = new LayerDrawable(array);
226         layerDrawable.getId(-1);
227     }
228 
229     @Test(expected=IndexOutOfBoundsException.class)
testGetIdIndexTooHigh()230     public void testGetIdIndexTooHigh() {
231         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
232         LayerDrawable layerDrawable = new LayerDrawable(array);
233         layerDrawable.getId(layerDrawable.getNumberOfLayers());
234     }
235 
236     @Test
testGetNumberOfLayers()237     public void testGetNumberOfLayers() {
238         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
239         LayerDrawable layerDrawable = new LayerDrawable(array);
240         assertEquals(2, layerDrawable.getNumberOfLayers());
241 
242         array = new Drawable[5];
243         for (int i = 0; i < 5; i++) {
244             array[i] = new BitmapDrawable();
245         }
246         layerDrawable = new LayerDrawable(array);
247         assertEquals(5, layerDrawable.getNumberOfLayers());
248 
249         array = new Drawable[0];
250         layerDrawable = new LayerDrawable(array);
251         assertEquals(0, layerDrawable.getNumberOfLayers());
252     }
253 
254     @Test
testAccessDrawable()255     public void testAccessDrawable() {
256         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
257         LayerDrawable layerDrawable = new LayerDrawable(array);
258         assertSame(mBitmapDrawable, layerDrawable.getDrawable(0));
259         assertSame(mColorDrawable, layerDrawable.getDrawable(1));
260 
261         layerDrawable.setId(0, 10);
262         layerDrawable.setId(1, 20);
263         Drawable d1 = new ColorDrawable(Color.GREEN);
264         Drawable d2 = new BitmapDrawable();
265         layerDrawable.setDrawableByLayerId(10, d1);
266         layerDrawable.setDrawableByLayerId(20, d2);
267         assertEquals(d1, layerDrawable.getDrawable(0));
268         assertEquals(d2, layerDrawable.getDrawable(1));
269 
270         assertFalse(layerDrawable.setDrawableByLayerId(30, d1));
271 
272         try {
273             layerDrawable.getDrawable(layerDrawable.getNumberOfLayers());
274             fail("Should throw IndexOutOfBoundsException");
275         } catch (IndexOutOfBoundsException e) {
276         }
277 
278         try {
279             layerDrawable.getDrawable(-1);
280             fail("Should throw IndexOutOfBoundsException");
281         } catch (IndexOutOfBoundsException e) {
282         }
283     }
284 
285     @Test
testSetDrawableByLayerId()286     public void testSetDrawableByLayerId() {
287         Drawable layer1A  = new ColorDrawable(Color.RED);
288         Drawable layer2A  = new ColorDrawable(Color.BLUE);
289         LayerDrawable layerDrawable = new LayerDrawable(new Drawable[] { layer1A, layer2A });
290         layerDrawable.setId(0, 10);
291         layerDrawable.setId(1, 20);
292 
293         Drawable layer1B = new ColorDrawable(Color.GREEN);
294         layer1B.setLevel(10000);
295         Drawable layer2B = new ColorDrawable(Color.YELLOW);
296         layer2B.setLevel(5000);
297         layerDrawable.setDrawableByLayerId(10, layer1B);
298         layerDrawable.setDrawableByLayerId(20, layer2B);
299 
300         assertEquals("Level is unchanged after setDrawableByLayerId()",
301                 10000, layerDrawable.findDrawableByLayerId(10).getLevel());
302         assertEquals("Level is unchanged after setDrawableByLayerId()",
303                 5000, layerDrawable.findDrawableByLayerId(20).getLevel());
304     }
305 
306     @Test
testSetLayerInset()307     public void testSetLayerInset() {
308         Drawable firstLayer = spy(new ColorDrawable(Color.YELLOW));
309         doReturn(10).when(firstLayer).getIntrinsicWidth();
310         doReturn(10).when(firstLayer).getIntrinsicHeight();
311         Drawable secondLayer = spy(new ColorDrawable(Color.YELLOW));
312         doReturn(-1).when(secondLayer).getIntrinsicWidth();
313         doReturn(-1).when(secondLayer).getIntrinsicHeight();
314 
315         Drawable[] array = new Drawable[] { firstLayer, secondLayer };
316         LayerDrawable layerDrawable = new LayerDrawable(array);
317 
318         // set inset for layer 0
319         int left = 10;
320         int top = 20;
321         int right = 30;
322         int bottom = 40;
323         layerDrawable.setLayerInset(0, left, top, right, bottom);
324         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
325                 layerDrawable.getIntrinsicWidth());
326         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
327                 layerDrawable.getIntrinsicHeight());
328 
329         // The drawable at index 0 has no intrinsic width or height, so it
330         // won't be counted for the overall intrinsic width or height.
331         layerDrawable.setLayerInset(1, 10, 10, 10, 10);
332         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
333                 layerDrawable.getIntrinsicWidth());
334         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
335                 layerDrawable.getIntrinsicHeight());
336 
337         try {
338             layerDrawable.setLayerInset(-1, left, top, right, bottom);
339             fail("Should throw IndexOutOfBoundsException");
340         } catch (IndexOutOfBoundsException e) {
341         }
342     }
343 
344     @Test
testInvalidateDrawable()345     public void testInvalidateDrawable() {
346         Drawable[] array = new Drawable[0];
347         LayerDrawable layerDrawable = new LayerDrawable(array);
348 
349         Drawable.Callback cb = mock(Drawable.Callback.class);
350         layerDrawable.setCallback(cb);
351         layerDrawable.invalidateDrawable(null);
352         verify(cb, times(1)).invalidateDrawable(any());
353 
354         reset(cb);
355         layerDrawable.invalidateDrawable(new BitmapDrawable());
356         verify(cb, times(1)).invalidateDrawable(any());
357 
358         reset(cb);
359         layerDrawable.setCallback(null);
360         layerDrawable.invalidateDrawable(null);
361         verify(cb, never()).invalidateDrawable(any());
362     }
363 
364     @Test
testScheduleDrawable()365     public void testScheduleDrawable() {
366         Drawable[] array = new Drawable[0];
367         LayerDrawable layerDrawable = new LayerDrawable(array);
368 
369         Drawable.Callback cb = mock(Drawable.Callback.class);
370         layerDrawable.setCallback(cb);
371         layerDrawable.scheduleDrawable(null, null, 0);
372         verify(cb, times(1)).scheduleDrawable(any(), any(), anyLong());
373 
374         reset(cb);
375         layerDrawable.scheduleDrawable(mBitmapDrawable, () -> {}, 1000L);
376         verify(cb, times(1)).scheduleDrawable(any(), any(), anyLong());
377 
378         reset(cb);
379         layerDrawable.setCallback(null);
380         layerDrawable.scheduleDrawable(null, null, 0);
381         verify(cb, never()).scheduleDrawable(any(), any(), anyLong());
382     }
383 
384     @Test
testUnscheduleDrawable()385     public void testUnscheduleDrawable() {
386         Drawable[] array = new Drawable[0];
387         LayerDrawable layerDrawable = new LayerDrawable(array);
388 
389         Drawable.Callback cb = mock(Drawable.Callback.class);
390         layerDrawable.setCallback(cb);
391         layerDrawable.unscheduleDrawable(null, null);
392         verify(cb, times(1)).unscheduleDrawable(any(), any());
393 
394         reset(cb);
395         layerDrawable.unscheduleDrawable(mBitmapDrawable, () -> {});
396         verify(cb, times(1)).unscheduleDrawable(any(), any());
397 
398         reset(cb);
399         layerDrawable.setCallback(null);
400         layerDrawable.unscheduleDrawable(null, null);
401         verify(cb, never()).unscheduleDrawable(any(), any());
402     }
403 
404     @Test
testDraw()405     public void testDraw() {
406         Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
407         Drawable mockDrawable2 = spy(new ColorDrawable(Color.RED));
408         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
409         LayerDrawable layerDrawable = new LayerDrawable(array);
410 
411         // this method will call each child's draw().
412         layerDrawable.draw(new Canvas());
413         verify(mockDrawable1, times(1)).draw(any());
414         verify(mockDrawable2, times(1)).draw(any());
415 
416         reset(mockDrawable1);
417         reset(mockDrawable2);
418         doNothing().when(mockDrawable1).draw(any());
419         doNothing().when(mockDrawable2).draw(any());
420         layerDrawable.draw(null);
421         verify(mockDrawable1, times(1)).draw(any());
422         verify(mockDrawable2, times(1)).draw(any());
423     }
424 
425     @Test
testGetChangingConfigurations()426     public void testGetChangingConfigurations() {
427         final int superConfig = 1;
428         final int gradientDrawableConfig = 2;
429         final int colorDrawableConfig = 4;
430         final int childConfig = gradientDrawableConfig | colorDrawableConfig;
431 
432         mBitmapDrawable.setChangingConfigurations(gradientDrawableConfig);
433         mColorDrawable.setChangingConfigurations(colorDrawableConfig);
434         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
435         LayerDrawable layerDrawable = new LayerDrawable(array);
436 
437         assertEquals(childConfig, layerDrawable.getChangingConfigurations());
438 
439         layerDrawable.setChangingConfigurations(superConfig);
440         assertEquals(superConfig | childConfig, layerDrawable.getChangingConfigurations());
441     }
442 
443     @Test
testAccessPadding()444     public void testAccessPadding() {
445         Drawable[] array = new Drawable[] { new ShapeDrawable(), new ShapeDrawable() };
446         LayerDrawable layerDrawable = new LayerDrawable(array);
447 
448         Rect rc = new Rect();
449         layerDrawable.getPadding(rc);
450         assertEquals(0, rc.left);
451         assertEquals(0, rc.top);
452         assertEquals(0, rc.right);
453         assertEquals(0, rc.bottom);
454 
455         Rect padding0 = new Rect(10, 20, 30, 40);
456         ((ShapeDrawable) layerDrawable.getDrawable(0)).setPadding(padding0);
457         layerDrawable.getPadding(rc);
458         assertEquals(padding0.left, rc.left);
459         assertEquals(padding0.top, rc.top);
460         assertEquals(padding0.right, rc.right);
461         assertEquals(padding0.bottom, rc.bottom);
462 
463         Rect padding1 = new Rect(20, 30, 40, 50);
464         ((ShapeDrawable) layerDrawable.getDrawable(1)).setPadding(padding1);
465         layerDrawable.getPadding(rc);
466         assertEquals(padding0.left + padding1.left, rc.left);
467         assertEquals(padding0.top + padding1.top, rc.top);
468         assertEquals(padding0.right + padding1.right, rc.right);
469         assertEquals(padding0.bottom + padding1.bottom, rc.bottom);
470     }
471 
472     @Test
testAccessPaddingMode()473     public void testAccessPaddingMode() {
474         Rect padding = new Rect();
475         Drawable dr0 = new IntrinsicSizeDrawable(20, 30, new Rect(1, 2, 3, 4));
476         Drawable dr1 = new IntrinsicSizeDrawable(30, 40, new Rect(9, 8, 7, 6));
477         LayerDrawable layerDrawable = new LayerDrawable(new Drawable[] { dr0, dr1 });
478 
479         assertEquals("Default padding mode is NEST",
480                 LayerDrawable.PADDING_MODE_NEST, layerDrawable.getPaddingMode());
481         assertEquals(34, layerDrawable.getIntrinsicWidth());
482         assertEquals(46, layerDrawable.getIntrinsicHeight());
483         assertTrue(layerDrawable.getPadding(padding));
484         assertEquals(new Rect(10, 10, 10, 10), padding);
485 
486         layerDrawable.setPaddingMode(LayerDrawable.PADDING_MODE_STACK);
487         assertEquals(LayerDrawable.PADDING_MODE_STACK, layerDrawable.getPaddingMode());
488         assertEquals(30, layerDrawable.getIntrinsicWidth());
489         assertEquals(40, layerDrawable.getIntrinsicHeight());
490         assertTrue(layerDrawable.getPadding(padding));
491         assertEquals(new Rect(9, 8, 7, 6), padding);
492     }
493 
494     @Test
testSetVisible()495     public void testSetVisible() {
496         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
497         LayerDrawable layerDrawable = new LayerDrawable(array);
498 
499         assertTrue(layerDrawable.setVisible(false, true));
500         assertFalse(layerDrawable.isVisible());
501         assertFalse(layerDrawable.getDrawable(0).isVisible());
502         assertFalse(layerDrawable.getDrawable(1).isVisible());
503 
504         assertFalse(layerDrawable.setVisible(false, false));
505 
506         assertTrue(layerDrawable.setVisible(true, false));
507         assertTrue(layerDrawable.isVisible());
508         assertTrue(layerDrawable.getDrawable(0).isVisible());
509         assertTrue(layerDrawable.getDrawable(1).isVisible());
510     }
511 
512     @Test
testSetDither()513     public void testSetDither() {
514         Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
515         Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLACK));
516         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
517         LayerDrawable layerDrawable = new LayerDrawable(array);
518 
519         layerDrawable.setDither(true);
520         verify(mockDrawable1, times(1)).setDither(anyBoolean());
521         verify(mockDrawable2, times(1)).setDither(anyBoolean());
522 
523         reset(mockDrawable1);
524         reset(mockDrawable2);
525         layerDrawable.setDither(false);
526         verify(mockDrawable1, times(1)).setDither(anyBoolean());
527         verify(mockDrawable2, times(1)).setDither(anyBoolean());
528     }
529 
530     @Test
testSetHotspotBounds()531     public void testSetHotspotBounds() {
532         Rect bounds = new Rect(10, 15, 100, 150);
533         Drawable mockDrawable1 = new ColorDrawable(Color.BLUE);
534         Drawable mockDrawable2 = new ColorDrawable(Color.GREEN);
535         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
536         LayerDrawable layerDrawable = new LayerDrawable(array);
537 
538         layerDrawable.setHotspotBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
539         Rect outRect = new Rect();
540         layerDrawable.getHotspotBounds(outRect);
541         assertTrue(bounds.equals(outRect));
542     }
543 
544     @Test
testGetHotspotBounds()545     public void testGetHotspotBounds() {
546         Rect bounds = new Rect(10, 15, 100, 150);
547         Drawable mockDrawable1 = new ColorDrawable(Color.BLUE);
548         Drawable mockDrawable2 = new ColorDrawable(Color.GREEN);
549         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
550         LayerDrawable layerDrawable = new LayerDrawable(array);
551 
552         layerDrawable.setHotspotBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
553         Rect outRect = new Rect();
554         layerDrawable.getHotspotBounds(outRect);
555         assertTrue(bounds.equals(outRect));
556     }
557 
558     @Test
testSetAlpha()559     public void testSetAlpha() {
560         Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
561         Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLACK));
562         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
563         LayerDrawable layerDrawable = new LayerDrawable(array);
564 
565         layerDrawable.setAlpha(0);
566         verify(mockDrawable1, times(1)).setAlpha(anyInt());
567         verify(mockDrawable2, times(1)).setAlpha(anyInt());
568 
569         reset(mockDrawable1);
570         reset(mockDrawable2);
571         layerDrawable.setAlpha(Integer.MAX_VALUE);
572         verify(mockDrawable1, times(1)).setAlpha(anyInt());
573         verify(mockDrawable2, times(1)).setAlpha(anyInt());
574     }
575 
576     @Test
testSetColorFilter()577     public void testSetColorFilter() {
578         Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
579         Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLACK));
580         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
581         LayerDrawable layerDrawable = new LayerDrawable(array);
582 
583         layerDrawable.setColorFilter(new ColorFilter());
584         verify(mockDrawable1, times(1)).setColorFilter(any());
585         verify(mockDrawable2, times(1)).setColorFilter(any());
586 
587         reset(mockDrawable1);
588         reset(mockDrawable2);
589         layerDrawable.setColorFilter(null);
590         verify(mockDrawable1, times(1)).setColorFilter(any());
591         verify(mockDrawable2, times(1)).setColorFilter(any());
592     }
593 
594     @Test
testAccessOpacity()595     public void testAccessOpacity() {
596         Drawable[] array = new Drawable[0];
597         LayerDrawable layerDrawable = new LayerDrawable(array);
598         assertEquals(PixelFormat.TRANSPARENT, layerDrawable.getOpacity());
599 
600         Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
601         Drawable mockDrawable2 = spy(new ColorDrawable(Color.GREEN));
602         array = new Drawable[] { mockDrawable1, mockDrawable2 };
603         layerDrawable = new LayerDrawable(array);
604         assertEquals(PixelFormat.OPAQUE, layerDrawable.getOpacity());
605 
606         layerDrawable = new LayerDrawable(array);
607         doReturn(PixelFormat.OPAQUE).when(mockDrawable1).getOpacity();
608         doReturn(PixelFormat.TRANSPARENT).when(mockDrawable2).getOpacity();
609         assertEquals(PixelFormat.TRANSPARENT, layerDrawable.getOpacity());
610 
611         layerDrawable = new LayerDrawable(array);
612         doReturn(PixelFormat.TRANSLUCENT).when(mockDrawable1).getOpacity();
613         doReturn(PixelFormat.TRANSPARENT).when(mockDrawable2).getOpacity();
614         assertEquals(PixelFormat.TRANSLUCENT, layerDrawable.getOpacity());
615 
616         layerDrawable = new LayerDrawable(array);
617         doReturn(PixelFormat.TRANSLUCENT).when(mockDrawable1).getOpacity();
618         doReturn(PixelFormat.UNKNOWN).when(mockDrawable2).getOpacity();
619         assertEquals(PixelFormat.UNKNOWN, layerDrawable.getOpacity());
620 
621         layerDrawable = new LayerDrawable(array);
622         layerDrawable.setOpacity(PixelFormat.OPAQUE);
623         doReturn(PixelFormat.TRANSLUCENT).when(mockDrawable1).getOpacity();
624         doReturn(PixelFormat.UNKNOWN).when(mockDrawable2).getOpacity();
625         assertEquals(PixelFormat.OPAQUE, layerDrawable.getOpacity());
626 
627     }
628 
629     @Test
testIsStateful()630     public void testIsStateful() {
631         Drawable[] array = new Drawable[0];
632         LayerDrawable layerDrawable = new LayerDrawable(array);
633         assertFalse(layerDrawable.isStateful());
634 
635         array = new Drawable[] { new GradientDrawable(), new MockDrawable(false) };
636         layerDrawable = new LayerDrawable(array);
637         assertFalse(layerDrawable.isStateful());
638 
639         array = new Drawable[] { new GradientDrawable(), new StateListDrawable() };
640         layerDrawable = new LayerDrawable(array);
641         assertTrue(layerDrawable.isStateful());
642     }
643 
644     @Test
testSetState()645     public void testSetState() {
646         MockDrawable mockDrawable1 = new MockDrawable(true);
647         MockDrawable mockDrawable2 = new MockDrawable(true);
648         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
649         LayerDrawable layerDrawable = new LayerDrawable(array);
650 
651         // Call onStateChange() without actually changing the state.
652         assertFalse(layerDrawable.setState(StateSet.WILD_CARD));
653         assertFalse(mockDrawable1.hasCalledSetState());
654         assertFalse(mockDrawable2.hasCalledSetState());
655         assertFalse(mockDrawable1.hasCalledOnBoundsChange());
656         assertFalse(mockDrawable2.hasCalledOnBoundsChange());
657 
658         // Call onStateChange() to change the state from WILD_CARD to null.
659         // This alters the padding of both layers, which forces a bounds change
660         // for the second layer due to the default "nest" padding mode.
661         mockDrawable1.reset();
662         mockDrawable2.reset();
663         assertTrue(layerDrawable.setState(null));
664         assertTrue(mockDrawable1.hasCalledSetState());
665         assertTrue(mockDrawable2.hasCalledSetState());
666         assertFalse(mockDrawable1.hasCalledOnBoundsChange());
667         assertTrue(mockDrawable2.hasCalledOnBoundsChange());
668 
669         // Call onStateChange() to change the state from null to valid state
670         // set. This alters the padding of both layers, which forces a bounds
671         // change for the second layer due to the default "nest" padding mode.
672         mockDrawable1.reset();
673         mockDrawable2.reset();
674         assertTrue(layerDrawable.setState(new int[]{
675                 android.R.attr.state_checked, android.R.attr.state_empty}));
676         assertTrue(mockDrawable1.hasCalledSetState());
677         assertTrue(mockDrawable2.hasCalledSetState());
678         assertFalse(mockDrawable1.hasCalledOnBoundsChange());
679         assertTrue(mockDrawable2.hasCalledOnBoundsChange());
680     }
681 
682     @Test
testJumpToCurrentState()683     public void testJumpToCurrentState() {
684         Drawable mockDrawable1 = spy(new ColorDrawable(Color.BLUE));
685         Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLACK));
686         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
687         LayerDrawable layerDrawable = new LayerDrawable(array);
688 
689         verify(mockDrawable1, never()).jumpToCurrentState();
690         verify(mockDrawable2, never()).jumpToCurrentState();
691 
692         layerDrawable.jumpToCurrentState();
693 
694         verify(mockDrawable1, times(1)).jumpToCurrentState();
695         verify(mockDrawable2, times(1)).jumpToCurrentState();
696     }
697 
698     @Test
testSetLevel()699     public void testSetLevel() {
700         MockDrawable mockDrawable1 = new MockDrawable();
701         MockDrawable mockDrawable2 = new MockDrawable();
702         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
703         LayerDrawable layerDrawable = new LayerDrawable(array);
704 
705         // Call onLevelChange() without actually changing the level.
706         assertFalse(layerDrawable.setLevel(0));
707         assertFalse(mockDrawable1.hasCalledOnLevelChange());
708         assertFalse(mockDrawable2.hasCalledOnLevelChange());
709         assertFalse(mockDrawable1.hasCalledOnBoundsChange());
710         assertFalse(mockDrawable2.hasCalledOnBoundsChange());
711 
712         // Call onLevelChange() to change the level from 0 to MAX_VALUE. This
713         // alters the padding of both layers, which forces a bounds change for
714         // the second layer due to the default "nest" padding mode.
715         mockDrawable1.reset();
716         mockDrawable2.reset();
717         assertTrue(layerDrawable.setLevel(Integer.MAX_VALUE));
718         assertTrue(mockDrawable1.hasCalledOnLevelChange());
719         assertTrue(mockDrawable2.hasCalledOnLevelChange());
720         assertFalse(mockDrawable1.hasCalledOnBoundsChange());
721         assertTrue(mockDrawable2.hasCalledOnBoundsChange());
722 
723         // Call onLevelChange() to change the level from MAX_VALUE to
724         // MIN_VALUE. This alters the padding of both layers, which forces a
725         // bounds change for the second layer due to the default "nest" padding
726         // mode.
727         mockDrawable1.reset();
728         mockDrawable2.reset();
729         assertTrue(layerDrawable.setLevel(Integer.MIN_VALUE));
730         assertTrue(mockDrawable1.hasCalledOnLevelChange());
731         assertTrue(mockDrawable2.hasCalledOnLevelChange());
732         assertFalse(mockDrawable1.hasCalledOnBoundsChange());
733         assertTrue(mockDrawable2.hasCalledOnBoundsChange());
734     }
735 
736     @Test
testSetBounds()737     public void testSetBounds() {
738         Drawable mockDrawable1 = spy(new ColorDrawable(Color.GREEN));
739         Drawable mockDrawable2 = spy(new ColorDrawable(Color.BLUE));
740         Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
741         LayerDrawable layerDrawable = new LayerDrawable(array);
742 
743         Rect inset1 = new Rect(1, 2, 3, 4);
744         Rect inset2 = new Rect(2, 4, 6, 7);
745         Rect padding1 = new Rect(11, 22, 33, 44);
746         Rect padding2 = new Rect(21, 32, 43, 54);
747         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
748         layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
749         doAnswer(invocation -> {
750             Rect target = (Rect) invocation.getArguments() [0];
751             target.set(padding1);
752             return true;
753         }).when(mockDrawable1).getPadding(any());
754         doAnswer(invocation -> {
755             Rect target = (Rect) invocation.getArguments() [0];
756             target.set(padding2);
757             return true;
758         }).when(mockDrawable2).getPadding(any());
759         layerDrawable.getPadding(new Rect());
760 
761         // the children's bounds before call onBoundsChange
762         assertEquals(0, mockDrawable1.getBounds().left);
763         assertEquals(0, mockDrawable1.getBounds().top);
764         assertEquals(0, mockDrawable1.getBounds().right);
765         assertEquals(0, mockDrawable1.getBounds().bottom);
766         assertEquals(0, mockDrawable2.getBounds().left);
767         assertEquals(0, mockDrawable2.getBounds().top);
768         assertEquals(0, mockDrawable2.getBounds().right);
769         assertEquals(0, mockDrawable2.getBounds().bottom);
770 
771         Rect bounds = new Rect(10, 20, 30, 40);
772         layerDrawable.setBounds(bounds);
773 
774         // all children's bounds will be changed after call onBoundsChange
775         assertEquals(bounds.left + inset1.left, mockDrawable1.getBounds().left);
776         assertEquals(bounds.top + inset1.top, mockDrawable1.getBounds().top);
777         assertEquals(bounds.right - inset1.right, mockDrawable1.getBounds().right);
778         assertEquals(bounds.bottom - inset1.bottom, mockDrawable1.getBounds().bottom);
779         assertEquals(bounds.left + inset2.left + padding1.left, mockDrawable2.getBounds().left);
780         assertEquals(bounds.top + inset2.top + padding1.top, mockDrawable2.getBounds().top);
781         assertEquals(bounds.right - inset2.right - padding1.right,
782                 mockDrawable2.getBounds().right);
783         assertEquals(bounds.bottom - inset2.bottom - padding1.bottom,
784                 mockDrawable2.getBounds().bottom);
785     }
786 
787     @Test
testGetIntrinsicWidth()788     public void testGetIntrinsicWidth() {
789         Drawable largeMockDrawable = spy(new ColorDrawable(Color.YELLOW));
790         doReturn(10).when(largeMockDrawable).getIntrinsicWidth();
791         doReturn(10).when(largeMockDrawable).getIntrinsicHeight();
792         Drawable smallMockDrawable = spy(new ColorDrawable(Color.MAGENTA));
793         doReturn(1).when(smallMockDrawable).getIntrinsicWidth();
794         doReturn(1).when(smallMockDrawable).getIntrinsicHeight();
795 
796         Drawable[] array = new Drawable[] { largeMockDrawable, smallMockDrawable };
797         LayerDrawable layerDrawable = new LayerDrawable(array);
798         assertEquals(largeMockDrawable.getIntrinsicWidth(), layerDrawable.getIntrinsicWidth());
799 
800         Rect inset1 = new Rect(1, 2, 3, 4);
801         Rect inset2 = new Rect(2, 4, 6, 7);
802         final Rect padding1 = new Rect(11, 22, 33, 44);
803         final Rect padding2 = new Rect(21, 32, 43, 54);
804         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
805         layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
806 
807         doAnswer(invocation -> {
808             Rect target = (Rect) invocation.getArguments() [0];
809             target.set(padding1);
810             return true;
811         }).when(largeMockDrawable).getPadding(any());
812         doAnswer(invocation -> {
813             Rect target = (Rect) invocation.getArguments() [0];
814             target.set(padding2);
815             return true;
816         }).when(smallMockDrawable).getPadding(any());
817 
818         layerDrawable.getPadding(new Rect());
819         assertEquals(smallMockDrawable.getIntrinsicWidth() + inset2.left
820                 + inset2.right + padding1.left + padding1.right,
821                 layerDrawable.getIntrinsicWidth());
822 
823         inset1 = new Rect(inset2.left + padding1.left + 1, inset2.top + padding1.top + 1,
824                 inset2.right + padding1.right + 1, inset2.bottom + padding1.bottom + 1);
825         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
826         assertEquals(largeMockDrawable.getIntrinsicWidth() + inset1.left + inset1.right,
827                 layerDrawable.getIntrinsicWidth());
828     }
829 
830     @Test
testGetIntrinsicHeight()831     public void testGetIntrinsicHeight() {
832         Drawable largeMockDrawable = spy(new ColorDrawable(Color.CYAN));
833         doReturn(10).when(largeMockDrawable).getIntrinsicWidth();
834         doReturn(10).when(largeMockDrawable).getIntrinsicHeight();
835         Drawable smallMockDrawable = spy(new ColorDrawable(Color.DKGRAY));
836         doReturn(1).when(smallMockDrawable).getIntrinsicWidth();
837         doReturn(1).when(smallMockDrawable).getIntrinsicHeight();
838 
839         Drawable[] array = new Drawable[] { largeMockDrawable, smallMockDrawable };
840         LayerDrawable layerDrawable = new LayerDrawable(array);
841         assertEquals(largeMockDrawable.getIntrinsicHeight(), layerDrawable.getIntrinsicHeight());
842 
843         Rect inset1 = new Rect(1, 2, 3, 4);
844         Rect inset2 = new Rect(2, 4, 6, 7);
845         final Rect padding1 = new Rect(11, 22, 33, 44);
846         final Rect padding2 = new Rect(21, 32, 43, 54);
847         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
848         layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
849 
850         doAnswer(invocation -> {
851             Rect target = (Rect) invocation.getArguments() [0];
852             target.set(padding1);
853             return true;
854         }).when(largeMockDrawable).getPadding(any());
855         doAnswer(invocation -> {
856             Rect target = (Rect) invocation.getArguments() [0];
857             target.set(padding2);
858             return true;
859         }).when(smallMockDrawable).getPadding(any());
860 
861         layerDrawable.getPadding(new Rect());
862         assertEquals(smallMockDrawable.getIntrinsicHeight() + inset2.top
863                 + inset2.bottom + padding1.top + padding1.bottom,
864                 layerDrawable.getIntrinsicHeight());
865 
866         inset1 = new Rect(inset2.left + padding1.left + 1, inset2.top + padding1.top + 1,
867                 inset2.right + padding1.right + 1, inset2.bottom + padding1.bottom + 1);
868         layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
869         assertEquals(largeMockDrawable.getIntrinsicHeight() + inset1.top + inset1.bottom,
870                 layerDrawable.getIntrinsicHeight());
871     }
872 
873     @Test
testGetConstantState()874     public void testGetConstantState() {
875         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
876         LayerDrawable layerDrawable = new LayerDrawable(array);
877         ConstantState constantState = layerDrawable.getConstantState();
878         assertNotNull(constantState);
879         assertEquals(0, constantState.getChangingConfigurations());
880 
881         layerDrawable.setChangingConfigurations(1);
882         constantState = layerDrawable.getConstantState();
883         assertNotNull(constantState);
884         assertEquals(1, constantState.getChangingConfigurations());
885     }
886 
887     @Test
testAddLayer()888     public void testAddLayer() {
889         Drawable[] array = new Drawable[] { new GradientDrawable(), new ColorDrawable(Color.BLUE) };
890         LayerDrawable layerDrawable = new LayerDrawable(array);
891         GradientDrawable newDrawable = new GradientDrawable();
892         int index = layerDrawable.addLayer(newDrawable);
893 
894         final int numLayers = layerDrawable.getNumberOfLayers();
895         assertEquals(index, numLayers - 1);
896         assertEquals(newDrawable, layerDrawable.getDrawable(index));
897     }
898 
899     @Test
testGetDrawable()900     public void testGetDrawable() {
901         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
902         LayerDrawable layerDrawable = new LayerDrawable(array);
903 
904         assertEquals(array[0], layerDrawable.getDrawable(0));
905         assertEquals(array[1], layerDrawable.getDrawable(1));
906         try {
907             assertEquals(null, layerDrawable.getDrawable(2));
908             fail("Should throw IndexOutOfBoundsException");
909         } catch (IndexOutOfBoundsException e) {
910         }
911     }
912 
913     @Test
testFindIndexByLayerId()914     public void testFindIndexByLayerId() {
915         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
916         LayerDrawable layerDrawable = new LayerDrawable(array);
917 
918         layerDrawable.setId(0, 10);
919         layerDrawable.setId(1, 20);
920 
921         assertEquals(0, layerDrawable.findIndexByLayerId(10));
922         assertEquals(1, layerDrawable.findIndexByLayerId(20));
923         assertEquals(-1, layerDrawable.findIndexByLayerId(30));
924     }
925 
926     @Test
testSetDrawable()927     public void testSetDrawable() {
928         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
929         LayerDrawable layerDrawable = new LayerDrawable(array);
930         BitmapDrawable newBitmapDrawable = new BitmapDrawable();
931         ColorDrawable newColorDrawable = new ColorDrawable(Color.GREEN);
932         layerDrawable.setDrawable(0, newColorDrawable);
933         layerDrawable.setDrawable(1, newBitmapDrawable);
934 
935         final int numLayers = layerDrawable.getNumberOfLayers();
936         assertEquals(2, numLayers);
937         assertEquals(newColorDrawable, layerDrawable.getDrawable(0));
938         assertEquals(newBitmapDrawable, layerDrawable.getDrawable(1));
939         try {
940             assertEquals(null, layerDrawable.getDrawable(2));
941             fail("Should throw IndexOutOfBoundsException");
942         } catch (IndexOutOfBoundsException e) {
943         }
944     }
945 
946     @Test
testGetLeftPadding()947     public void testGetLeftPadding() {
948         Drawable[] array = new Drawable[] { mBitmapDrawable };
949         LayerDrawable layerDrawable = new LayerDrawable(array);
950         layerDrawable.setPadding(10, 11, 20, 21);
951 
952         assertEquals(10, layerDrawable.getLeftPadding());
953     }
954 
955     @Test
testGetTopPadding()956     public void testGetTopPadding() {
957         Drawable[] array = new Drawable[] { mBitmapDrawable };
958         LayerDrawable layerDrawable = new LayerDrawable(array);
959         layerDrawable.setPadding(10, 11, 20, 21);
960 
961         assertEquals(11, layerDrawable.getTopPadding());
962     }
963 
964     @Test
testGetRightPadding()965     public void testGetRightPadding() {
966         Drawable[] array = new Drawable[] { mBitmapDrawable };
967         LayerDrawable layerDrawable = new LayerDrawable(array);
968         layerDrawable.setPadding(10, 11, 20, 21);
969 
970         assertEquals(20, layerDrawable.getRightPadding());
971     }
972 
973     @Test
testGetBottomPadding()974     public void testGetBottomPadding() {
975         Drawable[] array = new Drawable[] { mBitmapDrawable };
976         LayerDrawable layerDrawable = new LayerDrawable(array);
977         layerDrawable.setPadding(10, 11, 20, 21);
978 
979         assertEquals(21, layerDrawable.getBottomPadding());
980     }
981 
982     @Test
testGetStartPadding()983     public void testGetStartPadding() {
984         Drawable[] array = new Drawable[] { mBitmapDrawable };
985         LayerDrawable layerDrawable = new LayerDrawable(array);
986         layerDrawable.setPadding(10, 11, 20, 21);
987 
988         assertEquals(-1, layerDrawable.getStartPadding());
989         layerDrawable.setPaddingRelative(10, 11, 20, 21);
990         assertEquals(10, layerDrawable.getStartPadding());
991     }
992 
993     @Test
testGetEndPadding()994     public void testGetEndPadding() {
995         Drawable[] array = new Drawable[] { mBitmapDrawable };
996         LayerDrawable layerDrawable = new LayerDrawable(array);
997         layerDrawable.setPadding(10, 11, 20, 21);
998 
999         assertEquals(-1, layerDrawable.getEndPadding());
1000         layerDrawable.setPaddingRelative(10, 11, 20, 21);
1001         assertEquals(20, layerDrawable.getEndPadding());
1002     }
1003 
1004     @Test
testSetPadding()1005     public void testSetPadding() {
1006         Drawable[] array = new Drawable[] { mBitmapDrawable };
1007         LayerDrawable layerDrawable = new LayerDrawable(array);
1008         layerDrawable.setPadding(10, 11, 20, 21);
1009 
1010         assertEquals(10, layerDrawable.getLeftPadding());
1011         assertEquals(11, layerDrawable.getTopPadding());
1012         assertEquals(20, layerDrawable.getRightPadding());
1013         assertEquals(21, layerDrawable.getBottomPadding());
1014         assertEquals(-1, layerDrawable.getStartPadding());
1015         assertEquals(-1, layerDrawable.getEndPadding());
1016     }
1017 
1018     @Test
testSetPaddingRelative()1019     public void testSetPaddingRelative() {
1020         Drawable[] array = new Drawable[] { mBitmapDrawable };
1021         LayerDrawable layerDrawable = new LayerDrawable(array);
1022         layerDrawable.setPaddingRelative(10, 11, 20, 21);
1023 
1024         assertEquals(10, layerDrawable.getStartPadding());
1025         assertEquals(11, layerDrawable.getTopPadding());
1026         assertEquals(20, layerDrawable.getEndPadding());
1027         assertEquals(21, layerDrawable.getBottomPadding());
1028         assertEquals(-1, layerDrawable.getLeftPadding());
1029         assertEquals(-1, layerDrawable.getRightPadding());
1030     }
1031 
1032     @Test
testSetLayerGravity()1033     public void testSetLayerGravity() {
1034         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
1035         LayerDrawable layerDrawable = new LayerDrawable(array);
1036 
1037         layerDrawable.setLayerGravity(0, Gravity.CENTER);
1038         layerDrawable.setLayerGravity(1, Gravity.NO_GRAVITY);
1039 
1040         try {
1041             layerDrawable.setLayerGravity(2, Gravity.TOP);
1042             fail("Should throw ArrayIndexOutOfBoundsException");
1043         } catch (ArrayIndexOutOfBoundsException e) {
1044         }
1045         assertEquals(Gravity.CENTER, layerDrawable.getLayerGravity(0));
1046         assertEquals(Gravity.NO_GRAVITY, layerDrawable.getLayerGravity(1));
1047     }
1048 
1049     @Test
testGetLayerGravity()1050     public void testGetLayerGravity() {
1051         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
1052         LayerDrawable layerDrawable = new LayerDrawable(array);
1053 
1054         layerDrawable.setLayerGravity(0, Gravity.CENTER);
1055         layerDrawable.setLayerGravity(1, Gravity.NO_GRAVITY);
1056 
1057         assertEquals(Gravity.CENTER, layerDrawable.getLayerGravity(0));
1058         assertEquals(Gravity.NO_GRAVITY, layerDrawable.getLayerGravity(1));
1059         try {
1060             layerDrawable.getLayerGravity(2);
1061             fail("Should throw ArrayIndexOutOfBoundsException");
1062         } catch (ArrayIndexOutOfBoundsException e) {
1063         }
1064     }
1065 
1066     @Test
testSetLayerWidth()1067     public void testSetLayerWidth() {
1068         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
1069         LayerDrawable layerDrawable = new LayerDrawable(array);
1070 
1071         layerDrawable.setLayerWidth(0, 100);
1072         layerDrawable.setLayerWidth(1, 200);
1073 
1074         try {
1075             layerDrawable.setLayerWidth(2, 300);
1076             fail("Should throw ArrayIndexOutOfBoundsException");
1077         } catch (ArrayIndexOutOfBoundsException e) {
1078         }
1079         assertEquals(100, layerDrawable.getLayerWidth(0));
1080         assertEquals(200, layerDrawable.getLayerWidth(1));
1081     }
1082 
1083     @Test
testGetLayerWidth()1084     public void testGetLayerWidth() {
1085         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
1086         LayerDrawable layerDrawable = new LayerDrawable(array);
1087 
1088         layerDrawable.setLayerWidth(0, 100);
1089         layerDrawable.setLayerWidth(1, 200);
1090 
1091         assertEquals(100, layerDrawable.getLayerWidth(0));
1092         assertEquals(200, layerDrawable.getLayerWidth(1));
1093         try {
1094             layerDrawable.getLayerWidth(2);
1095             fail("Should throw ArrayIndexOutOfBoundsException");
1096         } catch (ArrayIndexOutOfBoundsException e) {
1097         }
1098     }
1099 
1100     @Test
testSetLayerHeight()1101     public void testSetLayerHeight() {
1102         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
1103         LayerDrawable layerDrawable = new LayerDrawable(array);
1104 
1105         layerDrawable.setLayerHeight(0, 100);
1106         layerDrawable.setLayerHeight(1, 200);
1107 
1108         try {
1109             layerDrawable.setLayerHeight(2, 300);
1110             fail("Should throw ArrayIndexOutOfBoundsException");
1111         } catch (ArrayIndexOutOfBoundsException e) {
1112         }
1113         assertEquals(100, layerDrawable.getLayerHeight(0));
1114         assertEquals(200, layerDrawable.getLayerHeight(1));
1115     }
1116 
1117     @Test
testGetLayerHeight()1118     public void testGetLayerHeight() {
1119         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
1120         LayerDrawable layerDrawable = new LayerDrawable(array);
1121 
1122         layerDrawable.setLayerHeight(0, 100);
1123         layerDrawable.setLayerHeight(1, 200);
1124 
1125         assertEquals(100, layerDrawable.getLayerHeight(0));
1126         assertEquals(200, layerDrawable.getLayerHeight(1));
1127         try {
1128             layerDrawable.getLayerHeight(2);
1129             fail("Should throw ArrayIndexOutOfBoundsException");
1130         } catch (ArrayIndexOutOfBoundsException e) {
1131         }
1132     }
1133 
1134     @Test
testSetLayerSize()1135     public void testSetLayerSize() {
1136         Drawable[] array = new Drawable[] { mBitmapDrawable, mColorDrawable };
1137         LayerDrawable layerDrawable = new LayerDrawable(array);
1138 
1139         layerDrawable.setLayerSize(0, 100, 200);
1140         layerDrawable.setLayerSize(1, 300, 400);
1141 
1142         try {
1143             layerDrawable.setLayerSize(2, 500, 600);
1144             fail("Should throw ArrayIndexOutOfBoundsException");
1145         } catch (ArrayIndexOutOfBoundsException e) {
1146         }
1147         assertEquals(100, layerDrawable.getLayerWidth(0));
1148         assertEquals(200, layerDrawable.getLayerHeight(0));
1149         assertEquals(300, layerDrawable.getLayerWidth(1));
1150         assertEquals(400, layerDrawable.getLayerHeight(1));
1151     }
1152 
1153     @Test
testSetLayerInsetRelative()1154     public void testSetLayerInsetRelative() {
1155         Drawable firstLayer = spy(new ColorDrawable(Color.YELLOW));
1156         doReturn(10).when(firstLayer).getIntrinsicWidth();
1157         doReturn(10).when(firstLayer).getIntrinsicHeight();
1158         Drawable secondLayer = spy(new ColorDrawable(Color.YELLOW));
1159         doReturn(-1).when(secondLayer).getIntrinsicWidth();
1160         doReturn(-1).when(secondLayer).getIntrinsicHeight();
1161 
1162         Drawable[] array = new Drawable[] { firstLayer, secondLayer };
1163         LayerDrawable layerDrawable = new LayerDrawable(array);
1164 
1165         int start = 10;
1166         int top = 20;
1167         int end = 30;
1168         int bottom = 40;
1169         layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
1170         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
1171                 layerDrawable.getIntrinsicWidth());
1172         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
1173                 layerDrawable.getIntrinsicHeight());
1174         assertEquals(start, layerDrawable.getLayerInsetStart(0));
1175         assertEquals(top, layerDrawable.getLayerInsetTop(0));
1176         assertEquals(end, layerDrawable.getLayerInsetEnd(0));
1177         assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
1178         assertEquals(0, layerDrawable.getLayerInsetLeft(0));
1179         assertEquals(0, layerDrawable.getLayerInsetRight(0));
1180 
1181         // The drawable at index 1 has no intrinsic width or height, so it
1182         // won't be counted for the overall intrinsic width or height.
1183         layerDrawable.setLayerInsetRelative(1, 10, 10, 10, 10);
1184         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
1185                 layerDrawable.getIntrinsicWidth());
1186         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
1187                 layerDrawable.getIntrinsicHeight());
1188 
1189         try {
1190             layerDrawable.setLayerInsetRelative(-1, start, top, end, bottom);
1191             fail("Should throw IndexOutOfBoundsException");
1192         } catch (IndexOutOfBoundsException e) {
1193         }
1194     }
1195 
1196     @Test
testSetLayerInsetLeft()1197     public void testSetLayerInsetLeft() {
1198         Drawable[] array = new Drawable[] { mBitmapDrawable };
1199         LayerDrawable layerDrawable = new LayerDrawable(array);
1200 
1201         // set inset for layer 0
1202         int left = 10;
1203         int top = 20;
1204         int right = 30;
1205         int bottom = 40;
1206         layerDrawable.setLayerInset(0, left, top, right, bottom);
1207         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
1208                 layerDrawable.getIntrinsicWidth());
1209         left += 5;
1210         layerDrawable.setLayerInsetLeft(0, left);
1211         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
1212                 layerDrawable.getIntrinsicWidth());
1213         assertEquals(left, layerDrawable.getLayerInsetLeft(0));
1214 
1215         try {
1216             layerDrawable.setLayerInsetLeft(1, left);
1217             fail("Should throw IndexOutOfBoundsException");
1218         } catch (IndexOutOfBoundsException e) {
1219         }
1220     }
1221 
1222     @Test
testGetLayerInsetLeft()1223     public void testGetLayerInsetLeft() {
1224         Drawable[] array = new Drawable[] { mBitmapDrawable };
1225         LayerDrawable layerDrawable = new LayerDrawable(array);
1226 
1227         // set inset for layer 0
1228         int left = 10;
1229         int top = 20;
1230         int right = 30;
1231         int bottom = 40;
1232         layerDrawable.setLayerInset(0, left, top, right, bottom);
1233         assertEquals(left, layerDrawable.getLayerInsetLeft(0));
1234         left += 5;
1235         layerDrawable.setLayerInsetLeft(0, left);
1236         assertEquals(left, layerDrawable.getLayerInsetLeft(0));
1237 
1238         try {
1239             layerDrawable.getLayerInsetLeft(1);
1240             fail("Should throw IndexOutOfBoundsException");
1241         } catch (IndexOutOfBoundsException e) {
1242         }
1243     }
1244 
1245     @Test
testSetLayerInsetTop()1246     public void testSetLayerInsetTop() {
1247         Drawable[] array = new Drawable[] { mBitmapDrawable };
1248         LayerDrawable layerDrawable = new LayerDrawable(array);
1249 
1250         // set inset for layer 0
1251         int left = 10;
1252         int top = 20;
1253         int right = 30;
1254         int bottom = 40;
1255         layerDrawable.setLayerInset(0, left, top, right, bottom);
1256         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
1257                 layerDrawable.getIntrinsicHeight());
1258         top += 5;
1259         layerDrawable.setLayerInsetTop(0, top);
1260         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
1261                 layerDrawable.getIntrinsicHeight());
1262         assertEquals(top, layerDrawable.getLayerInsetTop(0));
1263 
1264         try {
1265             layerDrawable.setLayerInsetTop(1, top);
1266             fail("Should throw IndexOutOfBoundsException");
1267         } catch (IndexOutOfBoundsException e) {
1268         }
1269     }
1270 
1271     @Test
testGetLayerInsetTop()1272     public void testGetLayerInsetTop() {
1273         Drawable[] array = new Drawable[] { mBitmapDrawable };
1274         LayerDrawable layerDrawable = new LayerDrawable(array);
1275 
1276         // set inset for layer 0
1277         int left = 10;
1278         int top = 20;
1279         int right = 30;
1280         int bottom = 40;
1281         layerDrawable.setLayerInset(0, left, top, right, bottom);
1282         assertEquals(top, layerDrawable.getLayerInsetTop(0));
1283         top += 5;
1284         layerDrawable.setLayerInsetTop(0, top);
1285         assertEquals(top, layerDrawable.getLayerInsetTop(0));
1286 
1287         try {
1288             layerDrawable.getLayerInsetTop(1);
1289             fail("Should throw IndexOutOfBoundsException");
1290         } catch (IndexOutOfBoundsException e) {
1291         }
1292     }
1293 
1294     @Test
testSetLayerInsetRight()1295     public void testSetLayerInsetRight() {
1296         Drawable[] array = new Drawable[] { mBitmapDrawable };
1297         LayerDrawable layerDrawable = new LayerDrawable(array);
1298 
1299         // set inset for layer 0
1300         int left = 10;
1301         int top = 20;
1302         int right = 30;
1303         int bottom = 40;
1304         layerDrawable.setLayerInset(0, left, top, right, bottom);
1305         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
1306                 layerDrawable.getIntrinsicWidth());
1307         right += 5;
1308         layerDrawable.setLayerInsetRight(0, right);
1309         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
1310                 layerDrawable.getIntrinsicWidth());
1311         assertEquals(right, layerDrawable.getLayerInsetRight(0));
1312 
1313         try {
1314             layerDrawable.setLayerInsetRight(1, right);
1315             fail("Should throw IndexOutOfBoundsException");
1316         } catch (IndexOutOfBoundsException e) {
1317         }
1318     }
1319 
1320     @Test
testGetLayerInsetRight()1321     public void testGetLayerInsetRight() {
1322         Drawable[] array = new Drawable[] { mBitmapDrawable };
1323         LayerDrawable layerDrawable = new LayerDrawable(array);
1324 
1325         // set inset for layer 0
1326         int left = 10;
1327         int top = 20;
1328         int right = 30;
1329         int bottom = 40;
1330         layerDrawable.setLayerInset(0, left, top, right, bottom);
1331         assertEquals(right, layerDrawable.getLayerInsetRight(0));
1332         right += 5;
1333         layerDrawable.setLayerInsetRight(0, right);
1334         assertEquals(right, layerDrawable.getLayerInsetRight(0));
1335 
1336         try {
1337             layerDrawable.getLayerInsetRight(1);
1338             fail("Should throw IndexOutOfBoundsException");
1339         } catch (IndexOutOfBoundsException e) {
1340         }
1341     }
1342 
1343     @Test
testSetLayerInsetBottom()1344     public void testSetLayerInsetBottom() {
1345         Drawable[] array = new Drawable[] { mBitmapDrawable };
1346         LayerDrawable layerDrawable = new LayerDrawable(array);
1347 
1348         // set inset for layer 0
1349         int left = 10;
1350         int top = 20;
1351         int right = 30;
1352         int bottom = 40;
1353         layerDrawable.setLayerInset(0, left, top, right, bottom);
1354         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
1355                 layerDrawable.getIntrinsicHeight());
1356         bottom += 5;
1357         layerDrawable.setLayerInsetBottom(0, bottom);
1358         assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
1359                 layerDrawable.getIntrinsicHeight());
1360         assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
1361 
1362         try {
1363             layerDrawable.setLayerInsetBottom(1, bottom);
1364             fail("Should throw IndexOutOfBoundsException");
1365         } catch (IndexOutOfBoundsException e) {
1366         }
1367     }
1368 
1369     @Test
testGetLayerInsetBottom()1370     public void testGetLayerInsetBottom() {
1371         Drawable[] array = new Drawable[] { mBitmapDrawable };
1372         LayerDrawable layerDrawable = new LayerDrawable(array);
1373 
1374         // set inset for layer 0
1375         int left = 10;
1376         int top = 20;
1377         int right = 30;
1378         int bottom = 40;
1379         layerDrawable.setLayerInset(0, left, top, right, bottom);
1380         assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
1381         bottom += 5;
1382         layerDrawable.setLayerInsetBottom(0, bottom);
1383         assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
1384 
1385         try {
1386             layerDrawable.getLayerInsetBottom(1);
1387             fail("Should throw IndexOutOfBoundsException");
1388         } catch (IndexOutOfBoundsException e) {
1389         }
1390     }
1391 
1392     @Test
testSetLayerInsetStart()1393     public void testSetLayerInsetStart() {
1394         Drawable[] array = new Drawable[] { mBitmapDrawable };
1395         LayerDrawable layerDrawable = new LayerDrawable(array);
1396 
1397         // set inset for layer 0
1398         int start = 10;
1399         int top = 20;
1400         int end = 30;
1401         int bottom = 40;
1402         layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
1403         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
1404                 layerDrawable.getIntrinsicWidth());
1405         start += 5;
1406         layerDrawable.setLayerInsetStart(0, start);
1407         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
1408                 layerDrawable.getIntrinsicWidth());
1409         assertEquals(start, layerDrawable.getLayerInsetStart(0));
1410 
1411         try {
1412             layerDrawable.setLayerInset(1, start, top, end, bottom);
1413             fail("Should throw IndexOutOfBoundsException");
1414         } catch (IndexOutOfBoundsException e) {
1415         }
1416     }
1417 
1418     @Test
testGetLayerInsetStart()1419     public void testGetLayerInsetStart() {
1420         Drawable[] array = new Drawable[] { mBitmapDrawable };
1421         LayerDrawable layerDrawable = new LayerDrawable(array);
1422 
1423         // set inset for layer 0
1424         int start = 10;
1425         int top = 20;
1426         int end = 30;
1427         int bottom = 40;
1428         layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
1429         assertEquals(start, layerDrawable.getLayerInsetStart(0));
1430         start += 5;
1431         layerDrawable.setLayerInsetStart(0, start);
1432         assertEquals(start, layerDrawable.getLayerInsetStart(0));
1433 
1434         try {
1435             layerDrawable.getLayerInsetStart(1);
1436             fail("Should throw IndexOutOfBoundsException");
1437         } catch (IndexOutOfBoundsException e) {
1438         }
1439     }
1440 
1441     @Test
testSetLayerInsetEnd()1442     public void testSetLayerInsetEnd() {
1443         Drawable[] array = new Drawable[] { mBitmapDrawable };
1444         LayerDrawable layerDrawable = new LayerDrawable(array);
1445 
1446         // set inset for layer 0
1447         int start = 10;
1448         int top = 20;
1449         int end = 30;
1450         int bottom = 40;
1451         layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
1452         assertEquals(end, layerDrawable.getLayerInsetEnd(0));
1453         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
1454                 layerDrawable.getIntrinsicWidth());
1455         end += 5;
1456         layerDrawable.setLayerInsetEnd(0, end);
1457         assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
1458                 layerDrawable.getIntrinsicWidth());
1459         assertEquals(end, layerDrawable.getLayerInsetEnd(0));
1460 
1461         try {
1462             layerDrawable.setLayerInsetEnd(1, end);
1463             fail("Should throw IndexOutOfBoundsException");
1464         } catch (IndexOutOfBoundsException e) {
1465         }
1466     }
1467 
1468     @Test
testGetLayerInsetEnd()1469     public void testGetLayerInsetEnd() {
1470         Drawable[] array = new Drawable[] { mBitmapDrawable };
1471         LayerDrawable layerDrawable = new LayerDrawable(array);
1472 
1473         // set inset for layer 0
1474         int start = 10;
1475         int top = 20;
1476         int end = 30;
1477         int bottom = 40;
1478         layerDrawable.setLayerInsetRelative(0, start, top, end, bottom);
1479         assertEquals(end, layerDrawable.getLayerInsetEnd(0));
1480         end += 5;
1481         layerDrawable.setLayerInsetEnd(0, end);
1482         assertEquals(end, layerDrawable.getLayerInsetEnd(0));
1483 
1484         try {
1485             layerDrawable.getLayerInsetEnd(1);
1486             fail("Should throw IndexOutOfBoundsException");
1487         } catch (IndexOutOfBoundsException e) {
1488         }
1489     }
1490 
1491     @Test
testChildIntrinsicSize()1492     public void testChildIntrinsicSize() {
1493         LayerDrawable dr;
1494 
1495         // Ensure that a child with no intrinsic size correctly reports bounds.
1496         dr = (LayerDrawable) mContext.getDrawable(R.drawable.layer_drawable_intrinsic);
1497         assertEquals(-1, dr.getIntrinsicWidth());
1498         assertEquals(-1, dr.getIntrinsicHeight());
1499 
1500         // Check when creating the drawble from code.
1501         dr = new LayerDrawable(new Drawable[] { new ColorDrawable(Color.RED) });
1502         dr.setLayerInset(0, 10, 10, 10, 10);
1503         assertEquals(-1, dr.getIntrinsicWidth());
1504         assertEquals(-1, dr.getIntrinsicHeight());
1505 
1506         // Ensure mixed children report bounds correctly as well.
1507         dr = (LayerDrawable) mContext.getDrawable(R.drawable.layer_drawable_intrinsic_mixed);
1508         int width = dr.getLayerInsetLeft(0) + dr.getLayerInsetRight(0)
1509                 + dr.getDrawable(0).getIntrinsicWidth();
1510         int height = dr.getLayerInsetTop(0) + dr.getLayerInsetBottom(0)
1511                 + dr.getDrawable(0).getIntrinsicHeight();
1512         assertEquals(width, dr.getIntrinsicWidth());
1513         assertEquals(height, dr.getIntrinsicHeight());
1514     }
1515 
1516     @Test
testIsProjectedWithNullLayer()1517     public void testIsProjectedWithNullLayer() {
1518         try {
1519             LayerDrawable dr = new LayerDrawable(new Drawable[] {null});
1520             dr.isProjected();
1521         } catch (NullPointerException excep) {
1522             fail("isProjected should support null child layer drawables");
1523         }
1524     }
1525 
1526     // Since Mockito can't mock or spy on protected methods, we have a custom extension
1527     // of Drawable to track calls to protected methods. This class also has empty implementations
1528     // of the base abstract methods. In addition, this class also updates its padding on every
1529     // change in level or state.
1530     private static class MockDrawable extends Drawable {
1531         private boolean mCalledSetState = false;
1532         private boolean mCalledOnLevelChange = false;
1533         private boolean mCalledOnBoundsChange = false;
1534 
1535         private boolean mIsStateful = false;
1536 
1537         private Rect mPadding = null;
1538 
MockDrawable()1539         public MockDrawable() {
1540             this(false);
1541         }
1542 
MockDrawable(boolean isStateful)1543         public MockDrawable(boolean isStateful) {
1544             mIsStateful = isStateful;
1545         }
1546 
1547         @Override
draw(Canvas canvas)1548         public void draw(Canvas canvas) {
1549         }
1550 
1551         @Override
getOpacity()1552         public int getOpacity() {
1553             return PixelFormat.OPAQUE;
1554         }
1555 
1556         @Override
setAlpha(int alpha)1557         public void setAlpha(int alpha) {
1558         }
1559 
1560         @Override
setColorFilter(ColorFilter cf)1561         public void setColorFilter(ColorFilter cf) {
1562         }
1563 
reset()1564         public void reset() {
1565             mCalledSetState = false;
1566             mCalledOnLevelChange = false;
1567             mCalledOnBoundsChange = false;
1568         }
1569 
1570         @Override
onStateChange(int[] state)1571         protected boolean onStateChange(int[] state) {
1572             increasePadding();
1573             return mIsStateful;
1574         }
1575 
increasePadding()1576         private void increasePadding() {
1577             Rect padding = new Rect();
1578             getPadding(padding);
1579             padding.left++;
1580             padding.top++;
1581             padding.right++;
1582             padding.bottom++;
1583 
1584             setPadding(padding);
1585         }
1586 
1587         @Override
onLevelChange(int level)1588         protected boolean onLevelChange(int level) {
1589             increasePadding();
1590             mCalledOnLevelChange = true;
1591             return true;
1592         }
1593 
1594         @Override
onBoundsChange(Rect bounds)1595         protected void onBoundsChange(Rect bounds) {
1596             mCalledOnBoundsChange = true;
1597             super.onBoundsChange(bounds);
1598         }
1599 
hasCalledOnBoundsChange()1600         public boolean hasCalledOnBoundsChange() {
1601             return mCalledOnBoundsChange;
1602         }
1603 
1604         @Override
isStateful()1605         public boolean isStateful() {
1606             return mIsStateful;
1607         }
1608 
hasCalledSetState()1609         public boolean hasCalledSetState() {
1610             return mCalledSetState;
1611         }
1612 
1613         @Override
setState(final int[] stateSet)1614         public boolean setState(final int[] stateSet) {
1615             mCalledSetState = true;
1616             return super.setState(stateSet);
1617         }
1618 
hasCalledOnLevelChange()1619         public boolean hasCalledOnLevelChange() {
1620             return mCalledOnLevelChange;
1621         }
1622 
setPadding(Rect padding)1623         private void setPadding(Rect padding) {
1624             if (padding == null) {
1625                 mPadding = null;
1626             } else {
1627                 if (mPadding == null) {
1628                     mPadding = new Rect();
1629                 }
1630                 mPadding.set(padding);
1631             }
1632         }
1633 
1634         @Override
getPadding(Rect padding)1635         public boolean getPadding(Rect padding) {
1636             if (mPadding != null) {
1637                 padding.set(mPadding);
1638                 return true;
1639             } else {
1640                 return super.getPadding(padding);
1641             }
1642         }
1643     }
1644 
1645     @Test
testMutate()1646     public void testMutate() {
1647         LayerDrawable d1 = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable);
1648         LayerDrawable d2 = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable);
1649         LayerDrawable d3 = (LayerDrawable) mContext.getDrawable(R.drawable.layerdrawable);
1650         int restoreAlpha = d1.getAlpha();
1651 
1652         try {
1653             // verify bad behavior - modify before mutate pollutes other drawables
1654             d1.setAlpha(100);
1655             assertEquals(100, ((BitmapDrawable) d1.getDrawable(0)).getPaint().getAlpha());
1656             assertEquals(100, ((BitmapDrawable) d1.getDrawable(0)).getPaint().getAlpha());
1657             assertEquals(100, ((BitmapDrawable) d2.getDrawable(0)).getPaint().getAlpha());
1658             assertEquals(100, ((BitmapDrawable) d2.getDrawable(0)).getPaint().getAlpha());
1659             assertEquals(100, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
1660             assertEquals(100, ((BitmapDrawable) d2.getDrawable(0)).getPaint().getAlpha());
1661 
1662             d1.mutate();
1663             d1.setAlpha(200);
1664             assertEquals(200, ((BitmapDrawable) d1.getDrawable(0)).getPaint().getAlpha());
1665             assertEquals(200, ((BitmapDrawable) d1.getDrawable(0)).getPaint().getAlpha());
1666             assertEquals(100, ((BitmapDrawable) d2.getDrawable(0)).getPaint().getAlpha());
1667             assertEquals(100, ((BitmapDrawable) d2.getDrawable(0)).getPaint().getAlpha());
1668             assertEquals(100, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
1669             assertEquals(100, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
1670 
1671             d2.setAlpha(50);
1672             assertEquals(200, ((BitmapDrawable) d1.getDrawable(0)).getPaint().getAlpha());
1673             assertEquals(200, ((BitmapDrawable) d1.getDrawable(0)).getPaint().getAlpha());
1674             assertEquals(50, ((BitmapDrawable) d2.getDrawable(0)).getPaint().getAlpha());
1675             assertEquals(50, ((BitmapDrawable) d2.getDrawable(0)).getPaint().getAlpha());
1676             assertEquals(50, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
1677             assertEquals(50, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
1678         } finally {
1679             // restore externally visible state, since other tests may use the drawable
1680             mContext.getDrawable(R.drawable.layerdrawable).setAlpha(restoreAlpha);
1681         }
1682     }
1683 
1684     @Test
testPreloadDensity()1685     public void testPreloadDensity() throws XmlPullParserException, IOException {
1686         final Resources res = mContext.getResources();
1687         final int densityDpi = res.getConfiguration().densityDpi;
1688         try {
1689             DrawableTestUtils.setResourcesDensity(res, densityDpi);
1690             verifyPreloadDensityInner(res, densityDpi);
1691         } finally {
1692             DrawableTestUtils.setResourcesDensity(res, densityDpi);
1693         }
1694     }
1695 
1696     @Test
testPreloadDensity_tvdpi()1697     public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
1698         final Resources res = mContext.getResources();
1699         final int densityDpi = res.getConfiguration().densityDpi;
1700         try {
1701             DrawableTestUtils.setResourcesDensity(res, 213);
1702             verifyPreloadDensityInner(res, 213);
1703         } finally {
1704             DrawableTestUtils.setResourcesDensity(res, densityDpi);
1705         }
1706     }
1707 
verifyPreloadDensityInner(Resources res, int densityDpi)1708     private void verifyPreloadDensityInner(Resources res, int densityDpi)
1709             throws XmlPullParserException, IOException {
1710         // Capture initial state at default density.
1711         final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
1712                 res, R.drawable.layer_drawable_density);
1713         final LayerDrawable preloadedDrawable = new LayerDrawable(new Drawable[0]);
1714         preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
1715         final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
1716         final int initialLeftPadding = preloadedDrawable.getLeftPadding();
1717         final int initialRightPadding = preloadedDrawable.getRightPadding();
1718         final int initialContentInsetL = preloadedDrawable.getLayerInsetLeft(0);
1719         final int initialContentInsetR = preloadedDrawable.getLayerInsetRight(0);
1720         final int initialContentWidth = preloadedDrawable.getLayerWidth(0);
1721         final int initialIntrinsicWidth = preloadedDrawable.getIntrinsicWidth();
1722         final int initialBottomPadding = preloadedDrawable.getBottomPadding();
1723         final int initialTopPadding = preloadedDrawable.getTopPadding();
1724         final int initialLayerInsetLeft = preloadedDrawable.getLayerInsetLeft(0);
1725         final int initialLayerInsetRight = preloadedDrawable.getLayerInsetRight(0);
1726         final int initialLayerInsetTop = preloadedDrawable.getLayerInsetTop(0);
1727         final int initialLayerInsetBottom = preloadedDrawable.getLayerInsetBottom(0);
1728         final int initialLayerWidth = preloadedDrawable.getLayerWidth(0);
1729         final int initialLayerHeight = preloadedDrawable.getLayerHeight(0);
1730 
1731         // Set density to half of original. Padding and insets are
1732         // truncated, dimensions are rounded to the nearest pixel. Because
1733         // LayerDrawable's intrinsic width is a combination of padding and
1734         // dimensions, some computation is necessary.
1735         DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
1736         final LayerDrawable halfDrawable =
1737                 (LayerDrawable) preloadedConstantState.newDrawable(res);
1738         // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
1739         final float approxHalf = (float)(densityDpi / 2) / densityDpi;
1740         final int halfContentWidth = Math.round(initialContentWidth * approxHalf);
1741         final int halfLeftPadding = (int) (initialLeftPadding * approxHalf);
1742         final int halfRightPadding = (int) (initialRightPadding * approxHalf);
1743         final int halfContentInsetL = (int) (initialContentInsetL * approxHalf);
1744         final int halfContentInsetR = (int) (initialContentInsetR * approxHalf);
1745         final int halfIntrinsicWidth = halfContentWidth + halfContentInsetL + halfContentInsetR;
1746         assertEquals(halfLeftPadding, halfDrawable.getLeftPadding());
1747         assertEquals(halfRightPadding, halfDrawable.getRightPadding());
1748         assertEquals(halfContentInsetL, halfDrawable.getLayerInsetRight(0));
1749         assertEquals(halfContentInsetR, halfDrawable.getLayerInsetLeft(0));
1750         assertEquals(halfContentWidth, halfDrawable.getLayerWidth(0));
1751         assertEquals(halfIntrinsicWidth, halfDrawable.getIntrinsicWidth());
1752         assertEquals((int) (initialBottomPadding * approxHalf), halfDrawable.getBottomPadding());
1753         assertEquals((int) (initialTopPadding * approxHalf), halfDrawable.getTopPadding());
1754         assertEquals((int) (initialLayerInsetLeft * approxHalf),
1755                 halfDrawable.getLayerInsetLeft(0));
1756         assertEquals((int) (initialLayerInsetRight * approxHalf),
1757                 halfDrawable.getLayerInsetRight(0));
1758         assertEquals((int) (initialLayerInsetTop * approxHalf),
1759                 halfDrawable.getLayerInsetTop(0));
1760         assertEquals((int) (initialLayerInsetBottom * approxHalf),
1761                 halfDrawable.getLayerInsetBottom(0));
1762         assertEquals(Math.round(initialLayerWidth * approxHalf), halfDrawable.getLayerWidth(0));
1763         assertEquals(Math.round(initialLayerHeight * approxHalf), halfDrawable.getLayerHeight(0));
1764 
1765         // Set density to double original.
1766         DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
1767         final LayerDrawable doubleDrawable =
1768                 (LayerDrawable) preloadedConstantState.newDrawable(res);
1769         assertEquals(initialLeftPadding * 2, doubleDrawable.getLeftPadding());
1770         assertEquals(initialRightPadding * 2, doubleDrawable.getRightPadding());
1771         assertEquals(initialContentInsetL * 2, doubleDrawable.getLayerInsetRight(0));
1772         assertEquals(initialContentInsetR * 2, doubleDrawable.getLayerInsetLeft(0));
1773         assertEquals(initialContentWidth * 2, doubleDrawable.getLayerWidth(0));
1774         assertEquals(initialIntrinsicWidth * 2, doubleDrawable.getIntrinsicWidth());
1775         assertEquals(initialBottomPadding * 2, doubleDrawable.getBottomPadding());
1776         assertEquals(initialTopPadding * 2, doubleDrawable.getTopPadding());
1777         assertEquals(initialLayerInsetLeft * 2, doubleDrawable.getLayerInsetLeft(0));
1778         assertEquals(initialLayerInsetRight * 2, doubleDrawable.getLayerInsetRight(0));
1779         assertEquals(initialLayerInsetTop * 2, doubleDrawable.getLayerInsetTop(0));
1780         assertEquals(initialLayerInsetBottom * 2, doubleDrawable.getLayerInsetBottom(0));
1781         assertEquals(initialLayerWidth * 2, doubleDrawable.getLayerWidth(0));
1782         assertEquals(initialLayerHeight * 2, doubleDrawable.getLayerHeight(0));
1783 
1784         // Restore original configuration and metrics.
1785         DrawableTestUtils.setResourcesDensity(res, densityDpi);
1786         final LayerDrawable origDrawable =
1787                 (LayerDrawable) preloadedConstantState.newDrawable(res);
1788         assertEquals(initialLeftPadding, origDrawable.getLeftPadding());
1789         assertEquals(initialRightPadding, origDrawable.getRightPadding());
1790         assertEquals(initialContentInsetL, origDrawable.getLayerInsetRight(0));
1791         assertEquals(initialContentInsetR, origDrawable.getLayerInsetLeft(0));
1792         assertEquals(initialContentWidth, origDrawable.getLayerWidth(0));
1793         assertEquals(initialIntrinsicWidth, origDrawable.getIntrinsicWidth());
1794         assertEquals(initialBottomPadding, origDrawable.getBottomPadding());
1795         assertEquals(initialTopPadding, origDrawable.getTopPadding());
1796         assertEquals(initialLayerInsetLeft, origDrawable.getLayerInsetLeft(0));
1797         assertEquals(initialLayerInsetRight, origDrawable.getLayerInsetRight(0));
1798         assertEquals(initialLayerInsetTop, origDrawable.getLayerInsetTop(0));
1799         assertEquals(initialLayerInsetBottom, origDrawable.getLayerInsetBottom(0));
1800         assertEquals(initialLayerWidth, origDrawable.getLayerWidth(0));
1801         assertEquals(initialLayerHeight, origDrawable.getLayerHeight(0));
1802 
1803         // Ensure theme density is applied correctly.
1804         final Theme t = res.newTheme();
1805 
1806         // The half-density drawable will scale-up all of the values that were
1807         // previously scaled-down, so we need to capture the rounding errors.
1808         halfDrawable.applyTheme(t);
1809 
1810         // Reproduce imprecise truncated scale down, and back up. Note that we don't round.
1811         float approxDouble = 1 / approxHalf;
1812         assertEquals((int) (halfLeftPadding * approxDouble), halfDrawable.getLeftPadding());
1813         assertEquals((int) (halfRightPadding * approxDouble), halfDrawable.getRightPadding());
1814         assertEquals((int) (halfContentInsetL * approxDouble), halfDrawable.getLayerInsetRight(0));
1815         assertEquals((int) (halfContentInsetR * approxDouble), halfDrawable.getLayerInsetLeft(0));
1816         assertEquals((int) (halfContentWidth * approxDouble), halfDrawable.getLayerWidth(0));
1817         assertEquals(halfIntrinsicWidth * 2, halfDrawable.getIntrinsicWidth());
1818         assertEquals((int) ((int) (initialBottomPadding * approxHalf) * approxDouble),
1819                 halfDrawable.getBottomPadding());
1820         assertEquals((int) ((int) (initialTopPadding * approxHalf) * approxDouble),
1821                 halfDrawable.getTopPadding());
1822         assertEquals((int) ((int) (initialLayerInsetLeft * approxHalf) * approxDouble),
1823                 halfDrawable.getLayerInsetLeft(0));
1824         assertEquals((int) ((int) (initialLayerInsetRight * approxHalf) * approxDouble),
1825                 halfDrawable.getLayerInsetRight(0));
1826         assertEquals((int) ((int) (initialLayerInsetTop * approxHalf) * approxDouble),
1827                 halfDrawable.getLayerInsetTop(0));
1828         assertEquals((int) ((int) (initialLayerInsetBottom * approxHalf) * approxDouble),
1829                 halfDrawable.getLayerInsetBottom(0));
1830         assertEquals(Math.round(Math.round(initialLayerWidth * approxHalf) * approxDouble),
1831                 halfDrawable.getLayerWidth(0));
1832         assertEquals(Math.round(Math.round(initialLayerHeight * approxHalf) * approxDouble),
1833                 halfDrawable.getLayerHeight(0));
1834 
1835         // The double-density drawable will scale-down all of the values that
1836         // were previously scaled-up, so we don't need to worry about rounding.
1837         doubleDrawable.applyTheme(t);
1838         assertEquals(initialLeftPadding, doubleDrawable.getLeftPadding());
1839         assertEquals(initialRightPadding, doubleDrawable.getRightPadding());
1840         assertEquals(initialContentInsetL, doubleDrawable.getLayerInsetRight(0));
1841         assertEquals(initialContentInsetR, doubleDrawable.getLayerInsetLeft(0));
1842         assertEquals(initialContentWidth, doubleDrawable.getLayerWidth(0));
1843         assertEquals(initialIntrinsicWidth, doubleDrawable.getIntrinsicWidth());
1844         assertEquals(initialBottomPadding, doubleDrawable.getBottomPadding());
1845         assertEquals(initialTopPadding, doubleDrawable.getTopPadding());
1846         assertEquals(initialLayerInsetLeft, doubleDrawable.getLayerInsetLeft(0));
1847         assertEquals(initialLayerInsetRight, doubleDrawable.getLayerInsetRight(0));
1848         assertEquals(initialLayerInsetTop, doubleDrawable.getLayerInsetTop(0));
1849         assertEquals(initialLayerInsetBottom, doubleDrawable.getLayerInsetBottom(0));
1850         assertEquals(initialLayerWidth, doubleDrawable.getLayerWidth(0));
1851         assertEquals(initialLayerHeight, doubleDrawable.getLayerHeight(0));
1852     }
1853 
1854     @Test
testOpacityChange()1855     public void testOpacityChange() {
1856         ColorDrawable c1 = new ColorDrawable(Color.RED);
1857         ColorDrawable c2 = new ColorDrawable(Color.BLUE);
1858         LayerDrawable dr = new LayerDrawable(new ColorDrawable[] { c1, c2 });
1859         assertEquals(PixelFormat.OPAQUE, dr.getOpacity());
1860 
1861         c1.setTint(0x80FF0000);
1862         c1.setTintMode(PorterDuff.Mode.SRC);
1863         c2.setTint(0x800000FF);
1864         c2.setTintMode(PorterDuff.Mode.SRC);
1865         assertEquals(PixelFormat.TRANSLUCENT, dr.getOpacity());
1866     }
1867 
1868     @Test
testStatefulnessChange()1869     public void testStatefulnessChange() {
1870         ColorDrawable c1 = new ColorDrawable(Color.RED);
1871         ColorDrawable c2 = new ColorDrawable(Color.BLUE);
1872         LayerDrawable dr = new LayerDrawable(new ColorDrawable[] { c1, c2 });
1873         assertEquals(false, dr.isStateful());
1874 
1875         ColorStateList csl = new ColorStateList(
1876                 new int[][] { { android.R.attr.state_enabled }, { } },
1877                 new int[] { Color.RED, Color.BLUE });
1878         c1.setTintList(csl);
1879         assertEquals(true, dr.isStateful());
1880     }
1881 
1882     @Test
testInvalidateDuringInit()1883     public void testInvalidateDuringInit() {
1884         Drawable layer = new RippleDrawable(ColorStateList.valueOf(Color.BLACK), null, null);
1885 
1886         LayerDrawable orig = new LayerDrawable(new Drawable[] { layer });
1887         orig.setBounds(0, 0, 100, 100);
1888 
1889         // This will invoke the layer's invalidateSelf() during construction.
1890         LayerDrawable copy = (LayerDrawable) orig.getConstantState().newDrawable();
1891         assertNotSame(orig, copy);
1892     }
1893 
1894     private static class IntrinsicSizeDrawable extends Drawable {
1895         private final int mIntrinsicWidth;
1896         private final int mIntrinsicHeight;
1897         private final Rect mPadding;
1898 
IntrinsicSizeDrawable(int intrinsicWidth, int intrinsicHeight, Rect padding)1899         public IntrinsicSizeDrawable(int intrinsicWidth, int intrinsicHeight, Rect padding) {
1900             mIntrinsicWidth = intrinsicWidth;
1901             mIntrinsicHeight = intrinsicHeight;
1902             mPadding = new Rect(padding);
1903         }
1904 
1905         @Override
getPadding(Rect padding)1906         public boolean getPadding(Rect padding) {
1907             padding.set(mPadding);
1908             return true;
1909         }
1910 
1911         @Override
getIntrinsicHeight()1912         public int getIntrinsicHeight() {
1913             return mIntrinsicHeight;
1914         }
1915 
1916         @Override
getIntrinsicWidth()1917         public int getIntrinsicWidth() {
1918             return mIntrinsicWidth;
1919         }
1920 
1921         @Override
draw(Canvas canvas)1922         public void draw(Canvas canvas) {
1923         }
1924 
1925         @Override
setAlpha(int alpha)1926         public void setAlpha(int alpha) {
1927         }
1928 
1929         @Override
setColorFilter(ColorFilter colorFilter)1930         public void setColorFilter(ColorFilter colorFilter) {
1931         }
1932 
1933         @Override
getOpacity()1934         public int getOpacity() {
1935             return 0;
1936         }
1937     }
1938 }
1939