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.eq; 27 import static org.mockito.Mockito.mock; 28 import static org.mockito.Mockito.times; 29 import static org.mockito.Mockito.verify; 30 31 import android.content.ContentResolver; 32 import android.content.Context; 33 import android.content.res.Resources; 34 import android.content.res.Resources.Theme; 35 import android.graphics.BitmapFactory; 36 import android.graphics.BlendMode; 37 import android.graphics.Canvas; 38 import android.graphics.ColorFilter; 39 import android.graphics.Insets; 40 import android.graphics.PixelFormat; 41 import android.graphics.PorterDuff; 42 import android.graphics.Rect; 43 import android.graphics.cts.R; 44 import android.graphics.drawable.Drawable; 45 import android.graphics.drawable.Drawable.Callback; 46 import android.net.Uri; 47 import android.util.AttributeSet; 48 import android.util.StateSet; 49 import android.util.TypedValue; 50 import android.util.Xml; 51 import android.view.View; 52 53 import androidx.test.InstrumentationRegistry; 54 import androidx.test.filters.SmallTest; 55 import androidx.test.runner.AndroidJUnit4; 56 57 import org.junit.Before; 58 import org.junit.Test; 59 import org.junit.runner.RunWith; 60 import org.xmlpull.v1.XmlPullParser; 61 import org.xmlpull.v1.XmlPullParserException; 62 63 import java.io.ByteArrayOutputStream; 64 import java.io.File; 65 import java.io.FileInputStream; 66 import java.io.FileOutputStream; 67 import java.io.IOException; 68 import java.io.InputStream; 69 import java.io.OutputStream; 70 71 @SmallTest 72 @RunWith(AndroidJUnit4.class) 73 public class DrawableTest { 74 private Context mContext; 75 private Resources mResources; 76 77 @Before 78 public void setup() { 79 mContext = InstrumentationRegistry.getTargetContext(); 80 mResources = mContext.getResources(); 81 } 82 83 @Test 84 public void testClearColorFilter() { 85 Drawable mockDrawable = new MockDrawable(); 86 mockDrawable.clearColorFilter(); 87 assertNull(mockDrawable.getColorFilter()); 88 89 ColorFilter cf = new ColorFilter(); 90 mockDrawable.setColorFilter(cf); 91 assertEquals(cf, mockDrawable.getColorFilter()); 92 93 mockDrawable.clearColorFilter(); 94 assertNull(mockDrawable.getColorFilter()); 95 } 96 97 @Test 98 public void testCopyBounds() { 99 Drawable mockDrawable = new MockDrawable(); 100 Rect rect1 = mockDrawable.copyBounds(); 101 Rect r1 = new Rect(); 102 mockDrawable.copyBounds(r1); 103 assertEquals(0, rect1.bottom); 104 assertEquals(0, rect1.left); 105 assertEquals(0, rect1.right); 106 assertEquals(0, rect1.top); 107 assertEquals(0, r1.bottom); 108 assertEquals(0, r1.left); 109 assertEquals(0, r1.right); 110 assertEquals(0, r1.top); 111 112 mockDrawable.setBounds(10, 10, 100, 100); 113 Rect rect2 = mockDrawable.copyBounds(); 114 Rect r2 = new Rect(); 115 mockDrawable.copyBounds(r2); 116 assertEquals(100, rect2.bottom); 117 assertEquals(10, rect2.left); 118 assertEquals(100, rect2.right); 119 assertEquals(10, rect2.top); 120 assertEquals(100, r2.bottom); 121 assertEquals(10, r2.left); 122 assertEquals(100, r2.right); 123 assertEquals(10, r2.top); 124 125 mockDrawable.setBounds(new Rect(50, 50, 500, 500)); 126 Rect rect3 = mockDrawable.copyBounds(); 127 Rect r3 = new Rect(); 128 mockDrawable.copyBounds(r3); 129 assertEquals(500, rect3.bottom); 130 assertEquals(50, rect3.left); 131 assertEquals(500, rect3.right); 132 assertEquals(50, rect3.top); 133 assertEquals(500, r3.bottom); 134 assertEquals(50, r3.left); 135 assertEquals(500, r3.right); 136 assertEquals(50, r3.top); 137 138 try { 139 mockDrawable.copyBounds(null); 140 fail("should throw NullPointerException."); 141 } catch (NullPointerException e) { 142 } 143 } 144 145 @Test 146 public void testCreateFromPath() throws IOException { 147 assertNull(Drawable.createFromPath(null)); 148 149 Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + 150 mContext.getPackageName() + R.raw.testimage); 151 assertNull(Drawable.createFromPath(uri.getPath())); 152 153 File imageFile = new File(mContext.getFilesDir(), "tempimage.jpg"); 154 assertTrue(imageFile.createNewFile()); 155 assertTrue(imageFile.exists()); 156 writeSampleImage(imageFile); 157 158 final String path = imageFile.getPath(); 159 Uri u = Uri.parse(path); 160 assertNotNull(Drawable.createFromPath(u.toString())); 161 assertTrue(imageFile.delete()); 162 } 163 164 @Test 165 public void testCreateFromIncomplete() throws IOException { 166 // Create a truncated image file. 167 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 168 byte[] buffer = new byte[1024]; 169 try (InputStream source = mResources.openRawResource(R.raw.testimage)) { 170 for (int len = source.read(buffer); len >= 0; len = source.read(buffer)) { 171 bytes.write(buffer, 0, len); 172 } 173 } 174 175 File imageFile = new File(mContext.getFilesDir(), "tempimage.jpg"); 176 assertTrue(imageFile.createNewFile()); 177 assertTrue(imageFile.exists()); 178 try (OutputStream target = new FileOutputStream(imageFile)) { 179 byte[] byteArray = bytes.toByteArray(); 180 target.write(byteArray, 0, byteArray.length / 2); 181 } 182 183 // Now test various Drawable APIs that should succeed. 184 final String path = imageFile.getPath(); 185 Uri u = Uri.parse(path); 186 assertNotNull(Drawable.createFromPath(u.toString())); 187 188 try (FileInputStream input = new FileInputStream(imageFile)) { 189 assertNotNull(Drawable.createFromStream(input, "")); 190 } 191 192 try (FileInputStream input = new FileInputStream(imageFile)) { 193 assertNotNull(Drawable.createFromResourceStream(mResources, new TypedValue(), 194 input, "")); 195 } 196 197 try (FileInputStream input = new FileInputStream(imageFile)) { 198 assertNotNull(Drawable.createFromResourceStream(mResources, new TypedValue(), 199 input, "", new BitmapFactory.Options())); 200 } 201 202 assertTrue(imageFile.delete()); 203 } 204 205 private void writeSampleImage(File imagefile) throws IOException { 206 try (InputStream source = mResources.openRawResource(R.raw.testimage); 207 OutputStream target = new FileOutputStream(imagefile)) { 208 byte[] buffer = new byte[1024]; 209 for (int len = source.read(buffer); len >= 0; len = source.read(buffer)) { 210 target.write(buffer, 0, len); 211 } 212 } 213 } 214 215 @Test 216 public void testCreateFromStream() throws IOException { 217 FileInputStream inputEmptyStream = null; 218 FileInputStream inputStream = null; 219 File imageFile = null; 220 OutputStream outputEmptyStream = null; 221 222 assertNull(Drawable.createFromStream(null, "test.bmp")); 223 224 File emptyFile = new File(mContext.getFilesDir(), "tempemptyimage.jpg"); 225 226 // write some random data. 227 try { 228 outputEmptyStream = new FileOutputStream(emptyFile); 229 outputEmptyStream.write(10); 230 231 inputEmptyStream = new FileInputStream(emptyFile); 232 assertNull(Drawable.createFromStream(inputEmptyStream, "Sample")); 233 234 imageFile = new File(mContext.getFilesDir(), "tempimage.jpg"); 235 236 writeSampleImage(imageFile); 237 238 inputStream = new FileInputStream(imageFile); 239 assertNotNull(Drawable.createFromStream(inputStream, "Sample")); 240 } finally { 241 if (null != outputEmptyStream) { 242 outputEmptyStream.close(); 243 } 244 if (null != inputEmptyStream) { 245 inputEmptyStream.close(); 246 } 247 if (null != inputStream) { 248 inputStream.close(); 249 } 250 if (emptyFile.exists()) { 251 assertTrue(emptyFile.delete()); 252 } 253 if (imageFile.exists()) { 254 assertTrue(imageFile.delete()); 255 } 256 } 257 } 258 259 private Boolean isClosed = new Boolean(false); 260 261 @Test 262 public void testCreateFromStream2() throws IOException { 263 FileInputStream inputStream = null; 264 File imageFile = null; 265 synchronized (isClosed) { 266 isClosed = false; 267 try { 268 imageFile = new File(mContext.getFilesDir(), "tempimage.jpg"); 269 writeSampleImage(imageFile); 270 271 inputStream = new FileInputStream(imageFile) { 272 @Override 273 public void close() throws IOException { 274 super.close(); 275 isClosed = true; 276 } 277 }; 278 assertNotNull(Drawable.createFromStream(inputStream, "Sample")); 279 } finally { 280 if (null != inputStream) { 281 // verify that the stream was not closed 282 assertFalse(isClosed); 283 inputStream.close(); 284 } 285 if (imageFile.exists()) { 286 assertTrue(imageFile.delete()); 287 } 288 } 289 } 290 } 291 292 @Test 293 public void testCreateFromResourceStream1() throws IOException { 294 FileInputStream inputEmptyStream = null; 295 FileInputStream inputStream = null; 296 File imageFile = null; 297 OutputStream outputEmptyStream = null; 298 299 assertNull(Drawable.createFromResourceStream(null, null, null, "test.bmp")); 300 301 File emptyFile = new File(mContext.getFilesDir(), "tempemptyimage.jpg"); 302 303 // write some random data. 304 try { 305 outputEmptyStream = new FileOutputStream(emptyFile); 306 outputEmptyStream.write(10); 307 308 inputEmptyStream = new FileInputStream(emptyFile); 309 assertNull(Drawable.createFromResourceStream(mResources, null, inputEmptyStream, 310 "Sample")); 311 312 imageFile = new File(mContext.getFilesDir(), "tempimage.jpg"); 313 314 writeSampleImage(imageFile); 315 316 inputStream = new FileInputStream(imageFile); 317 final TypedValue value = new TypedValue(); 318 assertNotNull(Drawable.createFromResourceStream(mResources, value, inputStream, 319 "Sample")); 320 } finally { 321 if (null != outputEmptyStream) { 322 outputEmptyStream.close(); 323 } 324 if (null != inputEmptyStream) { 325 inputEmptyStream.close(); 326 } 327 if (null != inputStream) { 328 inputStream.close(); 329 } 330 if (emptyFile.exists()) { 331 assertTrue(emptyFile.delete()); 332 } 333 if (imageFile.exists()) { 334 assertTrue(imageFile.delete()); 335 } 336 } 337 } 338 339 @Test 340 public void testCreateFromResourceStream2() throws IOException { 341 FileInputStream inputEmptyStream = null; 342 FileInputStream inputStream = null; 343 File imageFile = null; 344 OutputStream outputEmptyStream = null; 345 346 BitmapFactory.Options opt = new BitmapFactory.Options(); 347 opt.inScaled = false; 348 349 assertNull(Drawable.createFromResourceStream(null, null, null, "test.bmp", opt)); 350 351 File emptyFile = new File(mContext.getFilesDir(), "tempemptyimage.jpg"); 352 353 // write some random data. 354 try { 355 outputEmptyStream = new FileOutputStream(emptyFile); 356 outputEmptyStream.write(10); 357 358 inputEmptyStream = new FileInputStream(emptyFile); 359 assertNull(Drawable.createFromResourceStream(mResources, null, inputEmptyStream, 360 "Sample", opt)); 361 362 imageFile = new File(mContext.getFilesDir(), "tempimage.jpg"); 363 364 writeSampleImage(imageFile); 365 366 inputStream = new FileInputStream(imageFile); 367 final TypedValue value = new TypedValue(); 368 assertNotNull(Drawable.createFromResourceStream(mResources, value, inputStream, 369 "Sample", opt)); 370 } finally { 371 if (null != outputEmptyStream) { 372 outputEmptyStream.close(); 373 } 374 if (null != inputEmptyStream) { 375 inputEmptyStream.close(); 376 } 377 if (null != inputStream) { 378 inputStream.close(); 379 } 380 if (emptyFile.exists()) { 381 assertTrue(emptyFile.delete()); 382 } 383 if (imageFile.exists()) { 384 assertTrue(imageFile.delete()); 385 } 386 } 387 } 388 389 @Test 390 public void testImageIntrinsicScaledForDensity() throws IOException { 391 try (InputStream is = mContext.getAssets().open("green-p3.png")) { 392 Drawable drawable = Drawable.createFromStream(is, null); 393 assertNotNull(drawable); 394 395 float density = mContext.getResources().getDisplayMetrics().density; 396 int densityAdjustedSize = Math.round(64 / density); 397 assertEquals(densityAdjustedSize, drawable.getIntrinsicWidth()); 398 assertEquals(densityAdjustedSize, drawable.getIntrinsicHeight()); 399 } 400 } 401 402 @Test 403 public void testImageIntrinsicScaledForDensityWithBitmapOptions() throws IOException { 404 try (InputStream is = mContext.getAssets().open("green-p3.png")) { 405 // Verify that providing BitmapFactory Options provides the same result 406 Drawable drawable = Drawable.createFromResourceStream( 407 null, null, is, null, new BitmapFactory.Options()); 408 assertNotNull(drawable); 409 410 float density = mContext.getResources().getDisplayMetrics().density; 411 int densityAdjustedSize = Math.round(64 / density); 412 assertEquals(densityAdjustedSize, drawable.getIntrinsicWidth()); 413 assertEquals(densityAdjustedSize, drawable.getIntrinsicHeight()); 414 } 415 } 416 417 @Test 418 public void testCreateFromXml() throws XmlPullParserException, IOException { 419 XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable); 420 Drawable drawable = Drawable.createFromXml(mResources, parser); 421 assertNotNull(drawable); 422 423 Drawable expected = mResources.getDrawable(R.drawable.gradientdrawable, null); 424 assertEquals(expected.getIntrinsicWidth(), drawable.getIntrinsicWidth()); 425 assertEquals(expected.getIntrinsicHeight(), drawable.getIntrinsicHeight()); 426 } 427 428 @Test 429 public void testCreateFromXmlThemed() throws XmlPullParserException, IOException { 430 XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable_theme); 431 Theme theme = mResources.newTheme(); 432 theme.applyStyle(R.style.Theme_ThemedDrawableTest, true); 433 Drawable drawable = Drawable.createFromXml(mResources, parser, theme); 434 assertNotNull(drawable); 435 436 Drawable expected = mResources.getDrawable(R.drawable.gradientdrawable_theme, theme); 437 assertEquals(expected.getIntrinsicWidth(), drawable.getIntrinsicWidth()); 438 assertEquals(expected.getIntrinsicHeight(), drawable.getIntrinsicHeight()); 439 } 440 441 @Test 442 public void testCreateFromXmlInner() throws XmlPullParserException, IOException { 443 XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable); 444 while (parser.next() != XmlPullParser.START_TAG) { 445 // ignore event, just seek to first tag 446 } 447 AttributeSet attrs = Xml.asAttributeSet(parser); 448 Drawable drawable = Drawable.createFromXmlInner(mResources, parser, attrs); 449 assertNotNull(drawable); 450 451 Drawable expected = mResources.getDrawable(R.drawable.gradientdrawable, null); 452 assertEquals(expected.getIntrinsicWidth(), drawable.getIntrinsicWidth()); 453 assertEquals(expected.getIntrinsicHeight(), drawable.getIntrinsicHeight()); 454 } 455 456 @Test 457 public void testCreateFromXmlInnerThemed() throws XmlPullParserException, IOException { 458 XmlPullParser parser = mResources.getXml(R.drawable.gradientdrawable_theme); 459 while (parser.next() != XmlPullParser.START_TAG) { 460 // ignore event, just seek to first tag 461 } 462 AttributeSet attrs = Xml.asAttributeSet(parser); 463 Theme theme = mResources.newTheme(); 464 theme.applyStyle(R.style.Theme_ThemedDrawableTest, true); 465 Drawable drawable = Drawable.createFromXmlInner(mResources, parser, attrs, theme); 466 assertNotNull(drawable); 467 468 Drawable expected = mResources.getDrawable(R.drawable.gradientdrawable_theme, theme); 469 assertEquals(expected.getIntrinsicWidth(), drawable.getIntrinsicWidth()); 470 assertEquals(expected.getIntrinsicHeight(), drawable.getIntrinsicHeight()); 471 } 472 473 @Test 474 public void testAccessBounds() { 475 Drawable mockDrawable = new MockDrawable(); 476 mockDrawable.setBounds(0, 0, 100, 100); 477 Rect r = mockDrawable.getBounds(); 478 assertEquals(0, r.left); 479 assertEquals(0, r.top); 480 assertEquals(100, r.bottom); 481 assertEquals(100, r.right); 482 483 mockDrawable.setBounds(new Rect(10, 10, 150, 150)); 484 r = mockDrawable.getBounds(); 485 assertEquals(10, r.left); 486 assertEquals(10, r.top); 487 assertEquals(150, r.bottom); 488 assertEquals(150, r.right); 489 490 try { 491 mockDrawable.setBounds(null); 492 fail("should throw NullPointerException."); 493 } catch (NullPointerException e) { 494 } 495 } 496 497 @Test 498 public void testAccessChangingConfigurations() { 499 Drawable mockDrawable = new MockDrawable(); 500 assertEquals(0, mockDrawable.getChangingConfigurations()); 501 502 mockDrawable.setChangingConfigurations(1); 503 assertEquals(1, mockDrawable.getChangingConfigurations()); 504 505 mockDrawable.setChangingConfigurations(Integer.MAX_VALUE); 506 assertEquals(Integer.MAX_VALUE, mockDrawable.getChangingConfigurations()); 507 508 mockDrawable.setChangingConfigurations(Integer.MIN_VALUE); 509 assertEquals(Integer.MIN_VALUE, mockDrawable.getChangingConfigurations()); 510 } 511 512 @Test 513 public void testGetConstantState() { 514 Drawable mockDrawable = new MockDrawable(); 515 assertNull(mockDrawable.getConstantState()); 516 } 517 518 @Test 519 public void testGetCurrent() { 520 Drawable mockDrawable = new MockDrawable(); 521 assertSame(mockDrawable, mockDrawable.getCurrent()); 522 } 523 524 @Test 525 public void testGetIntrinsicHeight() { 526 Drawable mockDrawable = new MockDrawable(); 527 assertEquals(-1, mockDrawable.getIntrinsicHeight()); 528 } 529 530 @Test 531 public void testGetIntrinsicWidth() { 532 Drawable mockDrawable = new MockDrawable(); 533 assertEquals(-1, mockDrawable.getIntrinsicWidth()); 534 } 535 536 @Test 537 public void testAccessLevel() { 538 Drawable mockDrawable = new MockDrawable(); 539 assertEquals(0, mockDrawable.getLevel()); 540 541 assertFalse(mockDrawable.setLevel(10)); 542 assertEquals(10, mockDrawable.getLevel()); 543 544 assertFalse(mockDrawable.setLevel(20)); 545 assertEquals(20, mockDrawable.getLevel()); 546 547 assertFalse(mockDrawable.setLevel(0)); 548 assertEquals(0, mockDrawable.getLevel()); 549 550 assertFalse(mockDrawable.setLevel(10000)); 551 assertEquals(10000, mockDrawable.getLevel()); 552 } 553 554 @Test 555 public void testGetMinimumHeight() { 556 Drawable mockDrawable = new MockDrawable(); 557 assertEquals(0, mockDrawable.getMinimumHeight()); 558 } 559 560 @Test 561 public void testGetMinimumWidth() { 562 Drawable mockDrawable = new MockDrawable(); 563 assertEquals(0, mockDrawable.getMinimumWidth()); 564 } 565 566 @Test 567 public void testGetPadding() { 568 Drawable mockDrawable = new MockDrawable(); 569 Rect r = new Rect(10, 10, 20, 20); 570 assertFalse(mockDrawable.getPadding(r)); 571 assertEquals(0, r.bottom); 572 assertEquals(0, r.top); 573 assertEquals(0, r.left); 574 assertEquals(0, r.right); 575 576 try { 577 mockDrawable.getPadding(null); 578 fail("should throw NullPointerException."); 579 } catch (NullPointerException e) { 580 } 581 } 582 583 @Test 584 public void testAccessState() { 585 Drawable mockDrawable = new MockDrawable(); 586 assertEquals(StateSet.WILD_CARD, mockDrawable.getState()); 587 588 int[] states = new int[] {1, 2, 3}; 589 assertFalse(mockDrawable.setState(states)); 590 assertEquals(states, mockDrawable.getState()); 591 592 mockDrawable.setState(null); 593 } 594 595 @Test 596 public void testGetTransparentRegion() { 597 Drawable mockDrawable = new MockDrawable(); 598 assertNull(mockDrawable.getTransparentRegion()); 599 } 600 601 @Test 602 public void testInflate() throws XmlPullParserException, IOException { 603 Drawable mockDrawable = new MockDrawable(); 604 605 XmlPullParser parser = mResources.getXml(R.xml.drawable_test); 606 while (parser.next() != XmlPullParser.START_TAG) { 607 // ignore event, just seek to first tag 608 } 609 AttributeSet attrs = Xml.asAttributeSet(parser); 610 611 mockDrawable.inflate(mResources, parser, attrs); 612 // visibility set to false in resource 613 assertFalse(mockDrawable.isVisible()); 614 } 615 616 @Test 617 public void testInvalidateSelf() { 618 Drawable mockDrawable = new MockDrawable(); 619 // if setCallback() is not called, invalidateSelf() would do nothing, 620 // so just call it to check whether it throws exceptions. 621 mockDrawable.invalidateSelf(); 622 623 Drawable.Callback mockCallback = mock(Drawable.Callback.class); 624 mockDrawable.setCallback(mockCallback); 625 mockDrawable.invalidateSelf(); 626 verify(mockCallback, times(1)).invalidateDrawable(mockDrawable); 627 } 628 629 @Test 630 public void testIsStateful() { 631 Drawable mockDrawable = new MockDrawable(); 632 assertFalse(mockDrawable.isStateful()); 633 } 634 635 @Test 636 public void testVisible() { 637 Drawable mockDrawable = new MockDrawable(); 638 assertTrue(mockDrawable.isVisible()); 639 640 assertTrue(mockDrawable.setVisible(false, false)); 641 assertFalse(mockDrawable.isVisible()); 642 643 assertFalse(mockDrawable.setVisible(false, false)); 644 assertFalse(mockDrawable.isVisible()); 645 646 assertTrue(mockDrawable.setVisible(true, false)); 647 assertTrue(mockDrawable.isVisible()); 648 } 649 650 @Test 651 public void testOnBoundsChange() { 652 MockDrawable mockDrawable = new MockDrawable(); 653 654 // No-op in the Drawable superclass. 655 mockDrawable.onBoundsChange(new Rect(0, 0, 10, 10)); 656 } 657 658 @Test 659 public void testOnLevelChange() { 660 MockDrawable mockDrawable = new MockDrawable(); 661 assertFalse(mockDrawable.onLevelChange(0)); 662 } 663 664 @Test 665 public void testOnStateChange() { 666 MockDrawable mockDrawable = new MockDrawable(); 667 assertFalse(mockDrawable.onStateChange(null)); 668 } 669 670 @Test 671 public void testResolveOpacity() { 672 assertEquals(PixelFormat.TRANSLUCENT, 673 Drawable.resolveOpacity(PixelFormat.TRANSLUCENT, PixelFormat.TRANSLUCENT)); 674 assertEquals(PixelFormat.UNKNOWN, 675 Drawable.resolveOpacity(PixelFormat.UNKNOWN, PixelFormat.TRANSLUCENT)); 676 assertEquals(PixelFormat.TRANSLUCENT, 677 Drawable.resolveOpacity(PixelFormat.OPAQUE, PixelFormat.TRANSLUCENT)); 678 assertEquals(PixelFormat.TRANSPARENT, 679 Drawable.resolveOpacity(PixelFormat.OPAQUE, PixelFormat.TRANSPARENT)); 680 assertEquals(PixelFormat.OPAQUE, 681 Drawable.resolveOpacity(PixelFormat.RGB_888, PixelFormat.RGB_565)); 682 } 683 684 @Test 685 public void testScheduleSelf() { 686 Drawable mockDrawable = new MockDrawable(); 687 mockDrawable.scheduleSelf(null, 1000L); 688 689 Runnable runnable = mock(Runnable.class); 690 mockDrawable.scheduleSelf(runnable, 1000L); 691 692 Callback mockCallback = mock(Callback.class); 693 mockDrawable.setCallback(mockCallback); 694 mockDrawable.scheduleSelf(runnable, 1000L); 695 verify(mockCallback).scheduleDrawable(eq(mockDrawable), eq(runnable), eq(1000L)); 696 697 mockDrawable.scheduleSelf(runnable, 0L); 698 verify(mockCallback).scheduleDrawable(eq(mockDrawable), eq(runnable), eq(0L)); 699 700 mockDrawable.scheduleSelf(runnable, -1000L); 701 verify(mockCallback).scheduleDrawable(eq(mockDrawable), eq(runnable), eq(-1000L)); 702 } 703 704 @Test 705 public void testAccessCallback() { 706 Drawable mockDrawable = new MockDrawable(); 707 Callback mockCallback = mock(Callback.class); 708 709 mockDrawable.setCallback(mockCallback); 710 assertEquals(mockCallback, mockDrawable.getCallback()); 711 712 mockDrawable.setCallback(null); 713 assertEquals(null, mockDrawable.getCallback()); 714 } 715 716 @Test 717 public void testSetColorFilter() { 718 Drawable mockDrawable = new MockDrawable(); 719 mockDrawable.setColorFilter(5, PorterDuff.Mode.CLEAR); 720 } 721 722 @Test 723 public void testSetDither() { 724 Drawable mockDrawable = new MockDrawable(); 725 726 // No-op in the Drawable superclass. 727 mockDrawable.setDither(false); 728 } 729 730 @Test 731 public void testSetHotspotBounds() { 732 Drawable mockDrawable = new MockDrawable(); 733 734 // No-op in the Drawable superclass. 735 mockDrawable.setHotspotBounds(10, 15, 100, 150); 736 } 737 738 @Test 739 public void testGetHotspotBounds() { 740 Drawable mockDrawable = new MockDrawable(); 741 742 // No-op in the Drawable superclass. 743 mockDrawable.getHotspotBounds(new Rect()); 744 } 745 746 @Test 747 public void testAccessLayoutDirection() { 748 Drawable mockDrawable = new MockDrawable(); 749 750 mockDrawable.setLayoutDirection(View.LAYOUT_DIRECTION_LTR); 751 assertEquals(View.LAYOUT_DIRECTION_LTR, mockDrawable.getLayoutDirection()); 752 753 mockDrawable.setLayoutDirection(View.LAYOUT_DIRECTION_RTL); 754 assertEquals(View.LAYOUT_DIRECTION_RTL, mockDrawable.getLayoutDirection()); 755 } 756 757 @Test 758 public void testOnLayoutDirectionChanged() { 759 Drawable mockDrawable = new MockDrawable(); 760 761 // No-op in the Drawable superclass. 762 mockDrawable.onLayoutDirectionChanged(View.LAYOUT_DIRECTION_LTR); 763 } 764 765 @Test 766 public void testSetFilterBitmap() { 767 Drawable mockDrawable = new MockDrawable(); 768 769 // No-op in the Drawable superclass. 770 mockDrawable.setFilterBitmap(false); 771 } 772 773 @Test 774 public void testIsFilterBitmap() { 775 Drawable mockDrawable = new MockDrawable(); 776 777 // No-op in the Drawable superclass. 778 mockDrawable.isFilterBitmap(); 779 } 780 781 @Test 782 public void testUnscheduleSelf() { 783 Drawable mockDrawable = new MockDrawable(); 784 Drawable.Callback mockCallback = mock(Drawable.Callback.class); 785 mockDrawable.setCallback(mockCallback); 786 mockDrawable.unscheduleSelf(null); 787 verify(mockCallback, times(1)).unscheduleDrawable(mockDrawable, null); 788 } 789 790 @Test 791 public void testMutate() { 792 Drawable mockDrawable = new MockDrawable(); 793 assertSame(mockDrawable, mockDrawable.mutate()); 794 } 795 796 @Test 797 public void testDefaultOpticalInsetsIsNone() { 798 Drawable mockDrawable = new MockDrawable(); 799 assertEquals(Insets.NONE, mockDrawable.getOpticalInsets()); 800 } 801 802 @Test 803 public void testNoSetTintModeInfiniteLoop() { 804 // Setting a PorterDuff.Mode should delegate to the BlendMode API 805 TestTintDrawable testTintDrawable = new TestTintDrawable(); 806 807 testTintDrawable.setTintMode(PorterDuff.Mode.OVERLAY); 808 assertEquals(2, testTintDrawable.getNumTimesTintModeInvoked()); 809 assertEquals(1, testTintDrawable.getNumTimesBlendModeInvoked()); 810 } 811 812 @Test 813 public void testPorterDuffTintWithUnsupportedBlendMode() { 814 // Setting a BlendMode should delegate to the PorterDuff.Mode API 815 TestTintDrawable testTintDrawable = new TestTintDrawable(); 816 testTintDrawable.setTintBlendMode(BlendMode.LUMINOSITY); 817 // 1 time invoking setTintBlendMode because the default is applied if 818 // there is no equivalent for the luminosity blend mode on older API levels 819 assertEquals(1, testTintDrawable.getNumTimesTintModeInvoked()); 820 assertEquals(2, testTintDrawable.getNumTimesBlendModeInvoked()); 821 } 822 823 @Test 824 public void testPorterDuffTintWithSupportedBlendMode() { 825 TestTintDrawable testTintDrawable = new TestTintDrawable(); 826 testTintDrawable.setTintBlendMode(BlendMode.SRC_OVER); 827 assertEquals(1, testTintDrawable.getNumTimesTintModeInvoked()); 828 assertEquals(2, testTintDrawable.getNumTimesBlendModeInvoked()); 829 } 830 831 @Test 832 public void testBlendModeImplementationInvokedWithBlendMode() { 833 TestBlendModeImplementedDrawable test = new TestBlendModeImplementedDrawable(); 834 835 test.setTintBlendMode(BlendMode.SRC); 836 assertEquals(1, test.getNumTimesBlendModeInvoked()); 837 assertEquals(0, test.getNumTimesTintModeInvoked()); 838 } 839 840 @Test 841 public void testBlendModeImplementationInvokedWithPorterDuffMode() { 842 TestBlendModeImplementedDrawable test = new TestBlendModeImplementedDrawable(); 843 test.setTintMode(PorterDuff.Mode.CLEAR); 844 845 assertEquals(1, test.getNumTimesTintModeInvoked()); 846 assertEquals(1, test.getNumTimesBlendModeInvoked()); 847 } 848 849 @Test 850 public void testPorterDuffImplementationInvokedWithBlendMode() { 851 TestPorterDuffImplementedDrawable test = new TestPorterDuffImplementedDrawable(); 852 test.setTintBlendMode(BlendMode.CLEAR); 853 854 assertEquals(1, test.getNumTimesBlendModeInvoked()); 855 assertEquals(1, test.getNumTimesTintModeInvoked()); 856 } 857 858 @Test 859 public void testPorterDuffImplementationInvokedWithPorterDuffMode() { 860 TestPorterDuffImplementedDrawable test = new TestPorterDuffImplementedDrawable(); 861 test.setTintMode(PorterDuff.Mode.CLEAR); 862 863 assertEquals(1, test.getNumTimesTintModeInvoked()); 864 assertEquals(0, test.getNumTimesBlendModeInvoked()); 865 } 866 867 @Test 868 public void testNullPorterDuffReturnsDefaultBlendMode() { 869 TestNullBlendModeDrawable d = new TestNullBlendModeDrawable(); 870 d.setTintMode((PorterDuff.Mode) null); 871 assertEquals(BlendMode.SRC_IN, d.mode); 872 } 873 874 @Test 875 public void testNullBlendModeReturnsDefaultPorterDuffMode() { 876 TestNullPorterDuffDrawable d = new TestNullPorterDuffDrawable(); 877 d.setTintBlendMode((BlendMode) null); 878 assertEquals(PorterDuff.Mode.SRC_IN, d.mode); 879 } 880 881 // Since Mockito can't mock or spy on protected methods, we have a custom extension 882 // of Drawable to track calls to protected methods. This class also has empty implementations 883 // of the base abstract methods. 884 private static class MockDrawable extends Drawable { 885 private ColorFilter mColorFilter; 886 887 @Override 888 public void draw(Canvas canvas) { 889 } 890 891 @Override 892 public void setAlpha(int alpha) { 893 } 894 895 @Override 896 public void setColorFilter(ColorFilter cf) { 897 mColorFilter = cf; 898 } 899 900 @Override 901 public ColorFilter getColorFilter() { 902 return mColorFilter; 903 } 904 905 @Override 906 public int getOpacity() { 907 return PixelFormat.OPAQUE; 908 } 909 910 protected void onBoundsChange(Rect bounds) { 911 super.onBoundsChange(bounds); 912 } 913 914 protected boolean onLevelChange(int level) { 915 return super.onLevelChange(level); 916 } 917 918 protected boolean onStateChange(int[] state) { 919 return super.onStateChange(state); 920 } 921 } 922 923 private static class TestTintDrawable extends Drawable { 924 925 private int mSetTintModeInvoked = 0; 926 private int mSetBlendModeInvoked = 0; 927 928 @Override 929 public void draw(Canvas canvas) { 930 931 } 932 933 @Override 934 public void setAlpha(int alpha) { 935 936 } 937 938 @Override 939 public void setColorFilter(ColorFilter colorFilter) { 940 941 } 942 943 @Override 944 public int getOpacity() { 945 return 0; 946 } 947 948 @Override 949 public void setTintMode(PorterDuff.Mode tintMode) { 950 mSetTintModeInvoked++; 951 super.setTintMode(tintMode); 952 } 953 954 @Override 955 public void setTintBlendMode(BlendMode blendMode) { 956 mSetBlendModeInvoked++; 957 super.setTintBlendMode(blendMode); 958 } 959 960 public int getNumTimesTintModeInvoked() { 961 return mSetTintModeInvoked; 962 } 963 964 public int getNumTimesBlendModeInvoked() { 965 return mSetBlendModeInvoked; 966 } 967 } 968 969 private static class TestNullPorterDuffDrawable extends Drawable { 970 971 public PorterDuff.Mode mode; 972 973 @Override 974 public void draw(Canvas canvas) { 975 976 } 977 978 @Override 979 public void setAlpha(int alpha) { 980 981 } 982 983 @Override 984 public void setColorFilter(ColorFilter colorFilter) { 985 986 } 987 988 @Override 989 public void setTintMode(PorterDuff.Mode tintMode) { 990 mode = tintMode; 991 } 992 993 @Override 994 public int getOpacity() { 995 return 0; 996 } 997 } 998 999 private static class TestNullBlendModeDrawable extends Drawable { 1000 1001 public BlendMode mode; 1002 1003 @Override 1004 public void draw(Canvas canvas) { 1005 1006 } 1007 1008 @Override 1009 public void setAlpha(int alpha) { 1010 1011 } 1012 1013 @Override 1014 public void setColorFilter(ColorFilter colorFilter) { 1015 1016 } 1017 1018 @Override 1019 public void setTintBlendMode(BlendMode blendMode) { 1020 mode = blendMode; 1021 } 1022 1023 @Override 1024 public int getOpacity() { 1025 return 0; 1026 } 1027 } 1028 1029 private static class TestBlendModeImplementedDrawable extends Drawable { 1030 1031 private int mSetTintModeInvoked = 0; 1032 private int mSetBlendModeInvoked = 0; 1033 1034 @Override 1035 public void draw(Canvas canvas) { 1036 1037 } 1038 1039 @Override 1040 public void setAlpha(int alpha) { 1041 1042 } 1043 1044 @Override 1045 public void setColorFilter(ColorFilter colorFilter) { 1046 1047 } 1048 1049 @Override 1050 public int getOpacity() { 1051 return 0; 1052 } 1053 1054 @Override 1055 public void setTintMode(PorterDuff.Mode tintMode) { 1056 mSetTintModeInvoked++; 1057 super.setTintMode(tintMode); 1058 } 1059 1060 @Override 1061 public void setTintBlendMode(BlendMode blendMode) { 1062 // Intentionally not delegating to super class implementation 1063 mSetBlendModeInvoked++; 1064 } 1065 1066 public int getNumTimesTintModeInvoked() { 1067 return mSetTintModeInvoked; 1068 } 1069 1070 public int getNumTimesBlendModeInvoked() { 1071 return mSetBlendModeInvoked; 1072 } 1073 } 1074 1075 private static class TestPorterDuffImplementedDrawable extends Drawable { 1076 1077 private int mSetTintModeInvoked = 0; 1078 private int mSetBlendModeInvoked = 0; 1079 1080 @Override 1081 public void draw(Canvas canvas) { 1082 1083 } 1084 1085 @Override 1086 public void setAlpha(int alpha) { 1087 1088 } 1089 1090 @Override 1091 public void setColorFilter(ColorFilter colorFilter) { 1092 1093 } 1094 1095 @Override 1096 public int getOpacity() { 1097 return 0; 1098 } 1099 1100 @Override 1101 public void setTintMode(PorterDuff.Mode tintMode) { 1102 // Intentionally not delegating to super class implementation 1103 mSetTintModeInvoked++; 1104 } 1105 1106 @Override 1107 public void setTintBlendMode(BlendMode blendMode) { 1108 mSetBlendModeInvoked++; 1109 super.setTintBlendMode(blendMode); 1110 } 1111 1112 public int getNumTimesTintModeInvoked() { 1113 return mSetTintModeInvoked; 1114 } 1115 1116 public int getNumTimesBlendModeInvoked() { 1117 return mSetBlendModeInvoked; 1118 } 1119 } 1120 } 1121