NinePatchDrawable.java revision a426445dfdab43886dd894f2ba8a1d55bfcbb278
1/* 2 * Copyright (C) 2006 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 17package android.graphics.drawable; 18 19import android.annotation.NonNull; 20import android.content.res.ColorStateList; 21import android.content.res.Resources; 22import android.content.res.Resources.Theme; 23import android.content.res.TypedArray; 24import android.graphics.Bitmap; 25import android.graphics.BitmapFactory; 26import android.graphics.Canvas; 27import android.graphics.ColorFilter; 28import android.graphics.Insets; 29import android.graphics.NinePatch; 30import android.graphics.Outline; 31import android.graphics.Paint; 32import android.graphics.PixelFormat; 33import android.graphics.PorterDuff; 34import android.graphics.PorterDuff.Mode; 35import android.graphics.PorterDuffColorFilter; 36import android.graphics.Rect; 37import android.graphics.Region; 38import android.util.AttributeSet; 39import android.util.DisplayMetrics; 40import android.util.LayoutDirection; 41import android.util.TypedValue; 42 43import com.android.internal.R; 44 45import org.xmlpull.v1.XmlPullParser; 46import org.xmlpull.v1.XmlPullParserException; 47 48import java.io.IOException; 49import java.io.InputStream; 50 51/** 52 * 53 * A resizeable bitmap, with stretchable areas that you define. This type of image 54 * is defined in a .png file with a special format. 55 * 56 * <div class="special reference"> 57 * <h3>Developer Guides</h3> 58 * <p>For more information about how to use a NinePatchDrawable, read the 59 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch"> 60 * Canvas and Drawables</a> developer guide. For information about creating a NinePatch image 61 * file using the draw9patch tool, see the 62 * <a href="{@docRoot}guide/developing/tools/draw9patch.html">Draw 9-patch</a> tool guide.</p></div> 63 */ 64public class NinePatchDrawable extends Drawable { 65 // dithering helps a lot, and is pretty cheap, so default is true 66 private static final boolean DEFAULT_DITHER = false; 67 private NinePatchState mNinePatchState; 68 private NinePatch mNinePatch; 69 private PorterDuffColorFilter mTintFilter; 70 private Rect mPadding; 71 private Insets mOpticalInsets = Insets.NONE; 72 private Paint mPaint; 73 private boolean mMutated; 74 75 private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; 76 77 // These are scaled to match the target density. 78 private int mBitmapWidth = -1; 79 private int mBitmapHeight = -1; 80 81 NinePatchDrawable() { 82 mNinePatchState = new NinePatchState(); 83 } 84 85 /** 86 * Create drawable from raw nine-patch data, not dealing with density. 87 * @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)} 88 * to ensure that the drawable has correctly set its target density. 89 */ 90 @Deprecated 91 public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) { 92 this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null, null); 93 } 94 95 /** 96 * Create drawable from raw nine-patch data, setting initial target density 97 * based on the display metrics of the resources. 98 */ 99 public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk, 100 Rect padding, String srcName) { 101 this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res, null); 102 mNinePatchState.mTargetDensity = mTargetDensity; 103 } 104 105 /** 106 * Create drawable from raw nine-patch data, setting initial target density 107 * based on the display metrics of the resources. 108 * 109 * @hide 110 */ 111 public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk, 112 Rect padding, Rect opticalInsets, String srcName) { 113 this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets), 114 res, null); 115 mNinePatchState.mTargetDensity = mTargetDensity; 116 } 117 118 /** 119 * Create drawable from existing nine-patch, not dealing with density. 120 * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)} 121 * to ensure that the drawable has correctly set its target density. 122 */ 123 @Deprecated 124 public NinePatchDrawable(NinePatch patch) { 125 this(new NinePatchState(patch, new Rect()), null, null); 126 } 127 128 /** 129 * Create drawable from existing nine-patch, setting initial target density 130 * based on the display metrics of the resources. 131 */ 132 public NinePatchDrawable(Resources res, NinePatch patch) { 133 this(new NinePatchState(patch, new Rect()), res, null); 134 mNinePatchState.mTargetDensity = mTargetDensity; 135 } 136 137 /** 138 * Set the density scale at which this drawable will be rendered. This 139 * method assumes the drawable will be rendered at the same density as the 140 * specified canvas. 141 * 142 * @param canvas The Canvas from which the density scale must be obtained. 143 * 144 * @see android.graphics.Bitmap#setDensity(int) 145 * @see android.graphics.Bitmap#getDensity() 146 */ 147 public void setTargetDensity(Canvas canvas) { 148 setTargetDensity(canvas.getDensity()); 149 } 150 151 /** 152 * Set the density scale at which this drawable will be rendered. 153 * 154 * @param metrics The DisplayMetrics indicating the density scale for this drawable. 155 * 156 * @see android.graphics.Bitmap#setDensity(int) 157 * @see android.graphics.Bitmap#getDensity() 158 */ 159 public void setTargetDensity(DisplayMetrics metrics) { 160 setTargetDensity(metrics.densityDpi); 161 } 162 163 /** 164 * Set the density at which this drawable will be rendered. 165 * 166 * @param density The density scale for this drawable. 167 * 168 * @see android.graphics.Bitmap#setDensity(int) 169 * @see android.graphics.Bitmap#getDensity() 170 */ 171 public void setTargetDensity(int density) { 172 if (density != mTargetDensity) { 173 mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; 174 if (mNinePatch != null) { 175 computeBitmapSize(); 176 } 177 invalidateSelf(); 178 } 179 } 180 181 private static Insets scaleFromDensity(Insets insets, int sdensity, int tdensity) { 182 int left = Bitmap.scaleFromDensity(insets.left, sdensity, tdensity); 183 int top = Bitmap.scaleFromDensity(insets.top, sdensity, tdensity); 184 int right = Bitmap.scaleFromDensity(insets.right, sdensity, tdensity); 185 int bottom = Bitmap.scaleFromDensity(insets.bottom, sdensity, tdensity); 186 return Insets.of(left, top, right, bottom); 187 } 188 189 private void computeBitmapSize() { 190 final int sdensity = mNinePatch.getDensity(); 191 final int tdensity = mTargetDensity; 192 if (sdensity == tdensity) { 193 mBitmapWidth = mNinePatch.getWidth(); 194 mBitmapHeight = mNinePatch.getHeight(); 195 mOpticalInsets = mNinePatchState.mOpticalInsets; 196 } else { 197 mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(), sdensity, tdensity); 198 mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(), sdensity, tdensity); 199 if (mNinePatchState.mPadding != null && mPadding != null) { 200 Rect dest = mPadding; 201 Rect src = mNinePatchState.mPadding; 202 if (dest == src) { 203 mPadding = dest = new Rect(src); 204 } 205 dest.left = Bitmap.scaleFromDensity(src.left, sdensity, tdensity); 206 dest.top = Bitmap.scaleFromDensity(src.top, sdensity, tdensity); 207 dest.right = Bitmap.scaleFromDensity(src.right, sdensity, tdensity); 208 dest.bottom = Bitmap.scaleFromDensity(src.bottom, sdensity, tdensity); 209 } 210 mOpticalInsets = scaleFromDensity(mNinePatchState.mOpticalInsets, sdensity, tdensity); 211 } 212 } 213 214 private void setNinePatch(NinePatch ninePatch) { 215 if (mNinePatch != ninePatch) { 216 mNinePatch = ninePatch; 217 if (ninePatch != null) { 218 computeBitmapSize(); 219 } else { 220 mBitmapWidth = mBitmapHeight = -1; 221 mOpticalInsets = Insets.NONE; 222 } 223 invalidateSelf(); 224 } 225 } 226 227 @Override 228 public void draw(Canvas canvas) { 229 final Rect bounds = getBounds(); 230 231 final boolean clearColorFilter; 232 if (mTintFilter != null && getPaint().getColorFilter() == null) { 233 mPaint.setColorFilter(mTintFilter); 234 clearColorFilter = true; 235 } else { 236 clearColorFilter = false; 237 } 238 239 final boolean needsMirroring = needsMirroring(); 240 if (needsMirroring) { 241 // Mirror the 9patch 242 canvas.translate(bounds.right - bounds.left, 0); 243 canvas.scale(-1.0f, 1.0f); 244 } 245 246 final int restoreAlpha; 247 if (mNinePatchState.mBaseAlpha != 1.0f) { 248 restoreAlpha = mPaint.getAlpha(); 249 mPaint.setAlpha((int) (restoreAlpha * mNinePatchState.mBaseAlpha + 0.5f)); 250 } else { 251 restoreAlpha = -1; 252 } 253 254 mNinePatch.draw(canvas, bounds, mPaint); 255 256 if (clearColorFilter) { 257 mPaint.setColorFilter(null); 258 } 259 260 if (restoreAlpha >= 0) { 261 mPaint.setAlpha(restoreAlpha); 262 } 263 } 264 265 @Override 266 public int getChangingConfigurations() { 267 return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations; 268 } 269 270 @Override 271 public boolean getPadding(Rect padding) { 272 final Rect scaledPadding = mPadding; 273 if (scaledPadding != null) { 274 if (needsMirroring()) { 275 padding.set(scaledPadding.right, scaledPadding.top, 276 scaledPadding.left, scaledPadding.bottom); 277 } else { 278 padding.set(scaledPadding); 279 } 280 return (padding.left | padding.top | padding.right | padding.bottom) != 0; 281 } 282 return false; 283 } 284 285 @Override 286 public void getOutline(@NonNull Outline outline) { 287 final Rect bounds = getBounds(); 288 if (bounds.isEmpty()) return; 289 290 if (mNinePatchState != null) { 291 NinePatch.InsetStruct insets = mNinePatchState.getBitmap().getNinePatchInsets(); 292 if (insets != null) { 293 final Rect outlineInsets = insets.outlineRect; 294 outline.setRoundRect(bounds.left + outlineInsets.left, 295 bounds.top + outlineInsets.top, 296 bounds.right - outlineInsets.right, 297 bounds.bottom - outlineInsets.bottom, 298 insets.outlineRadius); 299 outline.setAlpha(insets.outlineAlpha * (getAlpha() / 255.0f)); 300 return; 301 } 302 } 303 super.getOutline(outline); 304 } 305 306 /** 307 * @hide 308 */ 309 @Override 310 public Insets getOpticalInsets() { 311 if (needsMirroring()) { 312 return Insets.of(mOpticalInsets.right, mOpticalInsets.top, 313 mOpticalInsets.left, mOpticalInsets.bottom); 314 } else { 315 return mOpticalInsets; 316 } 317 } 318 319 @Override 320 public void setAlpha(int alpha) { 321 if (mPaint == null && alpha == 0xFF) { 322 // Fast common case -- leave at normal alpha. 323 return; 324 } 325 getPaint().setAlpha(alpha); 326 invalidateSelf(); 327 } 328 329 @Override 330 public int getAlpha() { 331 if (mPaint == null) { 332 // Fast common case -- normal alpha. 333 return 0xFF; 334 } 335 return getPaint().getAlpha(); 336 } 337 338 @Override 339 public void setColorFilter(ColorFilter cf) { 340 if (mPaint == null && cf == null) { 341 // Fast common case -- leave at no color filter. 342 return; 343 } 344 getPaint().setColorFilter(cf); 345 invalidateSelf(); 346 } 347 348 @Override 349 public void setTintList(ColorStateList tint) { 350 mNinePatchState.mTint = tint; 351 mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode); 352 invalidateSelf(); 353 } 354 355 @Override 356 public void setTintMode(PorterDuff.Mode tintMode) { 357 mNinePatchState.mTintMode = tintMode; 358 mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode); 359 invalidateSelf(); 360 } 361 362 @Override 363 public void setDither(boolean dither) { 364 //noinspection PointlessBooleanExpression 365 if (mPaint == null && dither == DEFAULT_DITHER) { 366 // Fast common case -- leave at default dither. 367 return; 368 } 369 370 getPaint().setDither(dither); 371 invalidateSelf(); 372 } 373 374 @Override 375 public void setAutoMirrored(boolean mirrored) { 376 mNinePatchState.mAutoMirrored = mirrored; 377 } 378 379 private boolean needsMirroring() { 380 return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL; 381 } 382 383 @Override 384 public boolean isAutoMirrored() { 385 return mNinePatchState.mAutoMirrored; 386 } 387 388 @Override 389 public void setFilterBitmap(boolean filter) { 390 getPaint().setFilterBitmap(filter); 391 invalidateSelf(); 392 } 393 394 @Override 395 public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) 396 throws XmlPullParserException, IOException { 397 super.inflate(r, parser, attrs, theme); 398 399 final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.NinePatchDrawable); 400 updateStateFromTypedArray(a); 401 a.recycle(); 402 } 403 404 /** 405 * Updates the constant state from the values in the typed array. 406 */ 407 private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException { 408 final Resources r = a.getResources(); 409 final NinePatchState state = mNinePatchState; 410 411 // Account for any configuration changes. 412 state.mChangingConfigurations |= a.getChangingConfigurations(); 413 414 // Extract the theme attributes, if any. 415 state.mThemeAttrs = a.extractThemeAttrs(); 416 417 state.mDither = a.getBoolean(R.styleable.NinePatchDrawable_dither, state.mDither); 418 419 final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0); 420 if (srcResId != 0) { 421 final BitmapFactory.Options options = new BitmapFactory.Options(); 422 options.inDither = !state.mDither; 423 options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi; 424 425 final Rect padding = new Rect(); 426 final Rect opticalInsets = new Rect(); 427 Bitmap bitmap = null; 428 429 try { 430 final TypedValue value = new TypedValue(); 431 final InputStream is = r.openRawResource(srcResId, value); 432 433 bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options); 434 435 is.close(); 436 } catch (IOException e) { 437 // Ignore 438 } 439 440 if (bitmap == null) { 441 throw new XmlPullParserException(a.getPositionDescription() + 442 ": <nine-patch> requires a valid src attribute"); 443 } else if (bitmap.getNinePatchChunk() == null) { 444 throw new XmlPullParserException(a.getPositionDescription() + 445 ": <nine-patch> requires a valid 9-patch source image"); 446 } 447 448 // Hey, now might be a good time to actually load optical bounds! 449 bitmap.getOpticalInsets(opticalInsets); 450 451 // Sanity check for valid padding when we have optical insets. 452 if (padding.left < opticalInsets.left) { 453 padding.left = opticalInsets.left; 454 padding.right = opticalInsets.right; 455 } 456 if (padding.top < opticalInsets.top) { 457 padding.top = opticalInsets.top; 458 padding.bottom = opticalInsets.bottom; 459 } 460 461 state.mNinePatch = new NinePatch(bitmap, bitmap.getNinePatchChunk()); 462 state.mPadding = padding; 463 state.mOpticalInsets = Insets.of(opticalInsets); 464 } 465 466 state.mAutoMirrored = a.getBoolean( 467 R.styleable.NinePatchDrawable_autoMirrored, state.mAutoMirrored); 468 state.mBaseAlpha = a.getFloat(R.styleable.NinePatchDrawable_alpha, state.mBaseAlpha); 469 470 final int tintMode = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1); 471 if (tintMode != -1) { 472 state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN); 473 } 474 475 final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint); 476 if (tint != null) { 477 state.mTint = tint; 478 } 479 480 // Update local properties. 481 initializeWithState(state, r); 482 483 // Push density applied by setNinePatchState into state. 484 state.mTargetDensity = mTargetDensity; 485 } 486 487 @Override 488 public void applyTheme(Theme t) { 489 super.applyTheme(t); 490 491 final NinePatchState state = mNinePatchState; 492 if (state == null || state.mThemeAttrs == null) { 493 return; 494 } 495 496 final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.NinePatchDrawable); 497 try { 498 updateStateFromTypedArray(a); 499 } catch (XmlPullParserException e) { 500 throw new RuntimeException(e); 501 } finally { 502 a.recycle(); 503 } 504 } 505 506 @Override 507 public boolean canApplyTheme() { 508 return mNinePatchState != null && mNinePatchState.mThemeAttrs != null; 509 } 510 511 public Paint getPaint() { 512 if (mPaint == null) { 513 mPaint = new Paint(); 514 mPaint.setDither(DEFAULT_DITHER); 515 } 516 return mPaint; 517 } 518 519 /** 520 * Retrieves the width of the source .png file (before resizing). 521 */ 522 @Override 523 public int getIntrinsicWidth() { 524 return mBitmapWidth; 525 } 526 527 /** 528 * Retrieves the height of the source .png file (before resizing). 529 */ 530 @Override 531 public int getIntrinsicHeight() { 532 return mBitmapHeight; 533 } 534 535 @Override 536 public int getMinimumWidth() { 537 return mBitmapWidth; 538 } 539 540 @Override 541 public int getMinimumHeight() { 542 return mBitmapHeight; 543 } 544 545 /** 546 * Returns a {@link android.graphics.PixelFormat graphics.PixelFormat} 547 * value of OPAQUE or TRANSLUCENT. 548 */ 549 @Override 550 public int getOpacity() { 551 return mNinePatch.hasAlpha() || (mPaint != null && mPaint.getAlpha() < 255) ? 552 PixelFormat.TRANSLUCENT : PixelFormat.OPAQUE; 553 } 554 555 @Override 556 public Region getTransparentRegion() { 557 return mNinePatch.getTransparentRegion(getBounds()); 558 } 559 560 @Override 561 public ConstantState getConstantState() { 562 mNinePatchState.mChangingConfigurations = getChangingConfigurations(); 563 return mNinePatchState; 564 } 565 566 @Override 567 public Drawable mutate() { 568 if (!mMutated && super.mutate() == this) { 569 mNinePatchState = new NinePatchState(mNinePatchState); 570 mNinePatch = mNinePatchState.mNinePatch; 571 mMutated = true; 572 } 573 return this; 574 } 575 576 @Override 577 protected boolean onStateChange(int[] stateSet) { 578 final NinePatchState state = mNinePatchState; 579 if (state.mTint != null && state.mTintMode != null) { 580 mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); 581 return true; 582 } 583 584 return false; 585 } 586 587 @Override 588 public boolean isStateful() { 589 final NinePatchState s = mNinePatchState; 590 return super.isStateful() || (s.mTint != null && s.mTint.isStateful()); 591 } 592 593 final static class NinePatchState extends ConstantState { 594 // Values loaded during inflation. 595 int[] mThemeAttrs = null; 596 NinePatch mNinePatch = null; 597 ColorStateList mTint = null; 598 Mode mTintMode = Mode.SRC_IN; 599 Rect mPadding = null; 600 Insets mOpticalInsets = Insets.NONE; 601 float mBaseAlpha = 1.0f; 602 boolean mDither = DEFAULT_DITHER; 603 int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; 604 boolean mAutoMirrored = false; 605 606 int mChangingConfigurations; 607 608 NinePatchState() { 609 // Empty constructor. 610 } 611 612 NinePatchState(NinePatch ninePatch, Rect padding) { 613 this(ninePatch, padding, null, DEFAULT_DITHER, false); 614 } 615 616 NinePatchState(NinePatch ninePatch, Rect padding, Rect opticalInsets) { 617 this(ninePatch, padding, opticalInsets, DEFAULT_DITHER, false); 618 } 619 620 NinePatchState(NinePatch ninePatch, Rect padding, Rect opticalInsets, boolean dither, 621 boolean autoMirror) { 622 mNinePatch = ninePatch; 623 mPadding = padding; 624 mOpticalInsets = Insets.of(opticalInsets); 625 mDither = dither; 626 mAutoMirrored = autoMirror; 627 628 // Sanity check for valid padding when we have optical insets. 629 if (mPadding.left < mOpticalInsets.left) { 630 mPadding.left = mOpticalInsets.left; 631 mPadding.right = mOpticalInsets.right; 632 } 633 if (mPadding.top < mOpticalInsets.top) { 634 mPadding.top = mOpticalInsets.top; 635 mPadding.bottom = mOpticalInsets.bottom; 636 } 637 } 638 639 // Copy constructor 640 641 NinePatchState(NinePatchState state) { 642 // We don't deep-copy any fields because they are all immutable. 643 mNinePatch = state.mNinePatch; 644 mTint = state.mTint; 645 mTintMode = state.mTintMode; 646 mThemeAttrs = state.mThemeAttrs; 647 mPadding = state.mPadding; 648 mOpticalInsets = state.mOpticalInsets; 649 mBaseAlpha = state.mBaseAlpha; 650 mDither = state.mDither; 651 mChangingConfigurations = state.mChangingConfigurations; 652 mTargetDensity = state.mTargetDensity; 653 mAutoMirrored = state.mAutoMirrored; 654 } 655 656 @Override 657 public boolean canApplyTheme() { 658 return mThemeAttrs != null; 659 } 660 661 @Override 662 public Bitmap getBitmap() { 663 return mNinePatch.getBitmap(); 664 } 665 666 @Override 667 public Drawable newDrawable() { 668 return new NinePatchDrawable(this, null, null); 669 } 670 671 @Override 672 public Drawable newDrawable(Resources res) { 673 return new NinePatchDrawable(this, res, null); 674 } 675 676 @Override 677 public Drawable newDrawable(Resources res, Theme theme) { 678 return new NinePatchDrawable(this, res, theme); 679 } 680 681 @Override 682 public int getChangingConfigurations() { 683 return mChangingConfigurations; 684 } 685 } 686 687 /** 688 * The one constructor to rule them all. This is called by all public 689 * constructors to set the state and initialize local properties. 690 */ 691 private NinePatchDrawable(NinePatchState state, Resources res, Theme theme) { 692 if (theme != null && state.canApplyTheme()) { 693 // If we need to apply a theme, implicitly mutate. 694 mNinePatchState = new NinePatchState(state); 695 applyTheme(theme); 696 } else { 697 mNinePatchState = state; 698 } 699 700 initializeWithState(state, res); 701 } 702 703 /** 704 * Initializes local dynamic properties from state. 705 */ 706 private void initializeWithState(NinePatchState state, Resources res) { 707 if (res != null) { 708 mTargetDensity = res.getDisplayMetrics().densityDpi; 709 } else { 710 mTargetDensity = state.mTargetDensity; 711 } 712 713 // If we can, avoid calling any methods that initialize Paint. 714 if (state.mDither != DEFAULT_DITHER) { 715 setDither(state.mDither); 716 } 717 718 // Make a local copy of the padding. 719 if (state.mPadding != null) { 720 mPadding = new Rect(state.mPadding); 721 } 722 723 mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); 724 setNinePatch(state.mNinePatch); 725 } 726} 727