xref: /aosp_15_r20/cts/tests/tests/graphics/src/android/graphics/drawable/cts/TransitionDrawableTest.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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.assertTrue;
22 import static org.junit.Assert.fail;
23 import static org.mockito.Matchers.any;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.never;
26 import static org.mockito.Mockito.reset;
27 import static org.mockito.Mockito.times;
28 import static org.mockito.Mockito.verify;
29 
30 import android.content.Context;
31 import android.graphics.Bitmap;
32 import android.graphics.Bitmap.Config;
33 import android.graphics.Canvas;
34 import android.graphics.Color;
35 import android.graphics.cts.R;
36 import android.graphics.drawable.Drawable;
37 import android.graphics.drawable.TransitionDrawable;
38 
39 import androidx.test.InstrumentationRegistry;
40 import androidx.test.filters.LargeTest;
41 import androidx.test.runner.AndroidJUnit4;
42 
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 
47 @LargeTest
48 @RunWith(AndroidJUnit4.class)
49 public class TransitionDrawableTest {
50     private static final int COLOR1 = Color.BLUE;
51 
52     private static final int COLOR0 = Color.RED;
53 
54     private static final int CANVAS_WIDTH = 10;
55 
56     private static final int CANVAS_HEIGHT = 10;
57 
58     private Context mContext;
59     private TransitionDrawable mTransitionDrawable;
60     private Bitmap mBitmap;
61     private Canvas mCanvas;
62 
63     @Before
setup()64     public void setup() {
65         mContext = InstrumentationRegistry.getTargetContext();
66         mTransitionDrawable = (TransitionDrawable) mContext.getDrawable(R.drawable.transition_test);
67         mTransitionDrawable.setBounds(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
68 
69         mBitmap = Bitmap.createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT, Config.ARGB_8888);
70         mCanvas = new Canvas(mBitmap);
71     }
72 
73     @Test
testConstructor()74     public void testConstructor() {
75         Drawable[] drawables = new Drawable[] {
76                 mContext.getDrawable(R.drawable.testimage),
77                 mContext.getDrawable(R.drawable.levellistdrawable)
78         };
79         new TransitionDrawable(drawables);
80     }
81 
82     @Test
testStartTransition()83     public void testStartTransition() {
84         Drawable.Callback cb = mock(Drawable.Callback.class);
85         mTransitionDrawable.setCallback(cb);
86 
87         // start when there is no transition
88         mTransitionDrawable.startTransition(2000);
89         verify(cb, times(1)).invalidateDrawable(any());
90         verifyTransition(COLOR0, COLOR1, 2000);
91 
92         // start when there is a transition in progress
93         makeTransitionInProgress(2000, 1000);
94         reset(cb);
95         mTransitionDrawable.startTransition(2000);
96         verify(cb, times(1)).invalidateDrawable(any());
97         verifyTransition(COLOR0, COLOR1, 2000);
98 
99         // start when there is a reverse transition in progress
100         makeReverseTransitionInProgress(2000, 1000);
101         reset(cb);
102         mTransitionDrawable.startTransition(2000);
103         verify(cb, times(1)).invalidateDrawable(any());
104         verifyTransition(COLOR0, COLOR1, 2000);
105 
106         // should not accept negative duration
107         mTransitionDrawable.startTransition(-1);
108     }
109 
110     @Test
testResetTransition()111     public void testResetTransition() {
112         Drawable.Callback cb = mock(Drawable.Callback.class);
113         mTransitionDrawable.setCallback(cb);
114 
115         // reset when there is no transition
116         mTransitionDrawable.resetTransition();
117         verify(cb, times(1)).invalidateDrawable(any());
118 
119         // reset when there is a transition in progress
120         makeTransitionInProgress(2000, 1000);
121         reset(cb);
122         mTransitionDrawable.resetTransition();
123         verify(cb, times(1)).invalidateDrawable(any());
124         verifyTransitionStart(COLOR0);
125         verifyTransitionEnd(COLOR0, 2000);
126 
127         // reset when there is a reverse transition in progress
128         makeReverseTransitionInProgress(2000, 1000);
129         reset(cb);
130         mTransitionDrawable.resetTransition();
131         verify(cb, times(1)).invalidateDrawable(any());
132         verifyTransitionStart(COLOR0);
133         verifyTransitionEnd(COLOR0, 2000);
134     }
135 
136     @Test
testReverseTransition()137     public void testReverseTransition() {
138         Drawable.Callback cb = mock(Drawable.Callback.class);
139         mTransitionDrawable.setCallback(cb);
140 
141         // reverse when there is no transition
142         mTransitionDrawable.reverseTransition(2000);
143         verify(cb, times(1)).invalidateDrawable(any());
144         verifyTransition(COLOR0, COLOR1, 2000);
145 
146         // reverse after the other transition ends
147         reset(cb);
148         mTransitionDrawable.reverseTransition(2000);
149         verify(cb, times(1)).invalidateDrawable(any());
150         verifyTransition(COLOR1, COLOR0, 2000);
151 
152         // reverse when there is a transition in progress
153         makeTransitionInProgress(2000, 1000);
154         reset(cb);
155         mTransitionDrawable.reverseTransition(20000);
156         verify(cb, never()).invalidateDrawable(any());
157         int colorFrom = mBitmap.getPixel(0, 0);
158         verifyTransition(colorFrom, COLOR0, 1500);
159 
160         // reverse when there is a reverse transition in progress
161         makeReverseTransitionInProgress(2000, 1000);
162         reset(cb);
163         mTransitionDrawable.reverseTransition(20000);
164         verify(cb, never()).invalidateDrawable(any());
165         colorFrom = mBitmap.getPixel(0, 0);
166         verifyTransition(colorFrom, COLOR1, 1500);
167 
168         // should not accept negative duration
169         mTransitionDrawable.reverseTransition(-1);
170     }
171 
172     @Test(expected=NullPointerException.class)
testDrawWithNullCanvas()173     public void testDrawWithNullCanvas() {
174         mTransitionDrawable.draw(null);
175     }
176 
177     //  This boolean takes effect when the drawable is drawn and the effect can not be tested.
178     @Test
testAccessCrossFadeEnabled()179     public void testAccessCrossFadeEnabled() {
180         assertFalse(mTransitionDrawable.isCrossFadeEnabled());
181 
182         mTransitionDrawable.setCrossFadeEnabled(true);
183         assertTrue(mTransitionDrawable.isCrossFadeEnabled());
184 
185         mTransitionDrawable.setCrossFadeEnabled(false);
186         assertFalse(mTransitionDrawable.isCrossFadeEnabled());
187     }
188 
verifyTransition(int colorFrom, int colorTo, long delay)189     private void verifyTransition(int colorFrom, int colorTo, long delay) {
190         verifyTransitionStart(colorFrom);
191         verifyTransitionInProgress(colorFrom, colorTo, delay / 2);
192         verifyTransitionEnd(colorTo, delay);
193     }
194 
verifyTransitionStart(int colorFrom)195     private void verifyTransitionStart(int colorFrom) {
196         mBitmap.eraseColor(Color.TRANSPARENT);
197         mTransitionDrawable.draw(mCanvas);
198         verifyColorFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorFrom);
199     }
200 
verifyTransitionInProgress(int colorFrom, int colorTo, long delay)201     private void verifyTransitionInProgress(int colorFrom, int colorTo, long delay) {
202         drawAfterDelaySync(delay);
203         verifyColorNotFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorFrom);
204         verifyColorNotFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorTo);
205     }
206 
verifyTransitionEnd(int colorTo, long delay)207     private void verifyTransitionEnd(int colorTo, long delay) {
208         drawAfterDelaySync(delay);
209         verifyColorFillRect(mBitmap, 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, colorTo);
210     }
211 
verifyColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color)212     private void verifyColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color) {
213         for (int i = x; i < x + w; i++) {
214             for (int j = y; j < y + h; j++) {
215                 assertEquals(color, bmp.getPixel(i, j));
216             }
217         }
218     }
219 
verifyColorNotFillRect(Bitmap bmp, int x, int y, int w, int h, int color)220     private void verifyColorNotFillRect(Bitmap bmp, int x, int y, int w, int h, int color) {
221         for (int i = x; i < x + w; i++) {
222             for (int j = y; j < y + h; j++) {
223                 assertTrue(color != bmp.getPixel(i, j));
224             }
225         }
226     }
227 
makeReverseTransitionInProgress(int duration, int delay)228     private void makeReverseTransitionInProgress(int duration, int delay) {
229         mTransitionDrawable.resetTransition();
230         mTransitionDrawable.startTransition(2000);
231         verifyTransition(COLOR0, COLOR1, 2000);
232         mTransitionDrawable.reverseTransition(duration);
233         verifyTransitionStart(COLOR1);
234         verifyTransitionInProgress(COLOR1, COLOR0, delay);
235     }
236 
makeTransitionInProgress(int duration, int delay)237     private void makeTransitionInProgress(int duration, int delay) {
238         mTransitionDrawable.resetTransition();
239         mTransitionDrawable.startTransition(duration);
240         verifyTransitionStart(COLOR0);
241         verifyTransitionInProgress(COLOR0, COLOR1, delay);
242     }
243 
drawAfterDelaySync(long delay)244     private void drawAfterDelaySync(long delay) {
245         Thread t = new Thread(() -> {
246             mBitmap.eraseColor(Color.TRANSPARENT);
247             mTransitionDrawable.draw(mCanvas);
248         });
249         try {
250             Thread.sleep(delay);
251             t.start();
252             t.join();
253         } catch (InterruptedException e) {
254             // catch and fail, because propagating this all the way up is messy
255             fail(e.getMessage());
256         }
257     }
258 }
259