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