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 com.android.cts.stub.R; 20 21 import dalvik.annotation.TestLevel; 22 import dalvik.annotation.TestTargetClass; 23 import dalvik.annotation.TestTargetNew; 24 import dalvik.annotation.TestTargets; 25 import dalvik.annotation.ToBeFixed; 26 27 import org.xmlpull.v1.XmlPullParser; 28 import org.xmlpull.v1.XmlPullParserException; 29 30 import android.content.res.Resources; 31 import android.content.res.XmlResourceParser; 32 import android.graphics.Bitmap; 33 import android.graphics.BitmapFactory; 34 import android.graphics.Canvas; 35 import android.graphics.Color; 36 import android.graphics.ColorFilter; 37 import android.graphics.NinePatch; 38 import android.graphics.Paint; 39 import android.graphics.PixelFormat; 40 import android.graphics.Rect; 41 import android.graphics.Region; 42 import android.graphics.Bitmap.Config; 43 import android.graphics.drawable.NinePatchDrawable; 44 import android.graphics.drawable.Drawable.ConstantState; 45 import android.test.InstrumentationTestCase; 46 import android.util.AttributeSet; 47 import android.util.Xml; 48 49 import java.io.IOException; 50 51 @TestTargetClass(NinePatchDrawable.class) 52 public class NinePatchDrawableTest extends InstrumentationTestCase { 53 private static final int MIN_CHUNK_SIZE = 32; 54 55 private NinePatchDrawable mNinePatchDrawable; 56 57 private Resources mResources; 58 59 @Override setUp()60 protected void setUp() throws Exception { 61 super.setUp(); 62 mResources = getInstrumentation().getTargetContext().getResources(); 63 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_0); 64 } 65 66 @TestTargets({ 67 @TestTargetNew( 68 level = TestLevel.COMPLETE, 69 method = "NinePatchDrawable", 70 args = {Bitmap.class, byte[].class, Rect.class, String.class} 71 ), 72 @TestTargetNew( 73 level = TestLevel.COMPLETE, 74 method = "NinePatchDrawable", 75 args = {android.graphics.NinePatch.class} 76 ) 77 }) 78 @ToBeFixed(bug = "1417734", explanation = "should add @throws clause into javadoc of " 79 + "NinePatchDrawable#NinePatchDrawable(Bitmap, byte[], Rect, String) " 80 + "when param bitmap, chunk, padding or srcName is null") 81 @SuppressWarnings("deprecation") testConstructors()82 public void testConstructors() { 83 byte[] chunk = new byte[MIN_CHUNK_SIZE]; 84 chunk[MIN_CHUNK_SIZE - 1] = 1; 85 86 Rect r = new Rect(); 87 88 Bitmap bmp = BitmapFactory.decodeResource(mResources, R.drawable.ninepatch_0); 89 String name = mResources.getResourceName(R.drawable.ninepatch_0); 90 91 new NinePatchDrawable(bmp, chunk, r, name); 92 93 try { 94 new NinePatchDrawable(null, chunk, r, name); 95 fail("The constructor should check whether the bitmap is null."); 96 } catch (NullPointerException e) { 97 } 98 99 // These codes will crash the test cases though the exceptions are caught. 100 // try { 101 // new NinePatchDrawable(bmp, null, r, name); 102 // fail("The constructor should check whether the chunk is null."); 103 // } catch (Exception e) { 104 // } 105 106 try { 107 mNinePatchDrawable = new NinePatchDrawable(bmp, chunk, null, name); 108 fail("The constructor should not accept null padding."); 109 } catch (NullPointerException e) { 110 } 111 112 try { 113 new NinePatchDrawable(bmp, chunk, r, null); 114 } catch (NullPointerException e) { 115 fail("The constructor should accept null srcname."); 116 } 117 118 new NinePatchDrawable(new NinePatch(bmp, chunk, name)); 119 120 // constructor should accept a null NinePatch 121 mNinePatchDrawable = new NinePatchDrawable(null); 122 123 chunk = new byte[MIN_CHUNK_SIZE - 1]; 124 chunk[MIN_CHUNK_SIZE - 2] = 1; 125 try { 126 new NinePatchDrawable(bmp, chunk, r, name); 127 fail("The constructor should check whether the chunk is illegal."); 128 } catch (RuntimeException e) { 129 // This exception is thrown by native method. 130 } 131 } 132 133 @TestTargetNew( 134 level = TestLevel.COMPLETE, 135 method = "draw", 136 args = {android.graphics.Canvas.class} 137 ) 138 @ToBeFixed(bug = "1417734", explanation = "should add @throws clause into javadoc of " 139 + "NinePatchDrawable#draw(Canvas) when param canvas is null") testDraw()140 public void testDraw() { 141 Bitmap bmp = Bitmap.createBitmap(9, 9, Config.ARGB_8888); 142 Canvas c = new Canvas(bmp); 143 144 int ocean = Color.rgb(0, 0xFF, 0x80); 145 146 mNinePatchDrawable.setBounds(0, 0, 9, 9); 147 mNinePatchDrawable.draw(c); 148 assertColorFillRect(bmp, 0, 0, 4, 4, Color.RED); 149 assertColorFillRect(bmp, 5, 0, 4, 4, Color.BLUE); 150 assertColorFillRect(bmp, 0, 5, 4, 4, ocean); 151 assertColorFillRect(bmp, 5, 5, 4, 4, Color.YELLOW); 152 assertColorFillRect(bmp, 4, 0, 1, 9, Color.WHITE); 153 assertColorFillRect(bmp, 0, 4, 9, 1, Color.WHITE); 154 155 bmp.eraseColor(0xff000000); 156 157 mNinePatchDrawable.setBounds(0, 0, 3, 3); 158 mNinePatchDrawable.draw(c); 159 assertColorFillRect(bmp, 0, 0, 1, 1, Color.RED); 160 assertColorFillRect(bmp, 2, 0, 1, 1, Color.BLUE); 161 assertColorFillRect(bmp, 0, 2, 1, 1, ocean); 162 assertColorFillRect(bmp, 2, 2, 1, 1, Color.YELLOW); 163 assertColorFillRect(bmp, 1, 0, 1, 3, Color.WHITE); 164 assertColorFillRect(bmp, 0, 1, 3, 1, Color.WHITE); 165 166 try { 167 mNinePatchDrawable.draw(null); 168 fail("The method should check whether the canvas is null."); 169 } catch (NullPointerException e) { 170 // expected 171 } 172 } 173 174 @TestTargetNew( 175 level = TestLevel.COMPLETE, 176 method = "getChangingConfigurations", 177 args = {} 178 ) testGetChangingConfigurations()179 public void testGetChangingConfigurations() { 180 ConstantState constantState = mNinePatchDrawable.getConstantState(); 181 182 // default 183 assertEquals(0, constantState.getChangingConfigurations()); 184 assertEquals(0, mNinePatchDrawable.getChangingConfigurations()); 185 186 // change the drawable's configuration does not affect the state's configuration 187 mNinePatchDrawable.setChangingConfigurations(0xff); 188 assertEquals(0xff, mNinePatchDrawable.getChangingConfigurations()); 189 assertEquals(0, constantState.getChangingConfigurations()); 190 191 // the state's configuration get refreshed 192 constantState = mNinePatchDrawable.getConstantState(); 193 assertEquals(0xff, constantState.getChangingConfigurations()); 194 195 // set a new configuration to drawable 196 mNinePatchDrawable.setChangingConfigurations(0xff00); 197 assertEquals(0xff, constantState.getChangingConfigurations()); 198 assertEquals(0xffff, mNinePatchDrawable.getChangingConfigurations()); 199 } 200 201 @TestTargetNew( 202 level = TestLevel.COMPLETE, 203 method = "getPadding", 204 args = {android.graphics.Rect.class} 205 ) 206 @ToBeFixed(bug = "1417734", explanation = "should add @throws clause into javadoc of " 207 + "NinePatchDrawable#getPadding(Rect) when param padding is null or " 208 + "the insternal padding field is not set ") testGetPadding()209 public void testGetPadding() { 210 Rect r = new Rect(); 211 NinePatchDrawable npd = (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatch_0); 212 assertTrue(npd.getPadding(r)); 213 // exact padding unknown due to possible density scaling 214 assertEquals(0, r.left); 215 assertEquals(0, r.top); 216 assertTrue(r.right > 0); 217 assertTrue(r.bottom > 0); 218 219 npd = (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatch_1); 220 assertTrue(npd.getPadding(r)); 221 assertTrue(r.left > 0); 222 assertTrue(r.top > 0); 223 assertTrue(r.right > 0); 224 assertTrue(r.bottom > 0); 225 226 try { 227 // drawable constructed from a bitmap has no padding set 228 mNinePatchDrawable.getPadding(r); 229 fail("The method should check whether the padding field is null."); 230 } catch (NullPointerException e) { 231 // expected 232 } 233 234 // passed in a null rect 235 try { 236 mNinePatchDrawable.getPadding(null); 237 fail("The method should check whether the rect is null."); 238 } catch (NullPointerException e) { 239 // expected 240 } 241 } 242 243 @TestTargetNew( 244 level = TestLevel.COMPLETE, 245 method = "setAlpha", 246 args = {int.class} 247 ) testSetAlpha()248 public void testSetAlpha() { 249 assertEquals(0xff, mNinePatchDrawable.getPaint().getAlpha()); 250 251 mNinePatchDrawable.setAlpha(0); 252 assertEquals(0, mNinePatchDrawable.getPaint().getAlpha()); 253 254 mNinePatchDrawable.setAlpha(-1); 255 assertEquals(0xff, mNinePatchDrawable.getPaint().getAlpha()); 256 257 mNinePatchDrawable.setAlpha(0xfffe); 258 assertEquals(0xfe, mNinePatchDrawable.getPaint().getAlpha()); 259 } 260 261 @TestTargetNew( 262 level = TestLevel.COMPLETE, 263 method = "setColorFilter", 264 args = {android.graphics.ColorFilter.class} 265 ) testSetColorFilter()266 public void testSetColorFilter() { 267 assertNull(mNinePatchDrawable.getPaint().getColorFilter()); 268 269 MockColorFilter cf = new MockColorFilter(); 270 mNinePatchDrawable.setColorFilter(cf); 271 assertSame(cf, mNinePatchDrawable.getPaint().getColorFilter()); 272 273 mNinePatchDrawable.setColorFilter(null); 274 assertNull(mNinePatchDrawable.getPaint().getColorFilter()); 275 } 276 277 @TestTargetNew( 278 level = TestLevel.COMPLETE, 279 method = "setDither", 280 args = {boolean.class} 281 ) testSetDither()282 public void testSetDither() { 283 assertTrue(mNinePatchDrawable.getPaint().isDither()); 284 285 mNinePatchDrawable.setDither(false); 286 assertFalse(mNinePatchDrawable.getPaint().isDither()); 287 288 mNinePatchDrawable.setDither(true); 289 assertTrue(mNinePatchDrawable.getPaint().isDither()); 290 } 291 292 @TestTargetNew( 293 level = TestLevel.COMPLETE, 294 method = "getPaint", 295 args = {} 296 ) testGetPaint()297 public void testGetPaint() { 298 Paint paint = mNinePatchDrawable.getPaint(); 299 assertNotNull(paint); 300 301 assertSame(paint, mNinePatchDrawable.getPaint()); 302 } 303 304 @TestTargetNew( 305 level = TestLevel.COMPLETE, 306 method = "getIntrinsicWidth", 307 args = {} 308 ) testGetIntrinsicWidth()309 public void testGetIntrinsicWidth() { 310 Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0); 311 assertEquals(bmp.getWidth(), mNinePatchDrawable.getIntrinsicWidth()); 312 assertEquals(5, mNinePatchDrawable.getIntrinsicWidth()); 313 314 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 315 bmp = getBitmapUnscaled(R.drawable.ninepatch_1); 316 assertEquals(bmp.getWidth(), mNinePatchDrawable.getIntrinsicWidth()); 317 assertEquals(9, mNinePatchDrawable.getIntrinsicWidth()); 318 } 319 320 @TestTargetNew( 321 level = TestLevel.COMPLETE, 322 method = "getMinimumWidth", 323 args = {} 324 ) testGetMinimumWidth()325 public void testGetMinimumWidth() { 326 Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0); 327 assertEquals(bmp.getWidth(), mNinePatchDrawable.getMinimumWidth()); 328 assertEquals(5, mNinePatchDrawable.getMinimumWidth()); 329 330 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 331 bmp = getBitmapUnscaled(R.drawable.ninepatch_1); 332 assertEquals(bmp.getWidth(), mNinePatchDrawable.getMinimumWidth()); 333 assertEquals(9, mNinePatchDrawable.getMinimumWidth()); 334 } 335 336 @TestTargetNew( 337 level = TestLevel.COMPLETE, 338 method = "getIntrinsicHeight", 339 args = {} 340 ) testGetIntrinsicHeight()341 public void testGetIntrinsicHeight() { 342 Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0); 343 assertEquals(bmp.getHeight(), mNinePatchDrawable.getIntrinsicHeight()); 344 assertEquals(5, mNinePatchDrawable.getIntrinsicHeight()); 345 346 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 347 bmp = getBitmapUnscaled(R.drawable.ninepatch_1); 348 assertEquals(bmp.getHeight(), mNinePatchDrawable.getIntrinsicHeight()); 349 assertEquals(9, mNinePatchDrawable.getIntrinsicHeight()); 350 } 351 352 @TestTargetNew( 353 level = TestLevel.COMPLETE, 354 method = "getMinimumHeight", 355 args = {} 356 ) testGetMinimumHeight()357 public void testGetMinimumHeight() { 358 Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0); 359 assertEquals(bmp.getHeight(), mNinePatchDrawable.getMinimumHeight()); 360 assertEquals(5, mNinePatchDrawable.getMinimumHeight()); 361 362 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 363 bmp = getBitmapUnscaled(R.drawable.ninepatch_1); 364 assertEquals(bmp.getHeight(), mNinePatchDrawable.getMinimumHeight()); 365 assertEquals(9, mNinePatchDrawable.getMinimumHeight()); 366 } 367 368 @TestTargetNew( 369 level = TestLevel.COMPLETE, 370 method = "getOpacity", 371 args = {} 372 ) testGetOpacity()373 public void testGetOpacity() { 374 assertEquals(PixelFormat.OPAQUE, mNinePatchDrawable.getOpacity()); 375 376 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 377 assertEquals(PixelFormat.TRANSLUCENT, mNinePatchDrawable.getOpacity()); 378 } 379 380 @TestTargetNew( 381 level = TestLevel.COMPLETE, 382 method = "getTransparentRegion", 383 args = {} 384 ) testGetTransparentRegion()385 public void testGetTransparentRegion() { 386 // opaque image 387 Region r = mNinePatchDrawable.getTransparentRegion(); 388 assertNull(r); 389 390 mNinePatchDrawable.setBounds(0, 0, 7, 7); 391 r = mNinePatchDrawable.getTransparentRegion(); 392 assertNull(r); 393 394 // translucent image 395 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 396 r = mNinePatchDrawable.getTransparentRegion(); 397 assertNull(r); 398 399 mNinePatchDrawable.setBounds(1, 1, 7, 7); 400 r = mNinePatchDrawable.getTransparentRegion(); 401 assertNotNull(r); 402 assertEquals(new Rect(1, 1, 7, 7), r.getBounds()); 403 } 404 405 @TestTargetNew( 406 level = TestLevel.COMPLETE, 407 method = "getConstantState", 408 args = {} 409 ) testGetConstantState()410 public void testGetConstantState() { 411 assertNotNull(mNinePatchDrawable.getConstantState()); 412 413 ConstantState constantState = mNinePatchDrawable.getConstantState(); 414 // change the drawable's configuration does not affect the state's configuration 415 mNinePatchDrawable.setChangingConfigurations(0xff); 416 assertEquals(0, constantState.getChangingConfigurations()); 417 // the state's configuration refreshed when getConstantState is called. 418 constantState = mNinePatchDrawable.getConstantState(); 419 assertEquals(0xff, constantState.getChangingConfigurations()); 420 } 421 422 @TestTargetNew( 423 level = TestLevel.COMPLETE, 424 method = "inflate", 425 args = {Resources.class, XmlPullParser.class, AttributeSet.class} 426 ) testInflate()427 public void testInflate() throws XmlPullParserException, IOException { 428 final int width = 80; 429 final int height = 120; 430 final int[] COLOR = new int[width * height]; 431 Bitmap bitmap = Bitmap.createBitmap(COLOR, width, height, Bitmap.Config.RGB_565); 432 NinePatchDrawable ninePatchDrawable = 433 new NinePatchDrawable(mResources, bitmap, new byte[1000], null, "TESTNAME"); 434 435 assertEquals(height, ninePatchDrawable.getIntrinsicHeight()); 436 assertEquals(width, ninePatchDrawable.getIntrinsicWidth()); 437 XmlResourceParser parser = mResources.getXml(R.drawable.ninepatchdrawable); 438 int type; 439 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 440 && type != XmlPullParser.START_TAG) { 441 } 442 AttributeSet attrs = Xml.asAttributeSet(parser); 443 ninePatchDrawable.inflate(mResources, parser, attrs); 444 445 assertTrue(ninePatchDrawable.getPaint().isDither()); 446 assertTrue(height != ninePatchDrawable.getIntrinsicHeight()); 447 assertTrue(width != ninePatchDrawable.getIntrinsicWidth()); 448 } 449 450 @TestTargetNew( 451 level = TestLevel.SUFFICIENT, 452 method = "mutate", 453 args = {} 454 ) 455 @ToBeFixed(bug = "", explanation = "mutate() always throw NullPointerException.") testMutate()456 public void testMutate() { 457 NinePatchDrawable d1 = 458 (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatchdrawable); 459 NinePatchDrawable d2 = 460 (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatchdrawable); 461 NinePatchDrawable d3 = 462 (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatchdrawable); 463 464 // the state is not shared before mutate. 465 d1.setDither(false); 466 assertFalse(d1.getPaint().isDither()); 467 assertTrue(d2.getPaint().isDither()); 468 assertTrue(d3.getPaint().isDither()); 469 470 // cannot test if mutate worked, since state was not shared before 471 d1.mutate(); 472 } 473 assertColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color)474 private void assertColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color) { 475 for (int i = x; i < x + w; i++) { 476 for (int j = y; j < y + h; j++) { 477 assertEquals(color, bmp.getPixel(i, j)); 478 } 479 } 480 } 481 getNinePatchDrawable(int resId)482 private NinePatchDrawable getNinePatchDrawable(int resId) { 483 // jump through hoops to avoid scaling the tiny ninepatch, which would skew the results 484 // depending on device density 485 Bitmap bitmap = getBitmapUnscaled(resId); 486 NinePatch np = new NinePatch(bitmap, bitmap.getNinePatchChunk(), null); 487 return new NinePatchDrawable(mResources, np); 488 } 489 getBitmapUnscaled(int resId)490 private Bitmap getBitmapUnscaled(int resId) { 491 BitmapFactory.Options opts = new BitmapFactory.Options(); 492 opts.inDensity = opts.inTargetDensity = mResources.getDisplayMetrics().densityDpi; 493 Bitmap bitmap = BitmapFactory.decodeResource(mResources, resId, opts); 494 return bitmap; 495 } 496 497 private class MockColorFilter extends ColorFilter { 498 } 499 } 500