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