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 */ 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.assertSame; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.Matchers.any; 24 import static org.mockito.Matchers.anyBoolean; 25 import static org.mockito.Matchers.anyInt; 26 import static org.mockito.Matchers.anyLong; 27 import static org.mockito.Mockito.doNothing; 28 import static org.mockito.Mockito.mock; 29 import static org.mockito.Mockito.never; 30 import static org.mockito.Mockito.reset; 31 import static org.mockito.Mockito.spy; 32 import static org.mockito.Mockito.times; 33 import static org.mockito.Mockito.verify; 34 35 import android.graphics.Canvas; 36 import android.graphics.Color; 37 import android.graphics.ColorFilter; 38 import android.graphics.Insets; 39 import android.graphics.PixelFormat; 40 import android.graphics.PorterDuff; 41 import android.graphics.PorterDuffColorFilter; 42 import android.graphics.Rect; 43 import android.graphics.cts.R; 44 import android.graphics.drawable.BitmapDrawable; 45 import android.graphics.drawable.ColorDrawable; 46 import android.graphics.drawable.Drawable; 47 import android.graphics.drawable.DrawableWrapper; 48 import android.util.StateSet; 49 50 import androidx.annotation.Nullable; 51 import androidx.test.InstrumentationRegistry; 52 import androidx.test.filters.SmallTest; 53 import androidx.test.runner.AndroidJUnit4; 54 55 import org.junit.Test; 56 import org.junit.runner.RunWith; 57 58 import java.util.Arrays; 59 60 @SmallTest 61 @RunWith(AndroidJUnit4.class) 62 public class DrawableWrapperTest { 63 static class MyWrapper extends DrawableWrapper { MyWrapper(Drawable dr)64 public MyWrapper(Drawable dr) { 65 super(dr); 66 } 67 } 68 69 @SuppressWarnings("deprecation") 70 @Test testConstructor()71 public void testConstructor() { 72 Drawable d = new BitmapDrawable(); 73 DrawableWrapper wrapper = new MyWrapper(d); 74 assertSame(d, wrapper.getDrawable()); 75 76 new MyWrapper(null); 77 } 78 79 @SuppressWarnings("deprecation") 80 @Test testGetDrawable()81 public void testGetDrawable() { 82 Drawable d = new BitmapDrawable(); 83 DrawableWrapper wrapper = new MyWrapper(d); 84 assertSame(d, wrapper.getDrawable()); 85 } 86 87 @SuppressWarnings("deprecation") 88 @Test testSetDrawable()89 public void testSetDrawable() { 90 Drawable d = new BitmapDrawable(); 91 DrawableWrapper wrapper = new MyWrapper(null); 92 assertSame(null, wrapper.getDrawable()); 93 94 wrapper.setDrawable(d); 95 assertSame(d, wrapper.getDrawable()); 96 } 97 98 @SuppressWarnings("deprecation") 99 @Test testInvalidateDrawable()100 public void testInvalidateDrawable() { 101 DrawableWrapper wrapper = new MyWrapper(new BitmapDrawable()); 102 103 Drawable.Callback cb = mock(Drawable.Callback.class); 104 wrapper.setCallback(cb); 105 wrapper.invalidateDrawable(null); 106 verify(cb, times(1)).invalidateDrawable(any()); 107 108 reset(cb); 109 wrapper.invalidateDrawable(new BitmapDrawable()); 110 verify(cb, times(1)).invalidateDrawable(any()); 111 112 reset(cb); 113 wrapper.setCallback(null); 114 wrapper.invalidateDrawable(null); 115 verify(cb, never()).invalidateDrawable(any()); 116 } 117 118 @SuppressWarnings("deprecation") 119 @Test testScheduleDrawable()120 public void testScheduleDrawable() { 121 DrawableWrapper wrapper = new MyWrapper(new BitmapDrawable()); 122 123 Drawable.Callback cb = mock(Drawable.Callback.class); 124 wrapper.setCallback(cb); 125 wrapper.scheduleDrawable(null, null, 0); 126 verify(cb, times(1)).scheduleDrawable(any(), any(), anyLong()); 127 128 reset(cb); 129 wrapper.scheduleDrawable(new BitmapDrawable(), () -> {}, 1000L); 130 verify(cb, times(1)).scheduleDrawable(any(), any(), anyLong()); 131 132 reset(cb); 133 wrapper.setCallback(null); 134 wrapper.scheduleDrawable(null, null, 0); 135 verify(cb, never()).scheduleDrawable(any(), any(), anyLong()); 136 } 137 138 @SuppressWarnings("deprecation") 139 @Test testUnscheduleDrawable()140 public void testUnscheduleDrawable() { 141 DrawableWrapper wrapper = new MyWrapper(new BitmapDrawable()); 142 143 Drawable.Callback cb = mock(Drawable.Callback.class); 144 wrapper.setCallback(cb); 145 wrapper.unscheduleDrawable(null, null); 146 verify(cb, times(1)).unscheduleDrawable(any(), any()); 147 148 reset(cb); 149 wrapper.unscheduleDrawable(new BitmapDrawable(), () -> {}); 150 verify(cb, times(1)).unscheduleDrawable(any(), any()); 151 152 reset(cb); 153 wrapper.setCallback(null); 154 wrapper.unscheduleDrawable(null, null); 155 verify(cb, never()).unscheduleDrawable(any(), any()); 156 } 157 158 @Test testCallbackIsSet()159 public void testCallbackIsSet() { 160 Drawable dr = new MockDrawable(); 161 162 DrawableWrapper wrapper = new MyWrapper(dr); 163 assertEquals(wrapper, dr.getCallback()); 164 } 165 166 @Test testDraw()167 public void testDraw() { 168 Drawable mockDrawable = spy(new ColorDrawable(Color.BLUE)); 169 doNothing().when(mockDrawable).draw(any()); 170 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 171 172 wrapper.draw(new Canvas()); 173 verify(mockDrawable, times(1)).draw(any()); 174 175 reset(mockDrawable); 176 doNothing().when(mockDrawable).draw(any()); 177 wrapper.draw(null); 178 verify(mockDrawable, times(1)).draw(any()); 179 } 180 181 @Test testGetChangingConfigurations()182 public void testGetChangingConfigurations() { 183 final int SUPER_CONFIG = 1; 184 final int CONTAINED_DRAWABLE_CONFIG = 2; 185 186 MockDrawable mockDrawable = new MockDrawable(); 187 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 188 189 assertEquals(0, wrapper.getChangingConfigurations()); 190 191 mockDrawable.setChangingConfigurations(CONTAINED_DRAWABLE_CONFIG); 192 assertEquals(CONTAINED_DRAWABLE_CONFIG, wrapper.getChangingConfigurations()); 193 194 wrapper.setChangingConfigurations(SUPER_CONFIG); 195 assertEquals(SUPER_CONFIG | CONTAINED_DRAWABLE_CONFIG, 196 wrapper.getChangingConfigurations()); 197 } 198 199 @Test testGetPadding()200 public void testGetPadding() { 201 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 202 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 203 204 // this method will call contained drawable's getPadding method. 205 wrapper.getPadding(new Rect()); 206 verify(mockDrawable, times(1)).getPadding(any()); 207 } 208 209 @Test testColorFilter()210 public void testColorFilter() { 211 Drawable wrappedDrawable = new MockDrawable(); 212 DrawableWrapper wrapper = new MyWrapper(wrappedDrawable); 213 PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(Color.BLUE, 214 PorterDuff.Mode.SRC_OVER); 215 wrapper.setColorFilter(colorFilter); 216 ColorFilter obtainedColorFilter = wrapper.getColorFilter(); 217 assertEquals("Color filters are not properly returned", colorFilter, obtainedColorFilter); 218 } 219 220 @Test(expected=NullPointerException.class) testGetPaddingNull()221 public void testGetPaddingNull() { 222 DrawableWrapper wrapper = new MyWrapper(new ColorDrawable(Color.RED)); 223 224 wrapper.getPadding(null); 225 } 226 227 @Test testSetVisible()228 public void testSetVisible() { 229 Drawable mockDrawable = spy(new ColorDrawable(Color.YELLOW)); 230 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 231 assertTrue(wrapper.isVisible()); 232 233 reset(mockDrawable); 234 assertTrue(wrapper.setVisible(false, false)); 235 assertFalse(wrapper.isVisible()); 236 verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean()); 237 238 reset(mockDrawable); 239 assertFalse(wrapper.setVisible(false, false)); 240 assertFalse(wrapper.isVisible()); 241 verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean()); 242 243 reset(mockDrawable); 244 assertTrue(wrapper.setVisible(true, false)); 245 assertTrue(wrapper.isVisible()); 246 verify(mockDrawable, times(1)).setVisible(anyBoolean(), anyBoolean()); 247 } 248 249 @Test testSetAlpha()250 public void testSetAlpha() { 251 Drawable mockDrawable = spy(new ColorDrawable(Color.MAGENTA)); 252 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 253 254 // this method will call contained drawable's setAlpha method. 255 wrapper.setAlpha(100); 256 verify(mockDrawable, times(1)).setAlpha(anyInt()); 257 258 reset(mockDrawable); 259 wrapper.setAlpha(Integer.MAX_VALUE); 260 verify(mockDrawable, times(1)).setAlpha(anyInt()); 261 262 reset(mockDrawable); 263 wrapper.setAlpha(-1); 264 verify(mockDrawable, times(1)).setAlpha(anyInt()); 265 } 266 267 @Test testSetColorFilter()268 public void testSetColorFilter() { 269 Drawable mockDrawable = spy(new ColorDrawable(Color.GRAY)); 270 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 271 272 // this method will call contained drawable's setColorFilter method. 273 wrapper.setColorFilter(new ColorFilter()); 274 verify(mockDrawable, times(1)).setColorFilter(any()); 275 276 reset(mockDrawable); 277 wrapper.setColorFilter(null); 278 verify(mockDrawable, times(1)).setColorFilter(any()); 279 } 280 281 @Test testGetOpacity()282 public void testGetOpacity() { 283 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 284 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 285 286 // This method will call contained drawable's getOpacity method. 287 wrapper.setLevel(1); 288 wrapper.getOpacity(); 289 verify(mockDrawable, times(1)).getOpacity(); 290 } 291 292 @Test testIsStateful()293 public void testIsStateful() { 294 Drawable mockDrawable = spy(new ColorDrawable(Color.BLACK)); 295 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 296 297 // this method will call contained drawable's isStateful method. 298 wrapper.isStateful(); 299 verify(mockDrawable, times(1)).isStateful(); 300 } 301 302 @Test testOnStateChange()303 public void testOnStateChange() { 304 Drawable d = new MockDrawable(); 305 MockDrawableWrapper wrapper = new MockDrawableWrapper(d); 306 assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD); 307 308 int[] state = new int[] {1, 2, 3}; 309 assertFalse("child did not change", wrapper.onStateChange(state)); 310 assertEquals("child state did not change", d.getState(), StateSet.WILD_CARD); 311 312 d = InstrumentationRegistry.getTargetContext().getDrawable(R.drawable.statelistdrawable); 313 wrapper = new MockDrawableWrapper(d); 314 assertEquals("initial child state is empty", d.getState(), StateSet.WILD_CARD); 315 wrapper.onStateChange(state); 316 assertTrue("child state changed", Arrays.equals(state, d.getState())); 317 318 // input null as param 319 wrapper.onStateChange(null); 320 // expected, no Exception thrown out, test success 321 } 322 323 @Test testOnLevelChange()324 public void testOnLevelChange() { 325 MockDrawable mockDrawable = new MockDrawable(); 326 MockDrawableWrapper mockDrawableWrapper = new MockDrawableWrapper(mockDrawable); 327 328 assertEquals(0, mockDrawable.getLevel()); 329 assertFalse(mockDrawableWrapper.onLevelChange(0)); 330 assertFalse(mockDrawable.hasCalledOnLevelChange()); 331 332 assertFalse(mockDrawableWrapper.onLevelChange(1000)); 333 assertTrue(mockDrawable.hasCalledOnLevelChange()); 334 assertEquals(1000, mockDrawable.getLevel()); 335 336 mockDrawable.reset(); 337 assertFalse(mockDrawableWrapper.onLevelChange(Integer.MIN_VALUE)); 338 assertTrue(mockDrawable.hasCalledOnLevelChange()); 339 } 340 341 @Test testOnBoundsChange()342 public void testOnBoundsChange() { 343 MockDrawable mockDrawable = new MockDrawable(); 344 MockDrawableWrapper mockDrawableWrapper = new MockDrawableWrapper(mockDrawable); 345 Rect bounds = new Rect(2, 2, 26, 32); 346 mockDrawable.setBounds(bounds); 347 mockDrawableWrapper.onBoundsChange(bounds); 348 349 mockDrawableWrapper = new MockDrawableWrapper(mockDrawable); 350 mockDrawable.setBounds(bounds); 351 mockDrawableWrapper.onBoundsChange(bounds); 352 assertEquals(bounds.left, mockDrawable.getBounds().left); 353 assertEquals(bounds.top, mockDrawable.getBounds().top); 354 assertEquals(bounds.right, mockDrawable.getBounds().right); 355 assertEquals(bounds.bottom, mockDrawable.getBounds().bottom); 356 357 bounds = mockDrawable.getBounds(); 358 assertEquals(2, bounds.left); 359 assertEquals(2, bounds.top); 360 assertEquals(26, bounds.right); 361 assertEquals(32, bounds.bottom); 362 } 363 364 @Test(expected=NullPointerException.class) testOnBoundsChangeNull()365 public void testOnBoundsChangeNull() { 366 MockDrawable mockDrawable = new MockDrawable(); 367 MockDrawableWrapper mockDrawableWrapper = new MockDrawableWrapper(mockDrawable); 368 369 mockDrawableWrapper.onBoundsChange(null); 370 } 371 372 @Test testGetIntrinsicWidth()373 public void testGetIntrinsicWidth() { 374 Drawable mockDrawable = spy(new ColorDrawable(Color.WHITE)); 375 MyWrapper wrapper = new MyWrapper(mockDrawable); 376 377 // this method will call contained drawable's getIntrinsicWidth method. 378 wrapper.getIntrinsicWidth(); 379 verify(mockDrawable, times(1)).getIntrinsicWidth(); 380 } 381 382 @Test testGetIntrinsicHeight()383 public void testGetIntrinsicHeight() { 384 Drawable mockDrawable = spy(new ColorDrawable(Color.RED)); 385 DrawableWrapper wrapper = new MyWrapper(mockDrawable); 386 387 // this method will call contained drawable's getIntrinsicHeight method. 388 wrapper.getIntrinsicHeight(); 389 verify(mockDrawable, times(1)).getIntrinsicHeight(); 390 } 391 392 @Test testGetOpticalInsetsNoInternalDrawable()393 public void testGetOpticalInsetsNoInternalDrawable() { 394 DrawableWrapper wrapper = new MockDrawableWrapper(null); 395 assertEquals(Insets.NONE, wrapper.getOpticalInsets()); 396 } 397 398 @Test testGetOpticalInsetsFromInternalDrawable()399 public void testGetOpticalInsetsFromInternalDrawable() { 400 MockDrawable drawable = new MockDrawable(); 401 drawable.setInsets(Insets.of(30, 60, 90, 120)); 402 DrawableWrapper wrapper = new MockDrawableWrapper(drawable); 403 404 assertEquals(Insets.of(30, 60, 90, 120), wrapper.getOpticalInsets()); 405 } 406 407 @SuppressWarnings("deprecation") 408 @Test testGetConstantState()409 public void testGetConstantState() { 410 DrawableWrapper wrapper = new MyWrapper(new BitmapDrawable()); 411 wrapper.getConstantState(); 412 } 413 414 @Test testJumpToCurrentStateInvoked()415 public void testJumpToCurrentStateInvoked() { 416 MockDrawable inner = new MockDrawable(); 417 DrawableWrapper wrapper = new MockDrawableWrapper(inner); 418 419 wrapper.jumpToCurrentState(); 420 assertTrue(inner.isJumpToCurrentStateInvoked()); 421 } 422 423 // Since Mockito can't mock or spy on protected methods, we have a custom extension 424 // of Drawable to track calls to protected methods. This class also has empty implementations 425 // of the base abstract methods. 426 private static class MockDrawable extends Drawable { 427 private boolean mCalledOnLevelChange = false; 428 private ColorFilter mColorFilter; 429 private Insets mInsets = null; 430 431 private boolean mJumpToCurrentStateInvoked = false; 432 isJumpToCurrentStateInvoked()433 public boolean isJumpToCurrentStateInvoked() { 434 return mJumpToCurrentStateInvoked; 435 } 436 437 @Override jumpToCurrentState()438 public void jumpToCurrentState() { 439 mJumpToCurrentStateInvoked = true; 440 } 441 442 @Override draw(Canvas canvas)443 public void draw(Canvas canvas) { 444 } 445 446 @Override getOpacity()447 public int getOpacity() { 448 return PixelFormat.OPAQUE; 449 } 450 451 @Override setAlpha(int alpha)452 public void setAlpha(int alpha) { 453 } 454 455 @Override setColorFilter(ColorFilter cf)456 public void setColorFilter(ColorFilter cf) { 457 mColorFilter = cf; 458 } 459 460 @Override getColorFilter()461 public ColorFilter getColorFilter() { 462 return mColorFilter; 463 } 464 setInsets(@ullable Insets insets)465 public void setInsets(@Nullable Insets insets) { 466 mInsets = insets; 467 } 468 469 @Override getOpticalInsets()470 public Insets getOpticalInsets() { 471 return mInsets != null ? mInsets : Insets.NONE; 472 } 473 474 @Override onLevelChange(int level)475 protected boolean onLevelChange(int level) { 476 mCalledOnLevelChange = true; 477 return super.onLevelChange(level); 478 } 479 hasCalledOnLevelChange()480 public boolean hasCalledOnLevelChange() { 481 return mCalledOnLevelChange; 482 } 483 reset()484 public void reset() { 485 mCalledOnLevelChange = false; 486 } 487 } 488 489 private static class MockDrawableWrapper extends DrawableWrapper { MockDrawableWrapper()490 MockDrawableWrapper() { 491 super(null); 492 } 493 MockDrawableWrapper(Drawable drawable)494 public MockDrawableWrapper(Drawable drawable) { 495 super(drawable); 496 } 497 498 @Override onStateChange(int[] state)499 protected boolean onStateChange(int[] state) { 500 return super.onStateChange(state); 501 } 502 503 @Override onLevelChange(int level)504 protected boolean onLevelChange(int level) { 505 return super.onLevelChange(level); 506 } 507 508 @Override onBoundsChange(Rect bounds)509 protected void onBoundsChange(Rect bounds) { 510 super.onBoundsChange(bounds); 511 } 512 } 513 } 514