1/*
2 * Copyright (C) 2010 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
17package android.graphics.drawable;
18
19import android.graphics.Canvas;
20import android.graphics.ColorFilter;
21import android.graphics.Rect;
22import android.graphics.drawable.Drawable;
23import android.graphics.drawable.MipmapDrawable;
24import android.graphics.drawable.DrawableContainer.DrawableContainerState;
25import android.test.InstrumentationTestCase;
26
27public class MipmapDrawableTest extends InstrumentationTestCase {
28    private MockMipmapDrawable mMipmapDrawable;
29
30    private DrawableContainerState mDrawableContainerState;
31
32    @Override
33    protected void setUp() throws Exception {
34        super.setUp();
35        mMipmapDrawable = new MockMipmapDrawable();
36        mDrawableContainerState = (DrawableContainerState) mMipmapDrawable.getConstantState();
37    }
38
39    public void testMipmapDrawable() {
40        new MipmapDrawable();
41        // Check the values set in the constructor
42        assertNotNull(new MipmapDrawable().getConstantState());
43        assertTrue(new MockMipmapDrawable().hasCalledOnBoundsChanged());
44    }
45
46    public void testAddDrawable() {
47        assertEquals(0, mDrawableContainerState.getChildCount());
48
49        // nothing happens if drawable is null
50        mMipmapDrawable.reset();
51        mMipmapDrawable.addDrawable(null);
52        assertEquals(0, mDrawableContainerState.getChildCount());
53        assertFalse(mMipmapDrawable.hasCalledOnBoundsChanged());
54
55        mMipmapDrawable.reset();
56        mMipmapDrawable.addDrawable(new MockDrawable());
57        assertEquals(1, mDrawableContainerState.getChildCount());
58        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
59
60        mMipmapDrawable.reset();
61        mMipmapDrawable.addDrawable(new MockDrawable());
62        assertEquals(2, mDrawableContainerState.getChildCount());
63        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
64    }
65
66    public void testSortedByHeight() {
67        Drawable small = new MockDrawable(8);
68        Drawable medium = new MockDrawable(32);
69        Drawable large = new MockDrawable(128);
70
71        mMipmapDrawable.addDrawable(medium);
72        assertSame(medium, mDrawableContainerState.getChildren()[0]);
73
74        mMipmapDrawable.addDrawable(small);
75        assertSame(small, mDrawableContainerState.getChildren()[0]);
76        assertSame(medium, mDrawableContainerState.getChildren()[1]);
77
78        mMipmapDrawable.addDrawable(large);
79        assertSame(small, mDrawableContainerState.getChildren()[0]);
80        assertSame(medium, mDrawableContainerState.getChildren()[1]);
81        assertSame(large, mDrawableContainerState.getChildren()[2]);
82
83        mMipmapDrawable.addDrawable(small);
84        assertSame(small, mDrawableContainerState.getChildren()[0]);
85        assertSame(small, mDrawableContainerState.getChildren()[1]);
86        assertSame(medium, mDrawableContainerState.getChildren()[2]);
87        assertSame(large, mDrawableContainerState.getChildren()[3]);
88
89        mMipmapDrawable.addDrawable(medium);
90        assertSame(small, mDrawableContainerState.getChildren()[0]);
91        assertSame(small, mDrawableContainerState.getChildren()[1]);
92        assertSame(medium, mDrawableContainerState.getChildren()[2]);
93        assertSame(medium, mDrawableContainerState.getChildren()[3]);
94        assertSame(large, mDrawableContainerState.getChildren()[4]);
95
96        mMipmapDrawable.addDrawable(large);
97        assertSame(small, mDrawableContainerState.getChildren()[0]);
98        assertSame(small, mDrawableContainerState.getChildren()[1]);
99        assertSame(medium, mDrawableContainerState.getChildren()[2]);
100        assertSame(medium, mDrawableContainerState.getChildren()[3]);
101        assertSame(large, mDrawableContainerState.getChildren()[4]);
102        assertSame(large, mDrawableContainerState.getChildren()[5]);
103    }
104
105    public void testSetBoundsOneItem() {
106        // the method is not called if same bounds are set
107        mMipmapDrawable.reset();
108        mMipmapDrawable.setBounds(mMipmapDrawable.getBounds());
109        assertFalse(mMipmapDrawable.hasCalledOnBoundsChanged());
110
111        // the method is called if different bounds are set, even without drawables
112        mMipmapDrawable.reset();
113        mMipmapDrawable.setBounds(new Rect(0, 0, 0, mMipmapDrawable.getBounds().height() + 1));
114        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
115
116        // adding an item should check bounds to see if new drawable is more appropriate
117        mMipmapDrawable.reset();
118        Drawable item = new MockDrawable(42);
119        mMipmapDrawable.addDrawable(item);
120        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
121
122        // the method is called if different bounds are set
123        mMipmapDrawable.setBounds(new Rect(0, 0, 0, mMipmapDrawable.getBounds().height() + 1));
124        assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged());
125
126        // check that correct drawable is selected for any size.
127        mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight() - 1));
128        assertSame(item, mMipmapDrawable.getCurrent());
129
130        mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight()));
131        assertSame(item, mMipmapDrawable.getCurrent());
132
133        mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight() + 1));
134        assertSame(item, mMipmapDrawable.getCurrent());
135    }
136
137    public void testSetBounds() {
138        Drawable small = new MockDrawable(8);
139        Drawable medium = new MockDrawable(32);
140        Drawable large = new MockDrawable(128);
141
142        mMipmapDrawable.addDrawable(large);
143        mMipmapDrawable.addDrawable(small);
144        mMipmapDrawable.addDrawable(medium);
145
146        // check that correct drawable is selected.
147        mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight() - 1));
148        assertSame(small, mMipmapDrawable.getCurrent());
149
150        mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight()));
151        assertSame(small, mMipmapDrawable.getCurrent());
152
153        mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight() + 1));
154        assertSame(medium, mMipmapDrawable.getCurrent());
155
156        mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight() - 1));
157        assertSame(medium, mMipmapDrawable.getCurrent());
158
159        mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight()));
160        assertSame(medium, mMipmapDrawable.getCurrent());
161
162        mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight() + 1));
163        assertSame(large, mMipmapDrawable.getCurrent());
164
165        mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight() - 1));
166        assertSame(large, mMipmapDrawable.getCurrent());
167
168        mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight()));
169        assertSame(large, mMipmapDrawable.getCurrent());
170
171        mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight() + 1));
172        assertSame(large, mMipmapDrawable.getCurrent());
173    }
174
175    public void testSizes() {
176        // Check default value with no mipmap defined
177        assertEquals(-1, mMipmapDrawable.getIntrinsicHeight());
178        assertEquals(-1, mMipmapDrawable.getIntrinsicWidth());
179        assertEquals(0, mMipmapDrawable.getMinimumHeight());
180        assertEquals(0, mMipmapDrawable.getMinimumWidth());
181
182        Drawable small = new MockDrawable(8, 4);
183        Drawable medium = new MockDrawable(32, 16);
184        Drawable large = new MockDrawable(128, 64);
185
186        mMipmapDrawable.addDrawable(medium);
187        assertEquals(medium.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight());
188        assertEquals(medium.getMinimumHeight(), mMipmapDrawable.getMinimumHeight());
189
190        mMipmapDrawable.addDrawable(large);
191        assertEquals(large.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight());
192        assertEquals(medium.getMinimumHeight(), mMipmapDrawable.getMinimumHeight());
193
194        mMipmapDrawable.addDrawable(small);
195        assertEquals(large.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight());
196        assertEquals(small.getMinimumHeight(), mMipmapDrawable.getMinimumHeight());
197    }
198
199    public void testReplacementWhenAdded() {
200        Drawable small = new MockDrawable(8);
201        Drawable medium = new MockDrawable(32);
202        Drawable large = new MockDrawable(128);
203
204        // Small bounds, so that the smallest mipmap should always be selected
205        mMipmapDrawable.setBounds(new Rect(0, 0, 0, 0));
206
207        // Providing smaller versions, that should immediately be used as current
208        mMipmapDrawable.addDrawable(large);
209        assertSame(large, mMipmapDrawable.getCurrent());
210
211        mMipmapDrawable.addDrawable(medium);
212        assertSame(medium, mMipmapDrawable.getCurrent());
213
214        mMipmapDrawable.addDrawable(small);
215        assertSame(small, mMipmapDrawable.getCurrent());
216    }
217
218    private class MockMipmapDrawable extends MipmapDrawable {
219        private boolean mHasCalledOnBoundsChanged;
220
221        public boolean hasCalledOnBoundsChanged() {
222            return mHasCalledOnBoundsChanged;
223        }
224
225        public void reset() {
226            mHasCalledOnBoundsChanged = false;
227        }
228
229        @Override
230        protected void onBoundsChange(Rect bounds) {
231            super.onBoundsChange(bounds);
232            mHasCalledOnBoundsChanged = true;
233        }
234    }
235
236    private class MockDrawable extends Drawable {
237        int mIntrinsicHeight;
238        int mMinimumHeight;
239
240        public MockDrawable() {
241            this(0);
242        }
243
244        public MockDrawable(int intrinsicHeight) {
245            this(intrinsicHeight, intrinsicHeight);
246        }
247
248        public MockDrawable(int intrinsicHeight, int minimumHeight) {
249            mIntrinsicHeight = intrinsicHeight;
250            mMinimumHeight = minimumHeight;
251        }
252
253        @Override
254        public void draw(Canvas canvas) {
255        }
256
257        @Override
258        public int getOpacity() {
259            return 0;
260        }
261
262        @Override
263        public void setAlpha(int alpha) {
264        }
265
266        @Override
267        public void setColorFilter(ColorFilter cf) {
268        }
269
270        @Override
271        public int getIntrinsicHeight() {
272            return mIntrinsicHeight;
273        }
274
275        @Override
276        public int getMinimumHeight() {
277            return mMinimumHeight;
278        }
279    }
280}
281