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.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertSame; 24 import static org.junit.Assert.assertTrue; 25 import static org.junit.Assert.fail; 26 import static org.mockito.Matchers.any; 27 import static org.mockito.Matchers.anyInt; 28 import static org.mockito.Matchers.anyLong; 29 import static org.mockito.Mockito.atLeastOnce; 30 import static org.mockito.Mockito.doAnswer; 31 import static org.mockito.Mockito.doNothing; 32 import static org.mockito.Mockito.doReturn; 33 import static org.mockito.Mockito.mock; 34 import static org.mockito.Mockito.never; 35 import static org.mockito.Mockito.reset; 36 import static org.mockito.Mockito.spy; 37 import static org.mockito.Mockito.times; 38 import static org.mockito.Mockito.verify; 39 40 import android.content.res.ColorStateList; 41 import android.graphics.Canvas; 42 import android.graphics.Color; 43 import android.graphics.ColorFilter; 44 import android.graphics.PixelFormat; 45 import android.graphics.PorterDuff; 46 import android.graphics.PorterDuff.Mode; 47 import android.graphics.Rect; 48 import android.graphics.drawable.ColorDrawable; 49 import android.graphics.drawable.Drawable; 50 import android.graphics.drawable.DrawableContainer; 51 import android.graphics.drawable.DrawableContainer.DrawableContainerState; 52 import android.graphics.drawable.LevelListDrawable; 53 import android.support.test.filters.SmallTest; 54 import android.support.test.runner.AndroidJUnit4; 55 56 import org.junit.Before; 57 import org.junit.Test; 58 import org.junit.runner.RunWith; 59 import org.mockito.invocation.InvocationOnMock; 60 61 import java.util.Arrays; 62 63 @SmallTest 64 @RunWith(AndroidJUnit4.class) 65 public class DrawableContainerTest { 66 private DrawableContainerState mDrawableContainerState; 67 68 private MockDrawableContainer mMockDrawableContainer; 69 private DrawableContainer mDrawableContainer; 70 71 @Before 72 public void setup() { 73 // DrawableContainerState has no public constructor. Obtain an instance through 74 // LevelListDrawable.getConstants(). This is fine for testing the final methods of 75 // DrawableContainerState. 76 mDrawableContainerState = 77 (DrawableContainerState) new LevelListDrawable().getConstantState(); 78 assertNotNull(mDrawableContainerState); 79 80 mMockDrawableContainer = new MockDrawableContainer(); 81 // While the two fields point to the same object, the second one is there to 82 // workaround the bug in CTS coverage tool that is not recognizing calls on 83 // subclasses. 84 mDrawableContainer = mMockDrawableContainer; 85 86 assertNull(mDrawableContainer.getCurrent()); 87 } 88 89 @Test(expected=NullPointerException.class) 90 public void testConstantStateNotSet() { 91 // This should throw NPE since our mock container has not been configured with 92 // constant state yet 93 mDrawableContainer.getConstantState(); 94 } 95 96 @Test 97 public void testDraw() { 98 mDrawableContainer.draw(null); 99 mDrawableContainer.draw(new Canvas()); 100 101 mMockDrawableContainer.setConstantState(mDrawableContainerState); 102 Drawable dr = spy(new ColorDrawable(Color.WHITE)); 103 addAndSelectDrawable(dr); 104 105 reset(dr); 106 doNothing().when(dr).draw(any()); 107 mDrawableContainer.draw(null); 108 verify(dr, times(1)).draw(any()); 109 110 reset(dr); 111 doNothing().when(dr).draw(any()); 112 mDrawableContainer.draw(new Canvas()); 113 verify(dr, times(1)).draw(any()); 114 } 115 116 @Test 117 public void testSetEnterFadeDuration() { 118 verifySetEnterFadeDuration(1000); 119 verifySetEnterFadeDuration(0); 120 } 121 122 private void verifySetEnterFadeDuration(int enterFadeDuration) { 123 DrawableContainer container = new LevelListDrawable(); 124 DrawableContainerState cs = ((DrawableContainerState) container.getConstantState()); 125 container.setEnterFadeDuration(enterFadeDuration); 126 assertEquals(enterFadeDuration, cs.getEnterFadeDuration()); 127 } 128 129 @Test 130 public void testSetExitFadeDuration() { 131 verifySetExitFadeDuration(1000); 132 verifySetExitFadeDuration(0); 133 } 134 135 private void verifySetExitFadeDuration(int exitFadeDuration) { 136 DrawableContainer container = new LevelListDrawable(); 137 DrawableContainerState cs = ((DrawableContainerState) container.getConstantState()); 138 container.setExitFadeDuration(exitFadeDuration); 139 assertEquals(exitFadeDuration, cs.getExitFadeDuration()); 140 } 141 142 @Test(expected=NullPointerException.class) 143 public void testGetChangingConfigurationsNoConstantState() { 144 // Should throw NullPointerException if the constant state is not set 145 mDrawableContainer.getChangingConfigurations(); 146 } 147 148 @Test 149 public void testGetChangingConfigurations() { 150 mMockDrawableContainer.setConstantState(mDrawableContainerState); 151 MockDrawable dr0 = new MockDrawable(); 152 dr0.setChangingConfigurations(0x001); 153 mDrawableContainerState.addChild(dr0); 154 MockDrawable dr1 = new MockDrawable(); 155 dr1.setChangingConfigurations(0x010); 156 mDrawableContainerState.addChild(dr1); 157 mDrawableContainer.selectDrawable(0); 158 assertSame(dr0, mDrawableContainer.getCurrent()); 159 160 // can not set mDrawableContainerState's ChangingConfigurations 161 mDrawableContainer.setChangingConfigurations(0x100); 162 assertEquals(0x111 | mDrawableContainerState.getChangingConfigurations(), 163 mDrawableContainer.getChangingConfigurations()); 164 } 165 166 @Test(expected=NullPointerException.class) 167 public void testGetPaddingNoConstantState() { 168 Rect result = new Rect(1, 1, 1, 1); 169 // Should throw NullPointerException if the constant state is not set 170 mDrawableContainer.getPadding(result); 171 } 172 173 @Test 174 public void testGetPadding() { 175 Rect result = new Rect(1, 1, 1, 1); 176 177 mMockDrawableContainer.setConstantState(mDrawableContainerState); 178 Drawable dr0 = spy(new ColorDrawable(Color.BLUE)); 179 doAnswer((InvocationOnMock invocation) -> { 180 Rect target = (Rect) invocation.getArguments() [0]; 181 target.set(1, 2, 0, 0); 182 return true; 183 }).when(dr0).getPadding(any()); 184 mDrawableContainerState.addChild(dr0); 185 Drawable dr1 = spy(new ColorDrawable(Color.RED)); 186 doAnswer((InvocationOnMock invocation) -> { 187 Rect target = (Rect) invocation.getArguments() [0]; 188 target.set(0, 0, 3, 4); 189 return true; 190 }).when(dr1).getPadding(any()); 191 mDrawableContainerState.addChild(dr1); 192 mDrawableContainer.selectDrawable(0); 193 assertSame(dr0, mDrawableContainer.getCurrent()); 194 195 // use the current drawable's padding 196 mDrawableContainerState.setVariablePadding(true); 197 assertNull(mDrawableContainerState.getConstantPadding()); 198 assertTrue(mDrawableContainer.getPadding(result)); 199 assertEquals(new Rect(1, 2, 0, 0), result); 200 201 // use constant state's padding 202 mDrawableContainerState.setVariablePadding(false); 203 assertNotNull(mDrawableContainerState.getConstantPadding()); 204 assertTrue(mDrawableContainer.getPadding(result)); 205 assertEquals(mDrawableContainerState.getConstantPadding(), result); 206 207 // use default padding 208 mDrawableContainer.selectDrawable(-1); 209 assertNull(mDrawableContainer.getCurrent()); 210 mDrawableContainerState.setVariablePadding(true); 211 assertNull(mDrawableContainerState.getConstantPadding()); 212 assertFalse(mDrawableContainer.getPadding(result)); 213 assertEquals(new Rect(0, 0, 0, 0), result); 214 215 try { 216 mDrawableContainer.getPadding(null); 217 fail("Should throw NullPointerException if the padding is null."); 218 } catch (NullPointerException e) { 219 } 220 } 221 222 @Test 223 public void testSetAlpha() { 224 mDrawableContainer.setAlpha(0); 225 226 mMockDrawableContainer.setConstantState(mDrawableContainerState); 227 Drawable mockDrawable = spy(new ColorDrawable(Color.BLACK)); 228 addAndSelectDrawable(mockDrawable); 229 230 // call current drawable's setAlpha if alpha is changed. 231 reset(mockDrawable); 232 mDrawableContainer.setAlpha(1); 233 verify(mockDrawable, times(1)).setAlpha(1); 234 235 // does not call it if alpha is not changed. 236 reset(mockDrawable); 237 mDrawableContainer.setAlpha(1); 238 verify(mockDrawable, never()).setAlpha(anyInt()); 239 } 240 241 @Test 242 public void testSetDither() { 243 mMockDrawableContainer.setConstantState(mDrawableContainerState); 244 mDrawableContainer.setDither(false); 245 mDrawableContainer.setDither(true); 246 247 Drawable dr = spy(new ColorDrawable(Color.BLUE)); 248 addAndSelectDrawable(dr); 249 250 // call current drawable's setDither if dither is changed. 251 reset(dr); 252 mDrawableContainer.setDither(false); 253 verify(dr, times(1)).setDither(false); 254 255 // does not call it if dither is not changed. 256 reset(dr); 257 mDrawableContainer.setDither(true); 258 verify(dr, times(1)).setDither(true); 259 } 260 261 @Test 262 public void testSetHotspotBounds() { 263 Rect bounds = new Rect(10, 15, 100, 150); 264 assertNull(mDrawableContainer.getCurrent()); 265 266 mMockDrawableContainer.setConstantState(mDrawableContainerState); 267 268 MockDrawable dr = new MockDrawable(); 269 addAndSelectDrawable(dr); 270 271 dr.reset(); 272 mDrawableContainer.setHotspotBounds(bounds.left, bounds.top, bounds.right, bounds.bottom); 273 Rect outRect = new Rect(); 274 mDrawableContainer.getHotspotBounds(outRect); 275 assertEquals(bounds, outRect); 276 277 dr.reset(); 278 } 279 280 @Test 281 public void testGetHotspotBounds() { 282 Rect bounds = new Rect(10, 15, 100, 150); 283 assertNull(mDrawableContainer.getCurrent()); 284 285 mMockDrawableContainer.setConstantState(mDrawableContainerState); 286 287 MockDrawable dr = new MockDrawable(); 288 addAndSelectDrawable(dr); 289 290 dr.reset(); 291 mDrawableContainer.setHotspotBounds(bounds.left, bounds.top, bounds.right, bounds.bottom); 292 Rect outRect = new Rect(); 293 mDrawableContainer.getHotspotBounds(outRect); 294 assertEquals(bounds, outRect); 295 296 dr.reset(); 297 } 298 299 @Test 300 public void testSetColorFilter() { 301 mMockDrawableContainer.setConstantState(mDrawableContainerState); 302 mDrawableContainer.setColorFilter(null); 303 mDrawableContainer.setColorFilter(new ColorFilter()); 304 305 Drawable mockDrawable = spy(new ColorDrawable(Color.MAGENTA)); 306 addAndSelectDrawable(mockDrawable); 307 308 // call current drawable's setColorFilter if filter is changed. 309 reset(mockDrawable); 310 mDrawableContainer.setColorFilter(null); 311 verify(mockDrawable, times(1)).setColorFilter(null); 312 313 // does not call it if filter is not changed. 314 reset(mockDrawable); 315 mDrawableContainer.setColorFilter(new ColorFilter()); 316 verify(mockDrawable, times(1)).setColorFilter(any()); 317 } 318 319 @Test 320 public void testSetTint() { 321 mMockDrawableContainer.setConstantState(mDrawableContainerState); 322 mDrawableContainer.setTint(Color.BLACK); 323 mDrawableContainer.setTintMode(Mode.SRC_OVER); 324 325 Drawable dr = spy(new ColorDrawable(Color.GREEN)); 326 addAndSelectDrawable(dr); 327 328 verify(dr, times(1)).setTintMode(Mode.SRC_OVER); 329 330 mDrawableContainer.setTintList(null); 331 mDrawableContainer.setTintMode(null); 332 verify(dr, times(1)).setTintMode(null); 333 } 334 335 @Test 336 public void testOnBoundsChange() { 337 mMockDrawableContainer.onBoundsChange(new Rect()); 338 mMockDrawableContainer.onBoundsChange(null); 339 340 mMockDrawableContainer.setConstantState(mDrawableContainerState); 341 MockDrawable dr = new MockDrawable(); 342 dr.setBounds(new Rect()); 343 addAndSelectDrawable(dr); 344 345 // set current drawable's bounds. 346 dr.reset(); 347 assertEquals(new Rect(), dr.getBounds()); 348 mMockDrawableContainer.onBoundsChange(new Rect(1, 1, 1, 1)); 349 assertTrue(dr.hasOnBoundsChangedCalled()); 350 assertEquals(new Rect(1, 1, 1, 1), dr.getBounds()); 351 352 dr.reset(); 353 mMockDrawableContainer.onBoundsChange(new Rect(1, 1, 1, 1)); 354 assertFalse(dr.hasOnBoundsChangedCalled()); 355 assertEquals(new Rect(1, 1, 1, 1), dr.getBounds()); 356 357 try { 358 mMockDrawableContainer.onBoundsChange(null); 359 fail("Should throw NullPointerException if the bounds is null."); 360 } catch (NullPointerException e) { 361 } 362 } 363 364 @Test(expected=NullPointerException.class) 365 public void testIsStatefulNoConstantState() { 366 // Should throw NullPointerException if the constant state is not set 367 mDrawableContainer.isStateful(); 368 } 369 370 @Test 371 public void testIsStateful() { 372 mMockDrawableContainer.setConstantState(mDrawableContainerState); 373 Drawable dr0 = spy(new ColorDrawable(Color.YELLOW)); 374 doReturn(true).when(dr0).isStateful(); 375 mDrawableContainerState.addChild(dr0); 376 Drawable dr1 = spy(new ColorDrawable(Color.GREEN)); 377 doReturn(false).when(dr1).isStateful(); 378 mDrawableContainerState.addChild(dr1); 379 380 // return result of constant state's isStateful 381 assertEquals(mDrawableContainerState.isStateful(), mDrawableContainer.isStateful()); 382 assertEquals(true, mDrawableContainer.isStateful()); 383 384 mDrawableContainer.selectDrawable(1); 385 assertEquals(mDrawableContainerState.isStateful(), mDrawableContainer.isStateful()); 386 assertEquals(true, mDrawableContainer.isStateful()); 387 } 388 389 @Test 390 public void testOnStateChange() { 391 assertFalse(mMockDrawableContainer.onStateChange(new int[] { 0 })); 392 assertFalse(mMockDrawableContainer.onStateChange(null)); 393 394 mMockDrawableContainer.setConstantState(mDrawableContainerState); 395 MockDrawable dr = new MockDrawable(); 396 dr.setState(new int[] { 0 }); 397 addAndSelectDrawable(dr); 398 399 // set current drawable's state. 400 dr.reset(); 401 assertNotNull(dr.getState()); 402 mMockDrawableContainer.onStateChange(null); 403 assertTrue(dr.hasOnStateChangedCalled()); 404 assertNull(dr.getState()); 405 406 dr.reset(); 407 mMockDrawableContainer.onStateChange(new int[] { 0 }); 408 assertTrue(dr.hasOnStateChangedCalled()); 409 assertTrue(Arrays.equals(new int[] { 0 }, dr.getState())); 410 411 dr.reset(); 412 assertFalse(mMockDrawableContainer.onStateChange(new int[] { 0 })); 413 assertFalse(dr.hasOnStateChangedCalled()); 414 assertTrue(Arrays.equals(new int[] { 0 }, dr.getState())); 415 } 416 417 @Test 418 public void testOnLevelChange() { 419 assertFalse(mMockDrawableContainer.onLevelChange(Integer.MAX_VALUE)); 420 assertFalse(mMockDrawableContainer.onLevelChange(Integer.MIN_VALUE)); 421 422 mMockDrawableContainer.setConstantState(mDrawableContainerState); 423 MockDrawable dr = new MockDrawable(); 424 dr.setLevel(0); 425 addAndSelectDrawable(dr); 426 427 // set current drawable's level. 428 dr.reset(); 429 assertEquals(0, dr.getLevel()); 430 mMockDrawableContainer.onLevelChange(Integer.MAX_VALUE); 431 assertEquals(Integer.MAX_VALUE, dr.getLevel()); 432 assertTrue(dr.hasOnLevelChangedCalled()); 433 434 dr.reset(); 435 assertEquals(Integer.MAX_VALUE, dr.getLevel()); 436 mMockDrawableContainer.onLevelChange(Integer.MIN_VALUE); 437 assertEquals(Integer.MIN_VALUE, dr.getLevel()); 438 assertTrue(dr.hasOnLevelChangedCalled()); 439 440 dr.reset(); 441 assertEquals(Integer.MIN_VALUE, dr.getLevel()); 442 assertFalse(mMockDrawableContainer.onLevelChange(Integer.MIN_VALUE)); 443 assertEquals(Integer.MIN_VALUE, dr.getLevel()); 444 assertFalse(dr.hasOnLevelChangedCalled()); 445 } 446 447 @Test(expected=NullPointerException.class) 448 public void testGetIntrinsicWidthNoConstantState() { 449 // Should throw NullPointerException if the constant state is not set 450 mDrawableContainer.getIntrinsicWidth(); 451 } 452 453 @Test 454 public void testGetIntrinsicWidth() { 455 mMockDrawableContainer.setConstantState(mDrawableContainerState); 456 Drawable dr0 = spy(new ColorDrawable(Color.RED)); 457 doReturn(1).when(dr0).getIntrinsicWidth(); 458 mDrawableContainerState.addChild(dr0); 459 Drawable dr1 = spy(new ColorDrawable(Color.GREEN)); 460 doReturn(2).when(dr1).getIntrinsicWidth(); 461 mDrawableContainerState.addChild(dr1); 462 463 // return result of constant state's getConstantWidth 464 mDrawableContainerState.setConstantSize(true); 465 assertEquals(mDrawableContainerState.getConstantWidth(), 466 mDrawableContainer.getIntrinsicWidth()); 467 assertEquals(2, mDrawableContainer.getIntrinsicWidth()); 468 469 // return default value 470 mDrawableContainerState.setConstantSize(false); 471 assertNull(mDrawableContainer.getCurrent()); 472 assertEquals(-1, mDrawableContainer.getIntrinsicWidth()); 473 474 // return current drawable's getIntrinsicWidth 475 mDrawableContainer.selectDrawable(0); 476 assertSame(dr0, mDrawableContainer.getCurrent()); 477 assertEquals(1, mDrawableContainer.getIntrinsicWidth()); 478 } 479 480 @Test(expected=NullPointerException.class) 481 public void testGetIntrinsicHeightNoConstantState() { 482 // Should throw NullPointerException if the constant state is not set 483 mDrawableContainer.getIntrinsicHeight(); 484 } 485 486 @Test 487 public void testGetIntrinsicHeight() { 488 mMockDrawableContainer.setConstantState(mDrawableContainerState); 489 Drawable dr0 = spy(new ColorDrawable(Color.RED)); 490 doReturn(1).when(dr0).getIntrinsicHeight(); 491 mDrawableContainerState.addChild(dr0); 492 Drawable dr1 = spy(new ColorDrawable(Color.GREEN)); 493 doReturn(2).when(dr1).getIntrinsicHeight(); 494 mDrawableContainerState.addChild(dr1); 495 496 // return result of constant state's getConstantHeight 497 mDrawableContainerState.setConstantSize(true); 498 assertEquals(mDrawableContainerState.getConstantHeight(), 499 mDrawableContainer.getIntrinsicHeight()); 500 assertEquals(2, mDrawableContainer.getIntrinsicHeight()); 501 502 // return default value 503 mDrawableContainerState.setConstantSize(false); 504 assertNull(mDrawableContainer.getCurrent()); 505 assertEquals(-1, mDrawableContainer.getIntrinsicHeight()); 506 507 // return current drawable's getIntrinsicHeight 508 mDrawableContainer.selectDrawable(0); 509 assertSame(dr0, mDrawableContainer.getCurrent()); 510 assertEquals(1, mDrawableContainer.getIntrinsicHeight()); 511 } 512 513 @Test(expected=NullPointerException.class) 514 public void testGetMinimumWidthNoConstantState() { 515 // Should throw NullPointerException if the constant state is not set 516 mDrawableContainer.getMinimumWidth(); 517 } 518 519 @Test 520 public void testGetMinimumWidth() { 521 mMockDrawableContainer.setConstantState(mDrawableContainerState); 522 Drawable dr0 = spy(new ColorDrawable(Color.RED)); 523 doReturn(1).when(dr0).getMinimumWidth(); 524 mDrawableContainerState.addChild(dr0); 525 Drawable dr1 = spy(new ColorDrawable(Color.RED)); 526 doReturn(2).when(dr1).getMinimumWidth(); 527 mDrawableContainerState.addChild(dr1); 528 529 // return result of constant state's getConstantMinimumWidth 530 mDrawableContainerState.setConstantSize(true); 531 assertEquals(mDrawableContainerState.getConstantMinimumWidth(), 532 mDrawableContainer.getMinimumWidth()); 533 assertEquals(2, mDrawableContainer.getMinimumWidth()); 534 535 // return default value 536 mDrawableContainerState.setConstantSize(false); 537 assertNull(mDrawableContainer.getCurrent()); 538 assertEquals(0, mDrawableContainer.getMinimumWidth()); 539 540 // return current drawable's getMinimumWidth 541 mDrawableContainer.selectDrawable(0); 542 assertSame(dr0, mDrawableContainer.getCurrent()); 543 assertEquals(1, mDrawableContainer.getMinimumWidth()); 544 } 545 546 @Test(expected=NullPointerException.class) 547 public void testGetMinimumHeightNoConstantState() { 548 // Should throw NullPointerException if the constant state is not set 549 mDrawableContainer.getMinimumHeight(); 550 } 551 552 @Test 553 public void testGetMinimumHeight() { 554 mMockDrawableContainer.setConstantState(mDrawableContainerState); 555 Drawable dr0 = spy(new ColorDrawable(Color.RED)); 556 doReturn(1).when(dr0).getMinimumHeight(); 557 mDrawableContainerState.addChild(dr0); 558 Drawable dr1 = spy(new ColorDrawable(Color.GREEN)); 559 doReturn(2).when(dr1).getMinimumHeight(); 560 mDrawableContainerState.addChild(dr1); 561 562 // return result of constant state's getConstantMinimumHeight 563 mDrawableContainerState.setConstantSize(true); 564 assertEquals(mDrawableContainerState.getConstantMinimumHeight(), 565 mDrawableContainer.getMinimumHeight()); 566 assertEquals(2, mDrawableContainer.getMinimumHeight()); 567 568 // return default value 569 mDrawableContainerState.setConstantSize(false); 570 assertNull(mDrawableContainer.getCurrent()); 571 assertEquals(0, mDrawableContainer.getMinimumHeight()); 572 573 // return current drawable's getMinimumHeight 574 mDrawableContainer.selectDrawable(0); 575 assertSame(dr0, mDrawableContainer.getCurrent()); 576 assertEquals(1, mDrawableContainer.getMinimumHeight()); 577 } 578 579 @Test 580 public void testInvalidateDrawable() { 581 mDrawableContainer.setCallback(null); 582 mDrawableContainer.invalidateDrawable(mDrawableContainer); 583 mDrawableContainer.invalidateDrawable(null); 584 585 Drawable.Callback callback = mock(Drawable.Callback.class); 586 mDrawableContainer.setCallback(callback); 587 588 mDrawableContainer.invalidateDrawable(mDrawableContainer); 589 verify(callback, never()).invalidateDrawable(any()); 590 591 // the callback method can be called if the drawable passed in and the 592 // current drawable are both null 593 mDrawableContainer.invalidateDrawable(null); 594 verify(callback, times(1)).invalidateDrawable(any()); 595 596 mMockDrawableContainer.setConstantState(mDrawableContainerState); 597 MockDrawable mockDrawable = new MockDrawable(); 598 addAndSelectDrawable(mockDrawable); 599 600 reset(callback); 601 mDrawableContainer.invalidateDrawable(mDrawableContainer); 602 verify(callback, never()).invalidateDrawable(any()); 603 604 mDrawableContainer.invalidateDrawable(null); 605 verify(callback, never()).invalidateDrawable(any()); 606 607 // Call the callback method if the drawable is selected. 608 mDrawableContainer.invalidateDrawable(mockDrawable); 609 verify(callback, times(1)).invalidateDrawable(any()); 610 } 611 612 @Test 613 public void testScheduleDrawable() { 614 mDrawableContainer.setCallback(null); 615 mDrawableContainer.scheduleDrawable(mDrawableContainer, null, 0); 616 mDrawableContainer.scheduleDrawable(null, () -> {}, 0); 617 618 Drawable.Callback callback = mock(Drawable.Callback.class); 619 mDrawableContainer.setCallback(callback); 620 621 mDrawableContainer.scheduleDrawable(mDrawableContainer, null, 0); 622 verify(callback, never()).scheduleDrawable(any(), any(), anyLong()); 623 624 // the callback method can be called if the drawable passed in and the 625 // current drawble are both null 626 mDrawableContainer.scheduleDrawable(null, () -> {}, 0); 627 verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong()); 628 629 mMockDrawableContainer.setConstantState(mDrawableContainerState); 630 MockDrawable mockDrawable = new MockDrawable(); 631 addAndSelectDrawable(mockDrawable); 632 633 reset(callback); 634 mDrawableContainer.scheduleDrawable(mDrawableContainer, null, 0); 635 verify(callback, never()).scheduleDrawable(any(), any(), anyLong()); 636 verify(callback, never()).scheduleDrawable(any(), any(), anyLong()); 637 638 mDrawableContainer.scheduleDrawable(null, () -> {}, 0); 639 verify(callback, never()).scheduleDrawable(any(), any(), anyLong()); 640 641 // Call the callback method if the drawable is selected. 642 mDrawableContainer.scheduleDrawable(mockDrawable, null, 0); 643 verify(callback, times(1)).scheduleDrawable(any(), any(), anyLong()); 644 } 645 646 @Test 647 public void testUnscheduleDrawable() { 648 mDrawableContainer.setCallback(null); 649 mDrawableContainer.unscheduleDrawable(mDrawableContainer, null); 650 mDrawableContainer.unscheduleDrawable(null, () -> {}); 651 652 Drawable.Callback callback = mock(Drawable.Callback.class); 653 mDrawableContainer.setCallback(callback); 654 655 mDrawableContainer.unscheduleDrawable(mDrawableContainer, null); 656 verify(callback, never()).unscheduleDrawable(any(), any()); 657 658 // the callback method can be called if the drawable passed in and the 659 // current drawble are both null 660 mDrawableContainer.unscheduleDrawable(null, () -> {}); 661 verify(callback, times(1)).unscheduleDrawable(any(), any()); 662 663 mMockDrawableContainer.setConstantState(mDrawableContainerState); 664 MockDrawable mockDrawable = new MockDrawable(); 665 addAndSelectDrawable(mockDrawable); 666 667 reset(callback); 668 mDrawableContainer.unscheduleDrawable(mDrawableContainer, null); 669 verify(callback, never()).unscheduleDrawable(any(), any()); 670 671 mDrawableContainer.unscheduleDrawable(null, () -> {}); 672 verify(callback, never()).unscheduleDrawable(any(), any()); 673 674 // Call the callback method if the drawable is selected. 675 mDrawableContainer.unscheduleDrawable(mockDrawable, null); 676 verify(callback, times(1)).unscheduleDrawable(any(), any()); 677 } 678 679 @Test 680 public void testSetVisible() { 681 assertTrue(mDrawableContainer.isVisible()); 682 assertFalse(mDrawableContainer.setVisible(true, false)); 683 assertTrue(mDrawableContainer.setVisible(false, false)); 684 assertFalse(mDrawableContainer.setVisible(false, false)); 685 assertTrue(mDrawableContainer.setVisible(true, false)); 686 687 mMockDrawableContainer.setConstantState(mDrawableContainerState); 688 MockDrawable dr = new MockDrawable(); 689 addAndSelectDrawable(dr); 690 691 // set current drawable's visibility 692 assertTrue(mDrawableContainer.isVisible()); 693 assertTrue(dr.isVisible()); 694 assertTrue(mDrawableContainer.setVisible(false, false)); 695 assertFalse(mDrawableContainer.isVisible()); 696 assertFalse(dr.isVisible()); 697 } 698 699 @Test 700 public void testGetOpacity() { 701 // there is no child, so the container is transparent 702 assertEquals(PixelFormat.TRANSPARENT, mDrawableContainer.getOpacity()); 703 704 mMockDrawableContainer.setConstantState(mDrawableContainerState); 705 Drawable dr0 = spy(new ColorDrawable(Color.GREEN)); 706 doReturn(PixelFormat.OPAQUE).when(dr0).getOpacity(); 707 mDrawableContainerState.addChild(dr0); 708 // no child selected yet 709 assertEquals(PixelFormat.TRANSPARENT, mDrawableContainer.getOpacity()); 710 711 mDrawableContainer.selectDrawable(0); 712 assertEquals(mDrawableContainerState.getOpacity(), mDrawableContainer.getOpacity()); 713 assertEquals(PixelFormat.OPAQUE, mDrawableContainer.getOpacity()); 714 715 Drawable dr1 = spy(new ColorDrawable(Color.RED)); 716 doReturn(PixelFormat.TRANSLUCENT).when(dr1).getOpacity(); 717 mDrawableContainerState.addChild(dr1); 718 719 mDrawableContainer.selectDrawable(1); 720 assertEquals(mDrawableContainerState.getOpacity(), mDrawableContainer.getOpacity()); 721 assertEquals(PixelFormat.TRANSLUCENT, mDrawableContainer.getOpacity()); 722 } 723 724 @Test(expected=NullPointerException.class) 725 public void testSelectDrawableNoConstantState() { 726 // Should throw NullPointerException if the constant state is not set 727 mDrawableContainer.selectDrawable(0); 728 } 729 730 @Test 731 public void testSelectDrawable() { 732 mMockDrawableContainer.setConstantState(mDrawableContainerState); 733 MockDrawable dr0 = new MockDrawable(); 734 dr0.setVisible(false, false); 735 assertFalse(dr0.isVisible()); 736 mDrawableContainerState.addChild(dr0); 737 MockDrawable dr1 = new MockDrawable(); 738 dr1.setVisible(false, false); 739 assertFalse(dr1.isVisible()); 740 mDrawableContainerState.addChild(dr1); 741 742 assertTrue(mDrawableContainer.selectDrawable(0)); 743 assertSame(dr0, mDrawableContainer.getCurrent()); 744 assertTrue(dr0.isVisible()); 745 746 assertFalse(mDrawableContainer.selectDrawable(0)); 747 748 assertTrue(mDrawableContainer.selectDrawable(1)); 749 assertSame(dr1, mDrawableContainer.getCurrent()); 750 assertTrue(dr1.isVisible()); 751 assertFalse(dr0.isVisible()); 752 753 assertFalse(mDrawableContainer.selectDrawable(1)); 754 755 assertTrue(mDrawableContainer.selectDrawable(-1)); 756 assertNull(mDrawableContainer.getCurrent()); 757 assertFalse(dr0.isVisible()); 758 assertFalse(dr1.isVisible()); 759 760 assertTrue(mDrawableContainer.selectDrawable(2)); 761 assertNull(mDrawableContainer.getCurrent()); 762 assertFalse(dr0.isVisible()); 763 assertFalse(dr1.isVisible()); 764 } 765 766 @Test 767 public void testAccessConstantState() { 768 mMockDrawableContainer.setConstantState(mDrawableContainerState); 769 assertSame(mDrawableContainerState, mDrawableContainer.getConstantState()); 770 771 mMockDrawableContainer.setConstantState(null); 772 // Note that we're not using 'expected' on the @Test annotation since we want to 773 // make sure that only this next call is going to throw NPE. 774 try { 775 mDrawableContainer.getConstantState(); 776 fail("Should throw NullPointerException."); 777 } catch (NullPointerException e) { 778 } 779 } 780 781 @Test(expected=NullPointerException.class) 782 public void testMutateNoConstantState() { 783 // Should throw NullPointerException if the constant state is not set 784 mDrawableContainer.mutate(); 785 } 786 787 @Test 788 public void testMutate() { 789 mMockDrawableContainer.setConstantState(mDrawableContainerState); 790 Drawable dr0 = spy(new ColorDrawable(Color.MAGENTA)); 791 mDrawableContainerState.addChild(dr0); 792 mDrawableContainer.mutate(); 793 verify(dr0, atLeastOnce()).mutate(); 794 } 795 796 @Test 797 public void testOpacityChange() { 798 mMockDrawableContainer.setConstantState(mDrawableContainerState); 799 ColorDrawable c1 = new ColorDrawable(Color.RED); 800 ColorDrawable c2 = new ColorDrawable(Color.BLUE); 801 addAndSelectDrawable(c1); 802 addAndSelectDrawable(c2); 803 assertEquals(PixelFormat.OPAQUE, mDrawableContainer.getOpacity()); 804 805 // Changes to the not-current drawable should still refresh. 806 c1.setTint(0x80FF0000); 807 c1.setTintMode(PorterDuff.Mode.SRC); 808 assertEquals(PixelFormat.TRANSLUCENT, mDrawableContainer.getOpacity()); 809 } 810 811 @Test 812 public void testStatefulnessChange() { 813 mMockDrawableContainer.setConstantState(mDrawableContainerState); 814 ColorDrawable c1 = new ColorDrawable(Color.RED); 815 ColorDrawable c2 = new ColorDrawable(Color.BLUE); 816 addAndSelectDrawable(c1); 817 addAndSelectDrawable(c2); 818 assertEquals(false, mDrawableContainer.isStateful()); 819 820 // Changes to the not-current drawable should still refresh. 821 ColorStateList csl = new ColorStateList( 822 new int[][] { { android.R.attr.state_enabled }, { } }, 823 new int[] { Color.RED, Color.BLUE }); 824 c1.setTintList(csl); 825 assertEquals(true, mDrawableContainer.isStateful()); 826 } 827 828 private void addAndSelectDrawable(Drawable drawable) { 829 int pos = mDrawableContainerState.addChild(drawable); 830 mDrawableContainer.selectDrawable(pos); 831 assertSame(drawable, mDrawableContainer.getCurrent()); 832 } 833 834 private class MockDrawableContainer extends DrawableContainer { 835 @Override 836 protected void onBoundsChange(Rect bounds) { 837 super.onBoundsChange(bounds); 838 } 839 840 @Override 841 protected boolean onLevelChange(int level) { 842 return super.onLevelChange(level); 843 } 844 845 @Override 846 protected boolean onStateChange(int[] state) { 847 return super.onStateChange(state); 848 } 849 850 @Override 851 protected void setConstantState(DrawableContainerState state) { 852 super.setConstantState(state); 853 } 854 } 855 856 // Since Mockito can't mock or spy on protected methods, we have a custom extension 857 // of Drawable to track calls to protected methods. This class also has empty implementations 858 // of the base abstract methods. 859 private class MockDrawable extends Drawable { 860 private boolean mHasCalledOnBoundsChanged; 861 private boolean mHasCalledOnStateChanged; 862 private boolean mHasCalledOnLevelChanged; 863 864 @Override 865 public int getOpacity() { 866 return PixelFormat.OPAQUE; 867 } 868 869 @Override 870 public void draw(Canvas canvas) { 871 } 872 873 @Override 874 public void setAlpha(int alpha) { 875 } 876 877 @Override 878 public void setColorFilter(ColorFilter colorFilter) { 879 } 880 881 public boolean hasOnBoundsChangedCalled() { 882 return mHasCalledOnBoundsChanged; 883 } 884 885 public boolean hasOnStateChangedCalled() { 886 return mHasCalledOnStateChanged; 887 } 888 889 public boolean hasOnLevelChangedCalled() { 890 return mHasCalledOnLevelChanged; 891 } 892 893 public void reset() { 894 mHasCalledOnLevelChanged = false; 895 mHasCalledOnStateChanged = false; 896 mHasCalledOnBoundsChanged = false; 897 } 898 899 @Override 900 protected void onBoundsChange(Rect bounds) { 901 super.onBoundsChange(bounds); 902 mHasCalledOnBoundsChanged = true; 903 } 904 905 @Override 906 protected boolean onLevelChange(int level) { 907 boolean result = super.onLevelChange(level); 908 mHasCalledOnLevelChanged = true; 909 return result; 910 } 911 912 @Override 913 protected boolean onStateChange(int[] state) { 914 boolean result = super.onStateChange(state); 915 mHasCalledOnStateChanged = true; 916 return result; 917 } 918 } 919 } 920