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.graphics.R; 20 21 import org.xmlpull.v1.XmlPullParser; 22 import org.xmlpull.v1.XmlPullParserException; 23 24 import android.content.res.ColorStateList; 25 import android.content.res.Resources; 26 import android.content.res.XmlResourceParser; 27 import android.graphics.Bitmap; 28 import android.graphics.BitmapFactory; 29 import android.graphics.Canvas; 30 import android.graphics.Color; 31 import android.graphics.ColorFilter; 32 import android.graphics.NinePatch; 33 import android.graphics.Paint; 34 import android.graphics.PixelFormat; 35 import android.graphics.Rect; 36 import android.graphics.Region; 37 import android.graphics.Bitmap.Config; 38 import android.graphics.PorterDuff.Mode; 39 import android.graphics.drawable.NinePatchDrawable; 40 import android.graphics.drawable.ShapeDrawable; 41 import android.graphics.drawable.Drawable.ConstantState; 42 import android.graphics.drawable.shapes.RectShape; 43 import android.test.InstrumentationTestCase; 44 import android.util.AttributeSet; 45 import android.util.Xml; 46 47 import java.io.IOException; 48 49 public class NinePatchDrawableTest extends InstrumentationTestCase { 50 private static final int MIN_CHUNK_SIZE = 32; 51 52 private NinePatchDrawable mNinePatchDrawable; 53 54 private Resources mResources; 55 56 @Override 57 protected void setUp() throws Exception { 58 super.setUp(); 59 mResources = getInstrumentation().getTargetContext().getResources(); 60 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_0); 61 } 62 63 @SuppressWarnings("deprecation") 64 public void testConstructors() { 65 byte[] chunk = new byte[MIN_CHUNK_SIZE]; 66 chunk[MIN_CHUNK_SIZE - 1] = 1; 67 68 Rect r = new Rect(); 69 70 Bitmap bmp = BitmapFactory.decodeResource(mResources, R.drawable.ninepatch_0); 71 String name = mResources.getResourceName(R.drawable.ninepatch_0); 72 73 new NinePatchDrawable(bmp, chunk, r, name); 74 75 new NinePatchDrawable(new NinePatch(bmp, chunk, name)); 76 77 chunk = new byte[MIN_CHUNK_SIZE - 1]; 78 chunk[MIN_CHUNK_SIZE - 2] = 1; 79 try { 80 new NinePatchDrawable(bmp, chunk, r, name); 81 fail("The constructor should check whether the chunk is illegal."); 82 } catch (RuntimeException e) { 83 // This exception is thrown by native method. 84 } 85 } 86 87 public void testDraw() { 88 Bitmap bmp = Bitmap.createBitmap(9, 9, Config.ARGB_8888); 89 Canvas c = new Canvas(bmp); 90 91 int ocean = Color.rgb(0, 0xFF, 0x80); 92 93 mNinePatchDrawable.setBounds(0, 0, 9, 9); 94 mNinePatchDrawable.draw(c); 95 assertColorFillRect(bmp, 0, 0, 4, 4, Color.RED); 96 assertColorFillRect(bmp, 5, 0, 4, 4, Color.BLUE); 97 assertColorFillRect(bmp, 0, 5, 4, 4, ocean); 98 assertColorFillRect(bmp, 5, 5, 4, 4, Color.YELLOW); 99 assertColorFillRect(bmp, 4, 0, 1, 9, Color.WHITE); 100 assertColorFillRect(bmp, 0, 4, 9, 1, Color.WHITE); 101 102 bmp.eraseColor(0xff000000); 103 104 mNinePatchDrawable.setBounds(0, 0, 3, 3); 105 mNinePatchDrawable.draw(c); 106 assertColorFillRect(bmp, 0, 0, 1, 1, Color.RED); 107 assertColorFillRect(bmp, 2, 0, 1, 1, Color.BLUE); 108 assertColorFillRect(bmp, 0, 2, 1, 1, ocean); 109 assertColorFillRect(bmp, 2, 2, 1, 1, Color.YELLOW); 110 assertColorFillRect(bmp, 1, 0, 1, 3, Color.WHITE); 111 assertColorFillRect(bmp, 0, 1, 3, 1, Color.WHITE); 112 113 try { 114 mNinePatchDrawable.draw(null); 115 fail("The method should check whether the canvas is null."); 116 } catch (NullPointerException e) { 117 // expected 118 } 119 } 120 121 public void testGetChangingConfigurations() { 122 ConstantState constantState = mNinePatchDrawable.getConstantState(); 123 124 // default 125 assertEquals(0, constantState.getChangingConfigurations()); 126 assertEquals(0, mNinePatchDrawable.getChangingConfigurations()); 127 128 // change the drawable's configuration does not affect the state's configuration 129 mNinePatchDrawable.setChangingConfigurations(0xff); 130 assertEquals(0xff, mNinePatchDrawable.getChangingConfigurations()); 131 assertEquals(0, constantState.getChangingConfigurations()); 132 133 // the state's configuration get refreshed 134 constantState = mNinePatchDrawable.getConstantState(); 135 assertEquals(0xff, constantState.getChangingConfigurations()); 136 137 // set a new configuration to drawable 138 mNinePatchDrawable.setChangingConfigurations(0xff00); 139 assertEquals(0xff, constantState.getChangingConfigurations()); 140 assertEquals(0xffff, mNinePatchDrawable.getChangingConfigurations()); 141 } 142 143 public void testGetPadding() { 144 Rect r = new Rect(); 145 NinePatchDrawable npd = (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatch_0); 146 assertTrue(npd.getPadding(r)); 147 // exact padding unknown due to possible density scaling 148 assertEquals(0, r.left); 149 assertEquals(0, r.top); 150 assertTrue(r.right > 0); 151 assertTrue(r.bottom > 0); 152 153 npd = (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatch_1); 154 assertTrue(npd.getPadding(r)); 155 assertTrue(r.left > 0); 156 assertTrue(r.top > 0); 157 assertTrue(r.right > 0); 158 assertTrue(r.bottom > 0); 159 } 160 161 public void testSetAlpha() { 162 assertEquals(0xff, mNinePatchDrawable.getPaint().getAlpha()); 163 164 mNinePatchDrawable.setAlpha(0); 165 assertEquals(0, mNinePatchDrawable.getPaint().getAlpha()); 166 167 mNinePatchDrawable.setAlpha(-1); 168 assertEquals(0xff, mNinePatchDrawable.getPaint().getAlpha()); 169 170 mNinePatchDrawable.setAlpha(0xfffe); 171 assertEquals(0xfe, mNinePatchDrawable.getPaint().getAlpha()); 172 } 173 174 public void testSetColorFilter() { 175 assertNull(mNinePatchDrawable.getPaint().getColorFilter()); 176 177 MockColorFilter cf = new MockColorFilter(); 178 mNinePatchDrawable.setColorFilter(cf); 179 assertSame(cf, mNinePatchDrawable.getPaint().getColorFilter()); 180 181 mNinePatchDrawable.setColorFilter(null); 182 assertNull(mNinePatchDrawable.getPaint().getColorFilter()); 183 } 184 185 public void testSetTint() { 186 mNinePatchDrawable.setTint(Color.BLACK); 187 mNinePatchDrawable.setTintMode(Mode.SRC_OVER); 188 assertEquals("Nine-patch is tinted", Color.BLACK, 189 DrawableTestingUtils.getPixel(mNinePatchDrawable, 0, 0)); 190 191 mNinePatchDrawable.setTintList(null); 192 mNinePatchDrawable.setTintMode(null); 193 } 194 195 public void testSetDither() { 196 mNinePatchDrawable.setDither(false); 197 assertFalse(mNinePatchDrawable.getPaint().isDither()); 198 199 mNinePatchDrawable.setDither(true); 200 assertTrue(mNinePatchDrawable.getPaint().isDither()); 201 } 202 203 public void testGetPaint() { 204 Paint paint = mNinePatchDrawable.getPaint(); 205 assertNotNull(paint); 206 207 assertSame(paint, mNinePatchDrawable.getPaint()); 208 } 209 210 public void testGetIntrinsicWidth() { 211 Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0); 212 assertEquals(bmp.getWidth(), mNinePatchDrawable.getIntrinsicWidth()); 213 assertEquals(5, mNinePatchDrawable.getIntrinsicWidth()); 214 215 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 216 bmp = getBitmapUnscaled(R.drawable.ninepatch_1); 217 assertEquals(bmp.getWidth(), mNinePatchDrawable.getIntrinsicWidth()); 218 assertEquals(9, mNinePatchDrawable.getIntrinsicWidth()); 219 } 220 221 public void testGetMinimumWidth() { 222 Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0); 223 assertEquals(bmp.getWidth(), mNinePatchDrawable.getMinimumWidth()); 224 assertEquals(5, mNinePatchDrawable.getMinimumWidth()); 225 226 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 227 bmp = getBitmapUnscaled(R.drawable.ninepatch_1); 228 assertEquals(bmp.getWidth(), mNinePatchDrawable.getMinimumWidth()); 229 assertEquals(9, mNinePatchDrawable.getMinimumWidth()); 230 } 231 232 public void testGetIntrinsicHeight() { 233 Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0); 234 assertEquals(bmp.getHeight(), mNinePatchDrawable.getIntrinsicHeight()); 235 assertEquals(5, mNinePatchDrawable.getIntrinsicHeight()); 236 237 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 238 bmp = getBitmapUnscaled(R.drawable.ninepatch_1); 239 assertEquals(bmp.getHeight(), mNinePatchDrawable.getIntrinsicHeight()); 240 assertEquals(9, mNinePatchDrawable.getIntrinsicHeight()); 241 } 242 243 public void testGetMinimumHeight() { 244 Bitmap bmp = getBitmapUnscaled(R.drawable.ninepatch_0); 245 assertEquals(bmp.getHeight(), mNinePatchDrawable.getMinimumHeight()); 246 assertEquals(5, mNinePatchDrawable.getMinimumHeight()); 247 248 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 249 bmp = getBitmapUnscaled(R.drawable.ninepatch_1); 250 assertEquals(bmp.getHeight(), mNinePatchDrawable.getMinimumHeight()); 251 assertEquals(9, mNinePatchDrawable.getMinimumHeight()); 252 } 253 254 // Known failure: Bug 2834281 - Bitmap#hasAlpha seems to return true for 255 // images without alpha 256 public void suppress_testGetOpacity() { 257 assertEquals(PixelFormat.OPAQUE, mNinePatchDrawable.getOpacity()); 258 259 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 260 assertEquals(PixelFormat.TRANSLUCENT, mNinePatchDrawable.getOpacity()); 261 } 262 263 public void testGetTransparentRegion() { 264 // opaque image 265 Region r = mNinePatchDrawable.getTransparentRegion(); 266 assertNull(r); 267 268 mNinePatchDrawable.setBounds(0, 0, 7, 7); 269 r = mNinePatchDrawable.getTransparentRegion(); 270 assertNull(r); 271 272 // translucent image 273 mNinePatchDrawable = getNinePatchDrawable(R.drawable.ninepatch_1); 274 r = mNinePatchDrawable.getTransparentRegion(); 275 assertNull(r); 276 277 mNinePatchDrawable.setBounds(1, 1, 7, 7); 278 r = mNinePatchDrawable.getTransparentRegion(); 279 assertNotNull(r); 280 assertEquals(new Rect(1, 1, 7, 7), r.getBounds()); 281 } 282 283 public void testGetConstantState() { 284 assertNotNull(mNinePatchDrawable.getConstantState()); 285 286 ConstantState constantState = mNinePatchDrawable.getConstantState(); 287 // change the drawable's configuration does not affect the state's configuration 288 mNinePatchDrawable.setChangingConfigurations(0xff); 289 assertEquals(0, constantState.getChangingConfigurations()); 290 // the state's configuration refreshed when getConstantState is called. 291 constantState = mNinePatchDrawable.getConstantState(); 292 assertEquals(0xff, constantState.getChangingConfigurations()); 293 } 294 295 public void testInflate() throws XmlPullParserException, IOException { 296 final int width = 80; 297 final int height = 120; 298 final int[] COLOR = new int[width * height]; 299 Bitmap bitmap = Bitmap.createBitmap(COLOR, width, height, Bitmap.Config.RGB_565); 300 NinePatchDrawable ninePatchDrawable = 301 new NinePatchDrawable(mResources, bitmap, new byte[1000], null, "TESTNAME"); 302 303 assertEquals(height, ninePatchDrawable.getIntrinsicHeight()); 304 assertEquals(width, ninePatchDrawable.getIntrinsicWidth()); 305 XmlResourceParser parser = mResources.getXml(R.drawable.ninepatchdrawable); 306 int type; 307 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 308 && type != XmlPullParser.START_TAG) { 309 } 310 AttributeSet attrs = Xml.asAttributeSet(parser); 311 ninePatchDrawable.inflate(mResources, parser, attrs); 312 313 assertTrue(ninePatchDrawable.getPaint().isDither()); 314 assertTrue(height != ninePatchDrawable.getIntrinsicHeight()); 315 assertTrue(width != ninePatchDrawable.getIntrinsicWidth()); 316 } 317 318 public void testMutate() { 319 NinePatchDrawable d1 = 320 (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatchdrawable); 321 NinePatchDrawable d2 = 322 (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatchdrawable); 323 NinePatchDrawable d3 = 324 (NinePatchDrawable) mResources.getDrawable(R.drawable.ninepatchdrawable); 325 326 // the state is not shared before mutate. 327 d1.setDither(false); 328 assertFalse(d1.getPaint().isDither()); 329 assertTrue(d2.getPaint().isDither()); 330 assertTrue(d3.getPaint().isDither()); 331 332 // cannot test if mutate worked, since state was not shared before 333 d1.mutate(); 334 } 335 336 private void assertColorFillRect(Bitmap bmp, int x, int y, int w, int h, int color) { 337 for (int i = x; i < x + w; i++) { 338 for (int j = y; j < y + h; j++) { 339 assertEquals(color, bmp.getPixel(i, j)); 340 } 341 } 342 } 343 344 private NinePatchDrawable getNinePatchDrawable(int resId) { 345 // jump through hoops to avoid scaling the tiny ninepatch, which would skew the results 346 // depending on device density 347 Bitmap bitmap = getBitmapUnscaled(resId); 348 NinePatch np = new NinePatch(bitmap, bitmap.getNinePatchChunk(), null); 349 return new NinePatchDrawable(mResources, np); 350 } 351 352 private Bitmap getBitmapUnscaled(int resId) { 353 BitmapFactory.Options opts = new BitmapFactory.Options(); 354 opts.inDensity = opts.inTargetDensity = mResources.getDisplayMetrics().densityDpi; 355 Bitmap bitmap = BitmapFactory.decodeResource(mResources, resId, opts); 356 return bitmap; 357 } 358 359 private class MockColorFilter extends ColorFilter { 360 } 361 } 362