1/*
2 * Copyright (C) 2015 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 */
16package androidx.leanback.graphics;
17
18import static org.junit.Assert.assertEquals;
19import static org.junit.Assert.assertNotSame;
20import static org.junit.Assert.assertTrue;
21
22import android.content.Context;
23import android.graphics.Bitmap;
24import android.graphics.Rect;
25import android.graphics.drawable.BitmapDrawable;
26import android.os.Build;
27import android.support.test.InstrumentationRegistry;
28import android.support.test.filters.SdkSuppress;
29import android.support.test.filters.SmallTest;
30import android.support.test.runner.AndroidJUnit4;
31
32import androidx.leanback.graphics.BoundsRule.ValueRule;
33
34import org.junit.Test;
35import org.junit.runner.RunWith;
36
37/**
38 * Unit test for {@link CompositeDrawableTest}
39 */
40@RunWith(AndroidJUnit4.class)
41@SmallTest
42public class CompositeDrawableTest {
43
44    private static final int HEIGHT = 800;
45    private static final int WIDTH = 600;
46    Bitmap mBitmap = Bitmap.createBitmap(WIDTH, HEIGHT, Bitmap.Config.ARGB_8888);
47
48    @Test
49    public void updateBounds_noBoundsRule() {
50        CompositeDrawable parentDrawable = new CompositeDrawable();
51        FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
52        drawable.setBitmap(mBitmap);
53        Rect bounds = new Rect(0, 0, WIDTH, HEIGHT);
54        parentDrawable.addChildDrawable(drawable);
55        parentDrawable.updateBounds(bounds);
56
57        Rect adjustedBounds = drawable.getBounds();
58        assertEquals(bounds, adjustedBounds);
59    }
60
61    @Test
62    public void updateBounds_withBoundsRule() {
63        CompositeDrawable parentDrawable = new CompositeDrawable();
64        float fraction = 0.5f;
65        FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
66        drawable.setBitmap(mBitmap);
67        Rect bounds = new Rect(0, 0, WIDTH, HEIGHT);
68        assertEquals(HEIGHT, bounds.height());
69        assertEquals(WIDTH, bounds.width());
70
71        // inherit from parent
72        parentDrawable.addChildDrawable(drawable);
73        parentDrawable.getChildAt(0).getBoundsRule().bottom = ValueRule.inheritFromParent(
74                fraction);
75        parentDrawable.updateBounds(bounds);
76
77        Rect adjustedBounds = drawable.getBounds();
78        Rect expectedBounds = new Rect(bounds);
79        expectedBounds.bottom = bounds.top + (int) (HEIGHT * fraction);
80        assertEquals(expectedBounds, adjustedBounds);
81
82        // absolute value
83        drawable.setBounds(bounds);
84        parentDrawable.getChildAt(0).getBoundsRule().bottom = ValueRule.absoluteValue(200);
85        parentDrawable.updateBounds(bounds);
86
87        adjustedBounds = drawable.getBounds();
88        expectedBounds = new Rect(bounds);
89        expectedBounds.bottom = 200;
90        assertEquals(expectedBounds, adjustedBounds);
91
92        // inherit with offset
93        parentDrawable.getChildAt(0).getBoundsRule().bottom =
94                ValueRule.inheritFromParentWithOffset(fraction, 100);
95        parentDrawable.updateBounds(bounds);
96
97        adjustedBounds = drawable.getBounds();
98        expectedBounds = new Rect(bounds);
99        expectedBounds.bottom = bounds.top + (int) (HEIGHT * fraction + 100);
100        assertEquals(expectedBounds, adjustedBounds);
101
102        // inherit from parent 2
103        bounds = new Rect(100, 200, WIDTH, HEIGHT);
104        parentDrawable.getChildAt(0).getBoundsRule().bottom =
105                ValueRule.inheritFromParent(fraction);
106        parentDrawable.updateBounds(bounds);
107
108        adjustedBounds = drawable.getBounds();
109        expectedBounds = new Rect(bounds);
110        expectedBounds.bottom = bounds.top + (int) ((HEIGHT - 200) * fraction);
111        assertEquals(expectedBounds, adjustedBounds);
112    }
113
114    @Test
115    public void updateBounds_withOverride() {
116        CompositeDrawable parentDrawable = new CompositeDrawable();
117        float fraction = 0.5f;
118        FitWidthBitmapDrawable drawable = new FitWidthBitmapDrawable();
119        drawable.setBitmap(mBitmap);
120        Rect bounds = new Rect(0, 0, WIDTH, HEIGHT);
121        drawable.setBounds(bounds);
122        assertEquals(HEIGHT, drawable.getBounds().height());
123        assertEquals(WIDTH, drawable.getBounds().width());
124
125        parentDrawable.addChildDrawable(drawable);
126
127        // inherit from parent
128        BoundsRule boundsRule = parentDrawable.getChildAt(0).getBoundsRule();
129        boundsRule.top = ValueRule.absoluteValue(-200);
130        boundsRule.bottom = ValueRule.inheritFromParent(fraction);
131        parentDrawable.getChildAt(0).getBoundsRule().top.setAbsoluteValue(-100);
132
133        parentDrawable.updateBounds(bounds);
134
135        Rect adjustedBounds = drawable.getBounds();
136        Rect expectedBounds = new Rect(bounds);
137        expectedBounds.top = -100;
138        expectedBounds.bottom = (int) (HEIGHT * fraction);
139        assertEquals(expectedBounds, adjustedBounds);
140
141        // inherit from parent with offset
142        boundsRule.bottom = ValueRule.inheritFromParentWithOffset(1f, -100);
143
144        parentDrawable.updateBounds(bounds);
145
146        adjustedBounds = drawable.getBounds();
147        expectedBounds = new Rect(bounds);
148        expectedBounds.top = -100;
149        expectedBounds.bottom = HEIGHT - 100;
150        assertEquals(expectedBounds, adjustedBounds);
151
152        // using property would change type:
153        CompositeDrawable.ChildDrawable.BOTTOM_ABSOLUTE.set(parentDrawable.getChildAt(0), 0);
154        CompositeDrawable.ChildDrawable.BOTTOM_FRACTION.set(parentDrawable.getChildAt(0), 0.5f);
155        parentDrawable.updateBounds(bounds);
156        adjustedBounds = drawable.getBounds();
157        expectedBounds = new Rect(bounds);
158        expectedBounds.top = -100;
159        expectedBounds.bottom = (int) (0.5f * HEIGHT);
160        assertEquals(expectedBounds, adjustedBounds);
161    }
162
163
164    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.KITKAT)
165    @Test
166    public void constantState() {
167        Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
168        CompositeDrawable parentDrawable = new CompositeDrawable();
169        BitmapDrawable childDrawable = new BitmapDrawable(context.getResources(), mBitmap);
170        parentDrawable.addChildDrawable(childDrawable);
171
172        // getConstantState().newDrawable() will create a new CompositeDrawable with shared states:
173        CompositeDrawable parentDrawble2 = (CompositeDrawable)
174                parentDrawable.getConstantState().newDrawable();
175        BitmapDrawable childDrawable2 = (BitmapDrawable) parentDrawble2.getChildAt(0).getDrawable();
176        parentDrawable.setAlpha(128);
177        assertEquals(128, parentDrawble2.getAlpha());
178        assertEquals(128, childDrawable2.getAlpha());
179
180        // after mutate(), parentDrawble2 will have its own state
181        parentDrawble2.mutate();
182        childDrawable2 = (BitmapDrawable) parentDrawble2.getChildAt(0).getDrawable();
183        parentDrawable.setAlpha(64);
184        assertEquals(64, parentDrawable.getAlpha());
185        assertEquals(64, childDrawable.getAlpha());
186        assertEquals(128, parentDrawble2.getAlpha());
187        assertEquals(128, childDrawable2.getAlpha());
188        childDrawable.setAlpha(100);
189        assertEquals(128, parentDrawble2.getAlpha());
190        assertEquals(128, childDrawable2.getAlpha());
191    }
192
193    @Test
194    public void copyChildDrawableTest() {
195        double delta = .005f;
196        CompositeDrawable parent = new CompositeDrawable();
197        FitWidthBitmapDrawable child = new FitWidthBitmapDrawable();
198        parent.addChildDrawable(child);
199        parent.getChildAt(0).getBoundsRule().bottom =
200                ValueRule.inheritFromParentWithOffset(.5f, 100);
201
202        CompositeDrawable.ChildDrawable newChild = new CompositeDrawable.ChildDrawable(
203                parent.getChildAt(0),
204                parent,
205                null);
206        assertEquals(100, newChild.getBoundsRule().bottom.getAbsoluteValue());
207        assertEquals(.5f, newChild.getBoundsRule().bottom.getFraction(), delta);
208    }
209
210    @Test
211    public void mutateTest() {
212        double delta = .005f;
213        CompositeDrawable parent = new CompositeDrawable();
214        FitWidthBitmapDrawable child = new FitWidthBitmapDrawable();
215        parent.addChildDrawable(child);
216        parent.getChildAt(0).getBoundsRule().bottom =
217                ValueRule.inheritFromParentWithOffset(.5f, 100);
218
219        CompositeDrawable newDrawable = (CompositeDrawable) parent.getConstantState().newDrawable();
220
221        parent.mutate();
222        assertTrue(parent.mMutated);
223
224        CompositeDrawable.ChildDrawable newChild = newDrawable.getChildAt(0);
225        assertNotSame(parent.getChildAt(0), newChild);
226        assertEquals(parent.getChildAt(0).getBoundsRule().bottom.getAbsoluteValue(),
227                newChild.getBoundsRule().bottom.getAbsoluteValue());
228        assertEquals(parent.getChildAt(0).getBoundsRule().bottom.getFraction(),
229                newChild.getBoundsRule().bottom.getFraction(), delta);
230    }
231
232}
233