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