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 17 package android.graphics.drawable; 18 19 import com.android.internal.R; 20 21 import org.xmlpull.v1.XmlPullParser; 22 import org.xmlpull.v1.XmlPullParserException; 23 24 import android.annotation.AttrRes; 25 import android.annotation.ColorInt; 26 import android.annotation.IntRange; 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.annotation.TestApi; 30 import android.content.pm.ActivityInfo.Config; 31 import android.content.res.ColorStateList; 32 import android.content.res.Resources; 33 import android.content.res.Resources.Theme; 34 import android.content.res.TypedArray; 35 import android.graphics.Bitmap; 36 import android.graphics.BitmapFactory; 37 import android.graphics.Canvas; 38 import android.graphics.Color; 39 import android.graphics.ColorFilter; 40 import android.graphics.Insets; 41 import android.graphics.NinePatch; 42 import android.graphics.Outline; 43 import android.graphics.PixelFormat; 44 import android.graphics.PorterDuff; 45 import android.graphics.PorterDuff.Mode; 46 import android.graphics.PorterDuffColorFilter; 47 import android.graphics.Rect; 48 import android.graphics.Region; 49 import android.graphics.Xfermode; 50 import android.os.Trace; 51 import android.util.AttributeSet; 52 import android.util.DisplayMetrics; 53 import android.util.StateSet; 54 import android.util.TypedValue; 55 import android.util.Xml; 56 import android.view.View; 57 58 import java.io.IOException; 59 import java.io.InputStream; 60 import java.lang.ref.WeakReference; 61 import java.util.Arrays; 62 63 /** 64 * A Drawable is a general abstraction for "something that can be drawn." Most 65 * often you will deal with Drawable as the type of resource retrieved for 66 * drawing things to the screen; the Drawable class provides a generic API for 67 * dealing with an underlying visual resource that may take a variety of forms. 68 * Unlike a {@link android.view.View}, a Drawable does not have any facility to 69 * receive events or otherwise interact with the user. 70 * 71 * <p>In addition to simple drawing, Drawable provides a number of generic 72 * mechanisms for its client to interact with what is being drawn: 73 * 74 * <ul> 75 * <li> The {@link #setBounds} method <var>must</var> be called to tell the 76 * Drawable where it is drawn and how large it should be. All Drawables 77 * should respect the requested size, often simply by scaling their 78 * imagery. A client can find the preferred size for some Drawables with 79 * the {@link #getIntrinsicHeight} and {@link #getIntrinsicWidth} methods. 80 * 81 * <li> The {@link #getPadding} method can return from some Drawables 82 * information about how to frame content that is placed inside of them. 83 * For example, a Drawable that is intended to be the frame for a button 84 * widget would need to return padding that correctly places the label 85 * inside of itself. 86 * 87 * <li> The {@link #setState} method allows the client to tell the Drawable 88 * in which state it is to be drawn, such as "focused", "selected", etc. 89 * Some drawables may modify their imagery based on the selected state. 90 * 91 * <li> The {@link #setLevel} method allows the client to supply a single 92 * continuous controller that can modify the Drawable is displayed, such as 93 * a battery level or progress level. Some drawables may modify their 94 * imagery based on the current level. 95 * 96 * <li> A Drawable can perform animations by calling back to its client 97 * through the {@link Callback} interface. All clients should support this 98 * interface (via {@link #setCallback}) so that animations will work. A 99 * simple way to do this is through the system facilities such as 100 * {@link android.view.View#setBackground(Drawable)} and 101 * {@link android.widget.ImageView}. 102 * </ul> 103 * 104 * Though usually not visible to the application, Drawables may take a variety 105 * of forms: 106 * 107 * <ul> 108 * <li> <b>Bitmap</b>: the simplest Drawable, a PNG or JPEG image. 109 * <li> <b>Nine Patch</b>: an extension to the PNG format allows it to 110 * specify information about how to stretch it and place things inside of 111 * it. 112 * <li><b>Vector</b>: a drawable defined in an XML file as a set of points, 113 * lines, and curves along with its associated color information. This type 114 * of drawable can be scaled without loss of display quality. 115 * <li> <b>Shape</b>: contains simple drawing commands instead of a raw 116 * bitmap, allowing it to resize better in some cases. 117 * <li> <b>Layers</b>: a compound drawable, which draws multiple underlying 118 * drawables on top of each other. 119 * <li> <b>States</b>: a compound drawable that selects one of a set of 120 * drawables based on its state. 121 * <li> <b>Levels</b>: a compound drawable that selects one of a set of 122 * drawables based on its level. 123 * <li> <b>Scale</b>: a compound drawable with a single child drawable, 124 * whose overall size is modified based on the current level. 125 * </ul> 126 * 127 * <a name="Custom"></a> 128 * <h3>Custom drawables</h3> 129 * 130 * <p> 131 * All versions of Android allow the Drawable class to be extended and used at 132 * run time in place of framework-provided drawable classes. Starting in 133 * {@link android.os.Build.VERSION_CODES#N API 24}, custom drawables classes 134 * may also be used in XML. 135 * <p> 136 * <strong>Note:</strong> Custom drawable classes are only accessible from 137 * within your application package. Other applications will not be able to load 138 * them. 139 * <p> 140 * At a minimum, custom drawable classes must implement the abstract methods on 141 * Drawable and should override the {@link Drawable#draw(Canvas)} method to 142 * draw content. 143 * <p> 144 * Custom drawables classes may be used in XML in multiple ways: 145 * <ul> 146 * <li> 147 * Using the fully-qualified class name as the XML element name. For 148 * this method, the custom drawable class must be a public top-level 149 * class. 150 * <pre> 151 * <com.myapp.MyCustomDrawable xmlns:android="http://schemas.android.com/apk/res/android" 152 * android:color="#ffff0000" /> 153 * </pre> 154 * </li> 155 * <li> 156 * Using <em>drawable</em> as the XML element name and specifying the 157 * fully-qualified class name from the <em>class</em> attribute. This 158 * method may be used for both public top-level classes and public 159 * static inner classes. 160 * <pre> 161 * <drawable xmlns:android="http://schemas.android.com/apk/res/android" 162 * class="com.myapp.MyTopLevelClass$InnerCustomDrawable" 163 * android:color="#ffff0000" /> 164 * </pre> 165 * </li> 166 * </ul> 167 * 168 * <div class="special reference"> 169 * <h3>Developer Guides</h3> 170 * <p>For more information about how to use drawables, read the 171 * <a href="{@docRoot}guide/topics/graphics/2d-graphics.html">Canvas and Drawables</a> developer 172 * guide. For information and examples of creating drawable resources (XML or bitmap files that 173 * can be loaded in code), read the 174 * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a> 175 * document.</p></div> 176 */ 177 public abstract class Drawable { 178 private static final Rect ZERO_BOUNDS_RECT = new Rect(); 179 180 static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN; 181 182 private int[] mStateSet = StateSet.WILD_CARD; 183 private int mLevel = 0; 184 private @Config int mChangingConfigurations = 0; 185 private Rect mBounds = ZERO_BOUNDS_RECT; // lazily becomes a new Rect() 186 private WeakReference<Callback> mCallback = null; 187 private boolean mVisible = true; 188 189 private int mLayoutDirection; 190 191 /** 192 * The source density to use when looking up resources using 193 * {@link Resources#getDrawableForDensity(int, int, Theme)}. A value of 0 means there is no 194 * override and the system density will be used. 195 * 196 * NOTE(adamlesinski): This is transient state used to get around the public API that does not 197 * account for source density overrides. Custom drawables implemented by developers do not need 198 * to be aware of the source density override, as it is only used by Launcher to load higher 199 * resolution icons from external Resources packages, which do not execute custom code. 200 * This is all to support the {@link Resources#getDrawableForDensity(int, int, Theme)} API. 201 * 202 * @hide 203 */ 204 protected int mSrcDensityOverride = 0; 205 206 /** 207 * Draw in its bounds (set via setBounds) respecting optional effects such 208 * as alpha (set via setAlpha) and color filter (set via setColorFilter). 209 * 210 * @param canvas The canvas to draw into 211 */ draw(@onNull Canvas canvas)212 public abstract void draw(@NonNull Canvas canvas); 213 214 /** 215 * Specify a bounding rectangle for the Drawable. This is where the drawable 216 * will draw when its draw() method is called. 217 */ setBounds(int left, int top, int right, int bottom)218 public void setBounds(int left, int top, int right, int bottom) { 219 Rect oldBounds = mBounds; 220 221 if (oldBounds == ZERO_BOUNDS_RECT) { 222 oldBounds = mBounds = new Rect(); 223 } 224 225 if (oldBounds.left != left || oldBounds.top != top || 226 oldBounds.right != right || oldBounds.bottom != bottom) { 227 if (!oldBounds.isEmpty()) { 228 // first invalidate the previous bounds 229 invalidateSelf(); 230 } 231 mBounds.set(left, top, right, bottom); 232 onBoundsChange(mBounds); 233 } 234 } 235 236 /** 237 * Specify a bounding rectangle for the Drawable. This is where the drawable 238 * will draw when its draw() method is called. 239 */ setBounds(@onNull Rect bounds)240 public void setBounds(@NonNull Rect bounds) { 241 setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom); 242 } 243 244 /** 245 * Return a copy of the drawable's bounds in the specified Rect (allocated 246 * by the caller). The bounds specify where this will draw when its draw() 247 * method is called. 248 * 249 * @param bounds Rect to receive the drawable's bounds (allocated by the 250 * caller). 251 */ copyBounds(@onNull Rect bounds)252 public final void copyBounds(@NonNull Rect bounds) { 253 bounds.set(mBounds); 254 } 255 256 /** 257 * Return a copy of the drawable's bounds in a new Rect. This returns the 258 * same values as getBounds(), but the returned object is guaranteed to not 259 * be changed later by the drawable (i.e. it retains no reference to this 260 * rect). If the caller already has a Rect allocated, call copyBounds(rect). 261 * 262 * @return A copy of the drawable's bounds 263 */ 264 @NonNull copyBounds()265 public final Rect copyBounds() { 266 return new Rect(mBounds); 267 } 268 269 /** 270 * Return the drawable's bounds Rect. Note: for efficiency, the returned 271 * object may be the same object stored in the drawable (though this is not 272 * guaranteed), so if a persistent copy of the bounds is needed, call 273 * copyBounds(rect) instead. 274 * You should also not change the object returned by this method as it may 275 * be the same object stored in the drawable. 276 * 277 * @return The bounds of the drawable (which may change later, so caller 278 * beware). DO NOT ALTER the returned object as it may change the 279 * stored bounds of this drawable. 280 * 281 * @see #copyBounds() 282 * @see #copyBounds(android.graphics.Rect) 283 */ 284 @NonNull getBounds()285 public final Rect getBounds() { 286 if (mBounds == ZERO_BOUNDS_RECT) { 287 mBounds = new Rect(); 288 } 289 290 return mBounds; 291 } 292 293 /** 294 * Return the drawable's dirty bounds Rect. Note: for efficiency, the 295 * returned object may be the same object stored in the drawable (though 296 * this is not guaranteed). 297 * <p> 298 * By default, this returns the full drawable bounds. Custom drawables may 299 * override this method to perform more precise invalidation. 300 * 301 * @return The dirty bounds of this drawable 302 */ 303 @NonNull getDirtyBounds()304 public Rect getDirtyBounds() { 305 return getBounds(); 306 } 307 308 /** 309 * Set a mask of the configuration parameters for which this drawable 310 * may change, requiring that it be re-created. 311 * 312 * @param configs A mask of the changing configuration parameters, as 313 * defined by {@link android.content.pm.ActivityInfo}. 314 * 315 * @see android.content.pm.ActivityInfo 316 */ setChangingConfigurations(@onfig int configs)317 public void setChangingConfigurations(@Config int configs) { 318 mChangingConfigurations = configs; 319 } 320 321 /** 322 * Return a mask of the configuration parameters for which this drawable 323 * may change, requiring that it be re-created. The default implementation 324 * returns whatever was provided through 325 * {@link #setChangingConfigurations(int)} or 0 by default. Subclasses 326 * may extend this to or in the changing configurations of any other 327 * drawables they hold. 328 * 329 * @return Returns a mask of the changing configuration parameters, as 330 * defined by {@link android.content.pm.ActivityInfo}. 331 * 332 * @see android.content.pm.ActivityInfo 333 */ getChangingConfigurations()334 public @Config int getChangingConfigurations() { 335 return mChangingConfigurations; 336 } 337 338 /** 339 * Set to true to have the drawable dither its colors when drawn to a 340 * device with fewer than 8-bits per color component. 341 * 342 * @see android.graphics.Paint#setDither(boolean); 343 * @deprecated This property is ignored. 344 */ 345 @Deprecated setDither(boolean dither)346 public void setDither(boolean dither) {} 347 348 /** 349 * Set to true to have the drawable filter its bitmaps with bilinear 350 * sampling when they are scaled or rotated. 351 * 352 * <p>This can improve appearance when bitmaps are rotated. If the drawable 353 * does not use bitmaps, this call is ignored.</p> 354 * 355 * @see #isFilterBitmap() 356 * @see android.graphics.Paint#setFilterBitmap(boolean); 357 */ setFilterBitmap(boolean filter)358 public void setFilterBitmap(boolean filter) {} 359 360 /** 361 * @return whether this drawable filters its bitmaps 362 * @see #setFilterBitmap(boolean) 363 */ isFilterBitmap()364 public boolean isFilterBitmap() { 365 return false; 366 } 367 368 /** 369 * Implement this interface if you want to create an animated drawable that 370 * extends {@link android.graphics.drawable.Drawable Drawable}. 371 * Upon retrieving a drawable, use 372 * {@link Drawable#setCallback(android.graphics.drawable.Drawable.Callback)} 373 * to supply your implementation of the interface to the drawable; it uses 374 * this interface to schedule and execute animation changes. 375 */ 376 public interface Callback { 377 /** 378 * Called when the drawable needs to be redrawn. A view at this point 379 * should invalidate itself (or at least the part of itself where the 380 * drawable appears). 381 * 382 * @param who The drawable that is requesting the update. 383 */ invalidateDrawable(@onNull Drawable who)384 void invalidateDrawable(@NonNull Drawable who); 385 386 /** 387 * A Drawable can call this to schedule the next frame of its 388 * animation. An implementation can generally simply call 389 * {@link android.os.Handler#postAtTime(Runnable, Object, long)} with 390 * the parameters <var>(what, who, when)</var> to perform the 391 * scheduling. 392 * 393 * @param who The drawable being scheduled. 394 * @param what The action to execute. 395 * @param when The time (in milliseconds) to run. The timebase is 396 * {@link android.os.SystemClock#uptimeMillis} 397 */ scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)398 void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when); 399 400 /** 401 * A Drawable can call this to unschedule an action previously 402 * scheduled with {@link #scheduleDrawable}. An implementation can 403 * generally simply call 404 * {@link android.os.Handler#removeCallbacks(Runnable, Object)} with 405 * the parameters <var>(what, who)</var> to unschedule the drawable. 406 * 407 * @param who The drawable being unscheduled. 408 * @param what The action being unscheduled. 409 */ unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)410 void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what); 411 } 412 413 /** 414 * Bind a {@link Callback} object to this Drawable. Required for clients 415 * that want to support animated drawables. 416 * 417 * @param cb The client's Callback implementation. 418 * 419 * @see #getCallback() 420 */ setCallback(@ullable Callback cb)421 public final void setCallback(@Nullable Callback cb) { 422 mCallback = cb != null ? new WeakReference<>(cb) : null; 423 } 424 425 /** 426 * Return the current {@link Callback} implementation attached to this 427 * Drawable. 428 * 429 * @return A {@link Callback} instance or null if no callback was set. 430 * 431 * @see #setCallback(android.graphics.drawable.Drawable.Callback) 432 */ 433 @Nullable getCallback()434 public Callback getCallback() { 435 return mCallback != null ? mCallback.get() : null; 436 } 437 438 /** 439 * Use the current {@link Callback} implementation to have this Drawable 440 * redrawn. Does nothing if there is no Callback attached to the 441 * Drawable. 442 * 443 * @see Callback#invalidateDrawable 444 * @see #getCallback() 445 * @see #setCallback(android.graphics.drawable.Drawable.Callback) 446 */ invalidateSelf()447 public void invalidateSelf() { 448 final Callback callback = getCallback(); 449 if (callback != null) { 450 callback.invalidateDrawable(this); 451 } 452 } 453 454 /** 455 * Use the current {@link Callback} implementation to have this Drawable 456 * scheduled. Does nothing if there is no Callback attached to the 457 * Drawable. 458 * 459 * @param what The action being scheduled. 460 * @param when The time (in milliseconds) to run. 461 * 462 * @see Callback#scheduleDrawable 463 */ scheduleSelf(@onNull Runnable what, long when)464 public void scheduleSelf(@NonNull Runnable what, long when) { 465 final Callback callback = getCallback(); 466 if (callback != null) { 467 callback.scheduleDrawable(this, what, when); 468 } 469 } 470 471 /** 472 * Use the current {@link Callback} implementation to have this Drawable 473 * unscheduled. Does nothing if there is no Callback attached to the 474 * Drawable. 475 * 476 * @param what The runnable that you no longer want called. 477 * 478 * @see Callback#unscheduleDrawable 479 */ unscheduleSelf(@onNull Runnable what)480 public void unscheduleSelf(@NonNull Runnable what) { 481 final Callback callback = getCallback(); 482 if (callback != null) { 483 callback.unscheduleDrawable(this, what); 484 } 485 } 486 487 /** 488 * Returns the resolved layout direction for this Drawable. 489 * 490 * @return One of {@link android.view.View#LAYOUT_DIRECTION_LTR}, 491 * {@link android.view.View#LAYOUT_DIRECTION_RTL} 492 * @see #setLayoutDirection(int) 493 */ getLayoutDirection()494 public @View.ResolvedLayoutDir int getLayoutDirection() { 495 return mLayoutDirection; 496 } 497 498 /** 499 * Set the layout direction for this drawable. Should be a resolved 500 * layout direction, as the Drawable has no capacity to do the resolution on 501 * its own. 502 * 503 * @param layoutDirection the resolved layout direction for the drawable, 504 * either {@link android.view.View#LAYOUT_DIRECTION_LTR} 505 * or {@link android.view.View#LAYOUT_DIRECTION_RTL} 506 * @return {@code true} if the layout direction change has caused the 507 * appearance of the drawable to change such that it needs to be 508 * re-drawn, {@code false} otherwise 509 * @see #getLayoutDirection() 510 */ setLayoutDirection(@iew.ResolvedLayoutDir int layoutDirection)511 public final boolean setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) { 512 if (mLayoutDirection != layoutDirection) { 513 mLayoutDirection = layoutDirection; 514 return onLayoutDirectionChanged(layoutDirection); 515 } 516 return false; 517 } 518 519 /** 520 * Called when the drawable's resolved layout direction changes. 521 * 522 * @param layoutDirection the new resolved layout direction 523 * @return {@code true} if the layout direction change has caused the 524 * appearance of the drawable to change such that it needs to be 525 * re-drawn, {@code false} otherwise 526 * @see #setLayoutDirection(int) 527 */ onLayoutDirectionChanged(@iew.ResolvedLayoutDir int layoutDirection)528 public boolean onLayoutDirectionChanged(@View.ResolvedLayoutDir int layoutDirection) { 529 return false; 530 } 531 532 /** 533 * Specify an alpha value for the drawable. 0 means fully transparent, and 534 * 255 means fully opaque. 535 */ setAlpha(@ntRangefrom=0,to=255) int alpha)536 public abstract void setAlpha(@IntRange(from=0,to=255) int alpha); 537 538 /** 539 * Gets the current alpha value for the drawable. 0 means fully transparent, 540 * 255 means fully opaque. This method is implemented by 541 * Drawable subclasses and the value returned is specific to how that class treats alpha. 542 * The default return value is 255 if the class does not override this method to return a value 543 * specific to its use of alpha. 544 */ 545 @IntRange(from=0,to=255) getAlpha()546 public int getAlpha() { 547 return 0xFF; 548 } 549 550 /** 551 * @hide 552 * 553 * Internal-only method for setting xfermode on certain supported drawables. 554 * 555 * Should not be made public since the layers and drawing area with which 556 * Drawables draw is private implementation detail, and not something apps 557 * should rely upon. 558 */ setXfermode(@ullable Xfermode mode)559 public void setXfermode(@Nullable Xfermode mode) { 560 // Base implementation drops it on the floor for compatibility. Whee! 561 } 562 563 /** 564 * Specify an optional color filter for the drawable. 565 * <p> 566 * If a Drawable has a ColorFilter, each output pixel of the Drawable's 567 * drawing contents will be modified by the color filter before it is 568 * blended onto the render target of a Canvas. 569 * </p> 570 * <p> 571 * Pass {@code null} to remove any existing color filter. 572 * </p> 573 * <p class="note"><strong>Note:</strong> Setting a non-{@code null} color 574 * filter disables {@link #setTintList(ColorStateList) tint}. 575 * </p> 576 * 577 * @param colorFilter The color filter to apply, or {@code null} to remove the 578 * existing color filter 579 */ setColorFilter(@ullable ColorFilter colorFilter)580 public abstract void setColorFilter(@Nullable ColorFilter colorFilter); 581 582 /** 583 * Specify a color and Porter-Duff mode to be the color filter for this 584 * drawable. 585 * <p> 586 * Convenience for {@link #setColorFilter(ColorFilter)} which constructs a 587 * {@link PorterDuffColorFilter}. 588 * </p> 589 * <p class="note"><strong>Note:</strong> Setting a color filter disables 590 * {@link #setTintList(ColorStateList) tint}. 591 * </p> 592 */ setColorFilter(@olorInt int color, @NonNull PorterDuff.Mode mode)593 public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) { 594 if (getColorFilter() instanceof PorterDuffColorFilter) { 595 PorterDuffColorFilter existing = (PorterDuffColorFilter) getColorFilter(); 596 if (existing.getColor() == color && existing.getMode() == mode) { 597 return; 598 } 599 } 600 setColorFilter(new PorterDuffColorFilter(color, mode)); 601 } 602 603 /** 604 * Specifies tint color for this drawable. 605 * <p> 606 * A Drawable's drawing content will be blended together with its tint 607 * before it is drawn to the screen. This functions similarly to 608 * {@link #setColorFilter(int, PorterDuff.Mode)}. 609 * </p> 610 * <p> 611 * To clear the tint, pass {@code null} to 612 * {@link #setTintList(ColorStateList)}. 613 * </p> 614 * <p class="note"><strong>Note:</strong> Setting a color filter via 615 * {@link #setColorFilter(ColorFilter)} or 616 * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint. 617 * </p> 618 * 619 * @param tintColor Color to use for tinting this drawable 620 * @see #setTintList(ColorStateList) 621 * @see #setTintMode(PorterDuff.Mode) 622 */ setTint(@olorInt int tintColor)623 public void setTint(@ColorInt int tintColor) { 624 setTintList(ColorStateList.valueOf(tintColor)); 625 } 626 627 /** 628 * Specifies tint color for this drawable as a color state list. 629 * <p> 630 * A Drawable's drawing content will be blended together with its tint 631 * before it is drawn to the screen. This functions similarly to 632 * {@link #setColorFilter(int, PorterDuff.Mode)}. 633 * </p> 634 * <p class="note"><strong>Note:</strong> Setting a color filter via 635 * {@link #setColorFilter(ColorFilter)} or 636 * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint. 637 * </p> 638 * 639 * @param tint Color state list to use for tinting this drawable, or 640 * {@code null} to clear the tint 641 * @see #setTint(int) 642 * @see #setTintMode(PorterDuff.Mode) 643 */ setTintList(@ullable ColorStateList tint)644 public void setTintList(@Nullable ColorStateList tint) {} 645 646 /** 647 * Specifies a tint blending mode for this drawable. 648 * <p> 649 * Defines how this drawable's tint color should be blended into the drawable 650 * before it is drawn to screen. Default tint mode is {@link PorterDuff.Mode#SRC_IN}. 651 * </p> 652 * <p class="note"><strong>Note:</strong> Setting a color filter via 653 * {@link #setColorFilter(ColorFilter)} or 654 * {@link #setColorFilter(int, PorterDuff.Mode)} overrides tint. 655 * </p> 656 * 657 * @param tintMode A Porter-Duff blending mode 658 * @see #setTint(int) 659 * @see #setTintList(ColorStateList) 660 */ setTintMode(@onNull PorterDuff.Mode tintMode)661 public void setTintMode(@NonNull PorterDuff.Mode tintMode) {} 662 663 /** 664 * Returns the current color filter, or {@code null} if none set. 665 * 666 * @return the current color filter, or {@code null} if none set 667 */ getColorFilter()668 public @Nullable ColorFilter getColorFilter() { 669 return null; 670 } 671 672 /** 673 * Removes the color filter for this drawable. 674 */ clearColorFilter()675 public void clearColorFilter() { 676 setColorFilter(null); 677 } 678 679 /** 680 * Specifies the hotspot's location within the drawable. 681 * 682 * @param x The X coordinate of the center of the hotspot 683 * @param y The Y coordinate of the center of the hotspot 684 */ setHotspot(float x, float y)685 public void setHotspot(float x, float y) {} 686 687 /** 688 * Sets the bounds to which the hotspot is constrained, if they should be 689 * different from the drawable bounds. 690 * 691 * @param left position in pixels of the left bound 692 * @param top position in pixels of the top bound 693 * @param right position in pixels of the right bound 694 * @param bottom position in pixels of the bottom bound 695 * @see #getHotspotBounds(android.graphics.Rect) 696 */ setHotspotBounds(int left, int top, int right, int bottom)697 public void setHotspotBounds(int left, int top, int right, int bottom) {} 698 699 /** 700 * Populates {@code outRect} with the hotspot bounds. 701 * 702 * @param outRect the rect to populate with the hotspot bounds 703 * @see #setHotspotBounds(int, int, int, int) 704 */ getHotspotBounds(@onNull Rect outRect)705 public void getHotspotBounds(@NonNull Rect outRect) { 706 outRect.set(getBounds()); 707 } 708 709 /** 710 * Whether this drawable requests projection. 711 * 712 * @hide magic! 713 */ isProjected()714 public boolean isProjected() { 715 return false; 716 } 717 718 /** 719 * Indicates whether this drawable will change its appearance based on 720 * state. Clients can use this to determine whether it is necessary to 721 * calculate their state and call setState. 722 * 723 * @return True if this drawable changes its appearance based on state, 724 * false otherwise. 725 * @see #setState(int[]) 726 */ isStateful()727 public boolean isStateful() { 728 return false; 729 } 730 731 /** 732 * Indicates whether this drawable has at least one state spec explicitly 733 * specifying {@link android.R.attr#state_focused}. 734 * 735 * <p>Note: A View uses a {@link Drawable} instance as its background and it 736 * changes its appearance based on a state. On keyboard devices, it should 737 * specify its {@link android.R.attr#state_focused} to make sure the user 738 * knows which view is holding the focus.</p> 739 * 740 * @return {@code true} if {@link android.R.attr#state_focused} is specified 741 * for this drawable. 742 * 743 * @hide 744 */ 745 @TestApi hasFocusStateSpecified()746 public boolean hasFocusStateSpecified() { 747 return false; 748 } 749 750 /** 751 * Specify a set of states for the drawable. These are use-case specific, 752 * so see the relevant documentation. As an example, the background for 753 * widgets like Button understand the following states: 754 * [{@link android.R.attr#state_focused}, 755 * {@link android.R.attr#state_pressed}]. 756 * 757 * <p>If the new state you are supplying causes the appearance of the 758 * Drawable to change, then it is responsible for calling 759 * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em> 760 * true will be returned from this function. 761 * 762 * <p>Note: The Drawable holds a reference on to <var>stateSet</var> 763 * until a new state array is given to it, so you must not modify this 764 * array during that time.</p> 765 * 766 * @param stateSet The new set of states to be displayed. 767 * 768 * @return Returns true if this change in state has caused the appearance 769 * of the Drawable to change (hence requiring an invalidate), otherwise 770 * returns false. 771 */ setState(@onNull final int[] stateSet)772 public boolean setState(@NonNull final int[] stateSet) { 773 if (!Arrays.equals(mStateSet, stateSet)) { 774 mStateSet = stateSet; 775 return onStateChange(stateSet); 776 } 777 return false; 778 } 779 780 /** 781 * Describes the current state, as a union of primitve states, such as 782 * {@link android.R.attr#state_focused}, 783 * {@link android.R.attr#state_selected}, etc. 784 * Some drawables may modify their imagery based on the selected state. 785 * @return An array of resource Ids describing the current state. 786 */ getState()787 public @NonNull int[] getState() { 788 return mStateSet; 789 } 790 791 /** 792 * If this Drawable does transition animations between states, ask that 793 * it immediately jump to the current state and skip any active animations. 794 */ jumpToCurrentState()795 public void jumpToCurrentState() { 796 } 797 798 /** 799 * @return The current drawable that will be used by this drawable. For simple drawables, this 800 * is just the drawable itself. For drawables that change state like 801 * {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable 802 * currently in use. 803 */ getCurrent()804 public @NonNull Drawable getCurrent() { 805 return this; 806 } 807 808 /** 809 * Specify the level for the drawable. This allows a drawable to vary its 810 * imagery based on a continuous controller, for example to show progress 811 * or volume level. 812 * 813 * <p>If the new level you are supplying causes the appearance of the 814 * Drawable to change, then it is responsible for calling 815 * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em> 816 * true will be returned from this function. 817 * 818 * @param level The new level, from 0 (minimum) to 10000 (maximum). 819 * 820 * @return Returns true if this change in level has caused the appearance 821 * of the Drawable to change (hence requiring an invalidate), otherwise 822 * returns false. 823 */ setLevel(@ntRangefrom=0,to=10000) int level)824 public final boolean setLevel(@IntRange(from=0,to=10000) int level) { 825 if (mLevel != level) { 826 mLevel = level; 827 return onLevelChange(level); 828 } 829 return false; 830 } 831 832 /** 833 * Retrieve the current level. 834 * 835 * @return int Current level, from 0 (minimum) to 10000 (maximum). 836 */ getLevel()837 public final @IntRange(from=0,to=10000) int getLevel() { 838 return mLevel; 839 } 840 841 /** 842 * Set whether this Drawable is visible. This generally does not impact 843 * the Drawable's behavior, but is a hint that can be used by some 844 * Drawables, for example, to decide whether run animations. 845 * 846 * @param visible Set to true if visible, false if not. 847 * @param restart You can supply true here to force the drawable to behave 848 * as if it has just become visible, even if it had last 849 * been set visible. Used for example to force animations 850 * to restart. 851 * 852 * @return boolean Returns true if the new visibility is different than 853 * its previous state. 854 */ setVisible(boolean visible, boolean restart)855 public boolean setVisible(boolean visible, boolean restart) { 856 boolean changed = mVisible != visible; 857 if (changed) { 858 mVisible = visible; 859 invalidateSelf(); 860 } 861 return changed; 862 } 863 isVisible()864 public final boolean isVisible() { 865 return mVisible; 866 } 867 868 /** 869 * Set whether this Drawable is automatically mirrored when its layout direction is RTL 870 * (right-to left). See {@link android.util.LayoutDirection}. 871 * 872 * @param mirrored Set to true if the Drawable should be mirrored, false if not. 873 */ setAutoMirrored(boolean mirrored)874 public void setAutoMirrored(boolean mirrored) { 875 } 876 877 /** 878 * Tells if this Drawable will be automatically mirrored when its layout direction is RTL 879 * right-to-left. See {@link android.util.LayoutDirection}. 880 * 881 * @return boolean Returns true if this Drawable will be automatically mirrored. 882 */ isAutoMirrored()883 public boolean isAutoMirrored() { 884 return false; 885 } 886 887 /** 888 * Applies the specified theme to this Drawable and its children. 889 * 890 * @param t the theme to apply 891 */ applyTheme(@onNull @uppressWarnings"unused") Theme t)892 public void applyTheme(@NonNull @SuppressWarnings("unused") Theme t) { 893 } 894 canApplyTheme()895 public boolean canApplyTheme() { 896 return false; 897 } 898 899 /** 900 * Return the opacity/transparency of this Drawable. The returned value is 901 * one of the abstract format constants in 902 * {@link android.graphics.PixelFormat}: 903 * {@link android.graphics.PixelFormat#UNKNOWN}, 904 * {@link android.graphics.PixelFormat#TRANSLUCENT}, 905 * {@link android.graphics.PixelFormat#TRANSPARENT}, or 906 * {@link android.graphics.PixelFormat#OPAQUE}. 907 * 908 * <p>An OPAQUE drawable is one that draws all all content within its bounds, completely 909 * covering anything behind the drawable. A TRANSPARENT drawable is one that draws nothing 910 * within its bounds, allowing everything behind it to show through. A TRANSLUCENT drawable 911 * is a drawable in any other state, where the drawable will draw some, but not all, 912 * of the content within its bounds and at least some content behind the drawable will 913 * be visible. If the visibility of the drawable's contents cannot be determined, the 914 * safest/best return value is TRANSLUCENT. 915 * 916 * <p>Generally a Drawable should be as conservative as possible with the 917 * value it returns. For example, if it contains multiple child drawables 918 * and only shows one of them at a time, if only one of the children is 919 * TRANSLUCENT and the others are OPAQUE then TRANSLUCENT should be 920 * returned. You can use the method {@link #resolveOpacity} to perform a 921 * standard reduction of two opacities to the appropriate single output. 922 * 923 * <p>Note that the returned value does not necessarily take into account a 924 * custom alpha or color filter that has been applied by the client through 925 * the {@link #setAlpha} or {@link #setColorFilter} methods. Some subclasses, 926 * such as {@link BitmapDrawable}, {@link ColorDrawable}, and {@link GradientDrawable}, 927 * do account for the value of {@link #setAlpha}, but the general behavior is dependent 928 * upon the implementation of the subclass. 929 * 930 * @return int The opacity class of the Drawable. 931 * 932 * @see android.graphics.PixelFormat 933 */ getOpacity()934 public abstract @PixelFormat.Opacity int getOpacity(); 935 936 /** 937 * Return the appropriate opacity value for two source opacities. If 938 * either is UNKNOWN, that is returned; else, if either is TRANSLUCENT, 939 * that is returned; else, if either is TRANSPARENT, that is returned; 940 * else, OPAQUE is returned. 941 * 942 * <p>This is to help in implementing {@link #getOpacity}. 943 * 944 * @param op1 One opacity value. 945 * @param op2 Another opacity value. 946 * 947 * @return int The combined opacity value. 948 * 949 * @see #getOpacity 950 */ resolveOpacity(@ixelFormat.Opacity int op1, @PixelFormat.Opacity int op2)951 public static @PixelFormat.Opacity int resolveOpacity(@PixelFormat.Opacity int op1, 952 @PixelFormat.Opacity int op2) { 953 if (op1 == op2) { 954 return op1; 955 } 956 if (op1 == PixelFormat.UNKNOWN || op2 == PixelFormat.UNKNOWN) { 957 return PixelFormat.UNKNOWN; 958 } 959 if (op1 == PixelFormat.TRANSLUCENT || op2 == PixelFormat.TRANSLUCENT) { 960 return PixelFormat.TRANSLUCENT; 961 } 962 if (op1 == PixelFormat.TRANSPARENT || op2 == PixelFormat.TRANSPARENT) { 963 return PixelFormat.TRANSPARENT; 964 } 965 return PixelFormat.OPAQUE; 966 } 967 968 /** 969 * Returns a Region representing the part of the Drawable that is completely 970 * transparent. This can be used to perform drawing operations, identifying 971 * which parts of the target will not change when rendering the Drawable. 972 * The default implementation returns null, indicating no transparent 973 * region; subclasses can optionally override this to return an actual 974 * Region if they want to supply this optimization information, but it is 975 * not required that they do so. 976 * 977 * @return Returns null if the Drawables has no transparent region to 978 * report, else a Region holding the parts of the Drawable's bounds that 979 * are transparent. 980 */ getTransparentRegion()981 public @Nullable Region getTransparentRegion() { 982 return null; 983 } 984 985 /** 986 * Override this in your subclass to change appearance if you recognize the 987 * specified state. 988 * 989 * @return Returns true if the state change has caused the appearance of 990 * the Drawable to change (that is, it needs to be drawn), else false 991 * if it looks the same and there is no need to redraw it since its 992 * last state. 993 */ onStateChange(int[] state)994 protected boolean onStateChange(int[] state) { 995 return false; 996 } 997 998 /** Override this in your subclass to change appearance if you vary based 999 * on level. 1000 * @return Returns true if the level change has caused the appearance of 1001 * the Drawable to change (that is, it needs to be drawn), else false 1002 * if it looks the same and there is no need to redraw it since its 1003 * last level. 1004 */ onLevelChange(int level)1005 protected boolean onLevelChange(int level) { 1006 return false; 1007 } 1008 1009 /** 1010 * Override this in your subclass to change appearance if you vary based on 1011 * the bounds. 1012 */ onBoundsChange(Rect bounds)1013 protected void onBoundsChange(Rect bounds) { 1014 // Stub method. 1015 } 1016 1017 /** 1018 * Returns the drawable's intrinsic width. 1019 * <p> 1020 * Intrinsic width is the width at which the drawable would like to be laid 1021 * out, including any inherent padding. If the drawable has no intrinsic 1022 * width, such as a solid color, this method returns -1. 1023 * 1024 * @return the intrinsic width, or -1 if no intrinsic width 1025 */ getIntrinsicWidth()1026 public int getIntrinsicWidth() { 1027 return -1; 1028 } 1029 1030 /** 1031 * Returns the drawable's intrinsic height. 1032 * <p> 1033 * Intrinsic height is the height at which the drawable would like to be 1034 * laid out, including any inherent padding. If the drawable has no 1035 * intrinsic height, such as a solid color, this method returns -1. 1036 * 1037 * @return the intrinsic height, or -1 if no intrinsic height 1038 */ getIntrinsicHeight()1039 public int getIntrinsicHeight() { 1040 return -1; 1041 } 1042 1043 /** 1044 * Returns the minimum width suggested by this Drawable. If a View uses this 1045 * Drawable as a background, it is suggested that the View use at least this 1046 * value for its width. (There will be some scenarios where this will not be 1047 * possible.) This value should INCLUDE any padding. 1048 * 1049 * @return The minimum width suggested by this Drawable. If this Drawable 1050 * doesn't have a suggested minimum width, 0 is returned. 1051 */ getMinimumWidth()1052 public int getMinimumWidth() { 1053 final int intrinsicWidth = getIntrinsicWidth(); 1054 return intrinsicWidth > 0 ? intrinsicWidth : 0; 1055 } 1056 1057 /** 1058 * Returns the minimum height suggested by this Drawable. If a View uses this 1059 * Drawable as a background, it is suggested that the View use at least this 1060 * value for its height. (There will be some scenarios where this will not be 1061 * possible.) This value should INCLUDE any padding. 1062 * 1063 * @return The minimum height suggested by this Drawable. If this Drawable 1064 * doesn't have a suggested minimum height, 0 is returned. 1065 */ getMinimumHeight()1066 public int getMinimumHeight() { 1067 final int intrinsicHeight = getIntrinsicHeight(); 1068 return intrinsicHeight > 0 ? intrinsicHeight : 0; 1069 } 1070 1071 /** 1072 * Return in padding the insets suggested by this Drawable for placing 1073 * content inside the drawable's bounds. Positive values move toward the 1074 * center of the Drawable (set Rect.inset). 1075 * 1076 * @return true if this drawable actually has a padding, else false. When false is returned, 1077 * the padding is always set to 0. 1078 */ getPadding(@onNull Rect padding)1079 public boolean getPadding(@NonNull Rect padding) { 1080 padding.set(0, 0, 0, 0); 1081 return false; 1082 } 1083 1084 /** 1085 * Return in insets the layout insets suggested by this Drawable for use with alignment 1086 * operations during layout. 1087 * 1088 * @hide 1089 */ getOpticalInsets()1090 public @NonNull Insets getOpticalInsets() { 1091 return Insets.NONE; 1092 } 1093 1094 /** 1095 * Called to get the drawable to populate the Outline that defines its drawing area. 1096 * <p> 1097 * This method is called by the default {@link android.view.ViewOutlineProvider} to define 1098 * the outline of the View. 1099 * <p> 1100 * The default behavior defines the outline to be the bounding rectangle of 0 alpha. 1101 * Subclasses that wish to convey a different shape or alpha value must override this method. 1102 * 1103 * @see android.view.View#setOutlineProvider(android.view.ViewOutlineProvider) 1104 */ getOutline(@onNull Outline outline)1105 public void getOutline(@NonNull Outline outline) { 1106 outline.setRect(getBounds()); 1107 outline.setAlpha(0); 1108 } 1109 1110 /** 1111 * Make this drawable mutable. This operation cannot be reversed. A mutable 1112 * drawable is guaranteed to not share its state with any other drawable. 1113 * This is especially useful when you need to modify properties of drawables 1114 * loaded from resources. By default, all drawables instances loaded from 1115 * the same resource share a common state; if you modify the state of one 1116 * instance, all the other instances will receive the same modification. 1117 * 1118 * Calling this method on a mutable Drawable will have no effect. 1119 * 1120 * @return This drawable. 1121 * @see ConstantState 1122 * @see #getConstantState() 1123 */ mutate()1124 public @NonNull Drawable mutate() { 1125 return this; 1126 } 1127 1128 /** 1129 * Clears the mutated state, allowing this drawable to be cached and 1130 * mutated again. 1131 * <p> 1132 * This is hidden because only framework drawables can be cached, so 1133 * custom drawables don't need to support constant state, mutate(), or 1134 * clearMutated(). 1135 * 1136 * @hide 1137 */ clearMutated()1138 public void clearMutated() { 1139 // Default implementation is no-op. 1140 } 1141 1142 /** 1143 * Create a drawable from an inputstream 1144 */ createFromStream(InputStream is, String srcName)1145 public static Drawable createFromStream(InputStream is, String srcName) { 1146 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable"); 1147 try { 1148 return createFromResourceStream(null, null, is, srcName); 1149 } finally { 1150 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 1151 } 1152 } 1153 1154 /** 1155 * Create a drawable from an inputstream, using the given resources and 1156 * value to determine density information. 1157 */ createFromResourceStream(Resources res, TypedValue value, InputStream is, String srcName)1158 public static Drawable createFromResourceStream(Resources res, TypedValue value, 1159 InputStream is, String srcName) { 1160 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, srcName != null ? srcName : "Unknown drawable"); 1161 try { 1162 return createFromResourceStream(res, value, is, srcName, null); 1163 } finally { 1164 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 1165 } 1166 } 1167 1168 /** 1169 * Create a drawable from an inputstream, using the given resources and 1170 * value to determine density information. 1171 */ createFromResourceStream(Resources res, TypedValue value, InputStream is, String srcName, BitmapFactory.Options opts)1172 public static Drawable createFromResourceStream(Resources res, TypedValue value, 1173 InputStream is, String srcName, BitmapFactory.Options opts) { 1174 if (is == null) { 1175 return null; 1176 } 1177 1178 /* ugh. The decodeStream contract is that we have already allocated 1179 the pad rect, but if the bitmap does not had a ninepatch chunk, 1180 then the pad will be ignored. If we could change this to lazily 1181 alloc/assign the rect, we could avoid the GC churn of making new 1182 Rects only to drop them on the floor. 1183 */ 1184 Rect pad = new Rect(); 1185 1186 // Special stuff for compatibility mode: if the target density is not 1187 // the same as the display density, but the resource -is- the same as 1188 // the display density, then don't scale it down to the target density. 1189 // This allows us to load the system's density-correct resources into 1190 // an application in compatibility mode, without scaling those down 1191 // to the compatibility density only to have them scaled back up when 1192 // drawn to the screen. 1193 if (opts == null) opts = new BitmapFactory.Options(); 1194 opts.inScreenDensity = Drawable.resolveDensity(res, 0); 1195 Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts); 1196 if (bm != null) { 1197 byte[] np = bm.getNinePatchChunk(); 1198 if (np == null || !NinePatch.isNinePatchChunk(np)) { 1199 np = null; 1200 pad = null; 1201 } 1202 1203 final Rect opticalInsets = new Rect(); 1204 bm.getOpticalInsets(opticalInsets); 1205 return drawableFromBitmap(res, bm, np, pad, opticalInsets, srcName); 1206 } 1207 return null; 1208 } 1209 1210 /** 1211 * Create a drawable from an XML document. For more information on how to 1212 * create resources in XML, see 1213 * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>. 1214 */ 1215 @NonNull createFromXml(@onNull Resources r, @NonNull XmlPullParser parser)1216 public static Drawable createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser) 1217 throws XmlPullParserException, IOException { 1218 return createFromXml(r, parser, null); 1219 } 1220 1221 /** 1222 * Create a drawable from an XML document using an optional {@link Theme}. 1223 * For more information on how to create resources in XML, see 1224 * <a href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>. 1225 */ 1226 @NonNull createFromXml(@onNull Resources r, @NonNull XmlPullParser parser, @Nullable Theme theme)1227 public static Drawable createFromXml(@NonNull Resources r, @NonNull XmlPullParser parser, 1228 @Nullable Theme theme) throws XmlPullParserException, IOException { 1229 return createFromXmlForDensity(r, parser, 0, theme); 1230 } 1231 1232 /** 1233 * Version of {@link #createFromXml(Resources, XmlPullParser, Theme)} that accepts a density 1234 * override. 1235 * @hide 1236 */ 1237 @NonNull createFromXmlForDensity(@onNull Resources r, @NonNull XmlPullParser parser, int density, @Nullable Theme theme)1238 public static Drawable createFromXmlForDensity(@NonNull Resources r, 1239 @NonNull XmlPullParser parser, int density, @Nullable Theme theme) 1240 throws XmlPullParserException, IOException { 1241 AttributeSet attrs = Xml.asAttributeSet(parser); 1242 1243 int type; 1244 //noinspection StatementWithEmptyBody 1245 while ((type=parser.next()) != XmlPullParser.START_TAG 1246 && type != XmlPullParser.END_DOCUMENT) { 1247 // Empty loop. 1248 } 1249 1250 if (type != XmlPullParser.START_TAG) { 1251 throw new XmlPullParserException("No start tag found"); 1252 } 1253 1254 Drawable drawable = createFromXmlInnerForDensity(r, parser, attrs, density, theme); 1255 1256 if (drawable == null) { 1257 throw new RuntimeException("Unknown initial tag: " + parser.getName()); 1258 } 1259 1260 return drawable; 1261 } 1262 1263 /** 1264 * Create from inside an XML document. Called on a parser positioned at 1265 * a tag in an XML document, tries to create a Drawable from that tag. 1266 * Returns null if the tag is not a valid drawable. 1267 */ 1268 @NonNull createFromXmlInner(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs)1269 public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser, 1270 @NonNull AttributeSet attrs) throws XmlPullParserException, IOException { 1271 return createFromXmlInner(r, parser, attrs, null); 1272 } 1273 1274 /** 1275 * Create a drawable from inside an XML document using an optional 1276 * {@link Theme}. Called on a parser positioned at a tag in an XML 1277 * document, tries to create a Drawable from that tag. Returns {@code null} 1278 * if the tag is not a valid drawable. 1279 */ 1280 @NonNull createFromXmlInner(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)1281 public static Drawable createFromXmlInner(@NonNull Resources r, @NonNull XmlPullParser parser, 1282 @NonNull AttributeSet attrs, @Nullable Theme theme) 1283 throws XmlPullParserException, IOException { 1284 return createFromXmlInnerForDensity(r, parser, attrs, 0, theme); 1285 } 1286 1287 /** 1288 * Version of {@link #createFromXmlInner(Resources, XmlPullParser, AttributeSet, Theme)} that 1289 * accepts an override density. 1290 */ 1291 @NonNull createFromXmlInnerForDensity(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density, @Nullable Theme theme)1292 static Drawable createFromXmlInnerForDensity(@NonNull Resources r, 1293 @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, int density, 1294 @Nullable Theme theme) throws XmlPullParserException, IOException { 1295 return r.getDrawableInflater().inflateFromXmlForDensity(parser.getName(), parser, attrs, 1296 density, theme); 1297 } 1298 1299 /** 1300 * Create a drawable from file path name. 1301 */ 1302 @Nullable createFromPath(String pathName)1303 public static Drawable createFromPath(String pathName) { 1304 if (pathName == null) { 1305 return null; 1306 } 1307 1308 Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName); 1309 try { 1310 Bitmap bm = BitmapFactory.decodeFile(pathName); 1311 if (bm != null) { 1312 return drawableFromBitmap(null, bm, null, null, null, pathName); 1313 } 1314 } finally { 1315 Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); 1316 } 1317 1318 return null; 1319 } 1320 1321 /** 1322 * Inflate this Drawable from an XML resource. Does not apply a theme. 1323 * 1324 * @see #inflate(Resources, XmlPullParser, AttributeSet, Theme) 1325 */ inflate(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs)1326 public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, 1327 @NonNull AttributeSet attrs) throws XmlPullParserException, IOException { 1328 inflate(r, parser, attrs, null); 1329 } 1330 1331 /** 1332 * Inflate this Drawable from an XML resource optionally styled by a theme. 1333 * This can't be called more than once for each Drawable. Note that framework may have called 1334 * this once to create the Drawable instance from XML resource. 1335 * 1336 * @param r Resources used to resolve attribute values 1337 * @param parser XML parser from which to inflate this Drawable 1338 * @param attrs Base set of attribute values 1339 * @param theme Theme to apply, may be null 1340 * @throws XmlPullParserException 1341 * @throws IOException 1342 */ inflate(@onNull Resources r, @NonNull XmlPullParser parser, @NonNull AttributeSet attrs, @Nullable Theme theme)1343 public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser, 1344 @NonNull AttributeSet attrs, @Nullable Theme theme) 1345 throws XmlPullParserException, IOException { 1346 final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.Drawable); 1347 mVisible = a.getBoolean(R.styleable.Drawable_visible, mVisible); 1348 a.recycle(); 1349 } 1350 1351 /** 1352 * Inflate a Drawable from an XML resource. 1353 * 1354 * @throws XmlPullParserException 1355 * @throws IOException 1356 */ inflateWithAttributes(@onNull @uppressWarnings"unused") Resources r, @NonNull @SuppressWarnings("unused") XmlPullParser parser, @NonNull TypedArray attrs, @AttrRes int visibleAttr)1357 void inflateWithAttributes(@NonNull @SuppressWarnings("unused") Resources r, 1358 @NonNull @SuppressWarnings("unused") XmlPullParser parser, @NonNull TypedArray attrs, 1359 @AttrRes int visibleAttr) throws XmlPullParserException, IOException { 1360 mVisible = attrs.getBoolean(visibleAttr, mVisible); 1361 } 1362 1363 /** 1364 * Sets the source override density for this Drawable. If non-zero, this density is to be used 1365 * for any calls to {@link Resources#getDrawableForDensity(int, int, Theme)} or 1366 * {@link Resources#getValueForDensity(int, int, TypedValue, boolean)}. 1367 * @hide 1368 */ setSrcDensityOverride(int density)1369 final void setSrcDensityOverride(int density) { 1370 mSrcDensityOverride = density; 1371 } 1372 1373 /** 1374 * This abstract class is used by {@link Drawable}s to store shared constant state and data 1375 * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance 1376 * share a unique bitmap stored in their ConstantState. 1377 * 1378 * <p> 1379 * {@link #newDrawable(Resources)} can be used as a factory to create new Drawable instances 1380 * from this ConstantState. 1381 * </p> 1382 * 1383 * Use {@link Drawable#getConstantState()} to retrieve the ConstantState of a Drawable. Calling 1384 * {@link Drawable#mutate()} on a Drawable should typically create a new ConstantState for that 1385 * Drawable. 1386 */ 1387 public static abstract class ConstantState { 1388 /** 1389 * Creates a new Drawable instance from its constant state. 1390 * <p> 1391 * <strong>Note:</strong> Using this method means density-dependent 1392 * properties, such as pixel dimensions or bitmap images, will not be 1393 * updated to match the density of the target display. To ensure 1394 * correct scaling, use {@link #newDrawable(Resources)} instead to 1395 * provide an appropriate Resources object. 1396 * 1397 * @return a new drawable object based on this constant state 1398 * @see #newDrawable(Resources) 1399 */ newDrawable()1400 public abstract @NonNull Drawable newDrawable(); 1401 1402 /** 1403 * Creates a new Drawable instance from its constant state using the 1404 * specified resources. This method should be implemented for drawables 1405 * that have density-dependent properties. 1406 * <p> 1407 * The default implementation for this method calls through to 1408 * {@link #newDrawable()}. 1409 * 1410 * @param res the resources of the context in which the drawable will 1411 * be displayed 1412 * @return a new drawable object based on this constant state 1413 */ newDrawable(@ullable Resources res)1414 public @NonNull Drawable newDrawable(@Nullable Resources res) { 1415 return newDrawable(); 1416 } 1417 1418 /** 1419 * Creates a new Drawable instance from its constant state using the 1420 * specified resources and theme. This method should be implemented for 1421 * drawables that have theme-dependent properties. 1422 * <p> 1423 * The default implementation for this method calls through to 1424 * {@link #newDrawable(Resources)}. 1425 * 1426 * @param res the resources of the context in which the drawable will 1427 * be displayed 1428 * @param theme the theme of the context in which the drawable will be 1429 * displayed 1430 * @return a new drawable object based on this constant state 1431 */ newDrawable(@ullable Resources res, @Nullable @SuppressWarnings("unused") Theme theme)1432 public @NonNull Drawable newDrawable(@Nullable Resources res, 1433 @Nullable @SuppressWarnings("unused") Theme theme) { 1434 return newDrawable(res); 1435 } 1436 1437 /** 1438 * Return a bit mask of configuration changes that will impact 1439 * this drawable (and thus require completely reloading it). 1440 */ getChangingConfigurations()1441 public abstract @Config int getChangingConfigurations(); 1442 1443 /** 1444 * Return whether this constant state can have a theme applied. 1445 */ canApplyTheme()1446 public boolean canApplyTheme() { 1447 return false; 1448 } 1449 } 1450 1451 /** 1452 * Return a {@link ConstantState} instance that holds the shared state of this Drawable. 1453 * 1454 * @return The ConstantState associated to that Drawable. 1455 * @see ConstantState 1456 * @see Drawable#mutate() 1457 */ getConstantState()1458 public @Nullable ConstantState getConstantState() { 1459 return null; 1460 } 1461 drawableFromBitmap(Resources res, Bitmap bm, byte[] np, Rect pad, Rect layoutBounds, String srcName)1462 private static Drawable drawableFromBitmap(Resources res, Bitmap bm, byte[] np, 1463 Rect pad, Rect layoutBounds, String srcName) { 1464 1465 if (np != null) { 1466 return new NinePatchDrawable(res, bm, np, pad, layoutBounds, srcName); 1467 } 1468 1469 return new BitmapDrawable(res, bm); 1470 } 1471 1472 /** 1473 * Ensures the tint filter is consistent with the current tint color and 1474 * mode. 1475 */ updateTintFilter(@ullable PorterDuffColorFilter tintFilter, @Nullable ColorStateList tint, @Nullable PorterDuff.Mode tintMode)1476 @Nullable PorterDuffColorFilter updateTintFilter(@Nullable PorterDuffColorFilter tintFilter, 1477 @Nullable ColorStateList tint, @Nullable PorterDuff.Mode tintMode) { 1478 if (tint == null || tintMode == null) { 1479 return null; 1480 } 1481 1482 final int color = tint.getColorForState(getState(), Color.TRANSPARENT); 1483 if (tintFilter == null) { 1484 return new PorterDuffColorFilter(color, tintMode); 1485 } 1486 1487 tintFilter.setColor(color); 1488 tintFilter.setMode(tintMode); 1489 return tintFilter; 1490 } 1491 1492 /** 1493 * Obtains styled attributes from the theme, if available, or unstyled 1494 * resources if the theme is null. 1495 * @hide 1496 */ obtainAttributes(@onNull Resources res, @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs)1497 protected static @NonNull TypedArray obtainAttributes(@NonNull Resources res, 1498 @Nullable Theme theme, @NonNull AttributeSet set, @NonNull int[] attrs) { 1499 if (theme == null) { 1500 return res.obtainAttributes(set, attrs); 1501 } 1502 return theme.obtainStyledAttributes(set, attrs, 0, 0); 1503 } 1504 1505 /** 1506 * Scales a floating-point pixel value from the source density to the 1507 * target density. 1508 * 1509 * @param pixels the pixel value for use in source density 1510 * @param sourceDensity the source density 1511 * @param targetDensity the target density 1512 * @return the scaled pixel value for use in target density 1513 */ scaleFromDensity(float pixels, int sourceDensity, int targetDensity)1514 static float scaleFromDensity(float pixels, int sourceDensity, int targetDensity) { 1515 return pixels * targetDensity / sourceDensity; 1516 } 1517 1518 /** 1519 * Scales a pixel value from the source density to the target density, 1520 * optionally handling the resulting pixel value as a size rather than an 1521 * offset. 1522 * <p> 1523 * A size conversion involves rounding the base value and ensuring that 1524 * a non-zero base value is at least one pixel in size. 1525 * <p> 1526 * An offset conversion involves simply truncating the base value to an 1527 * integer. 1528 * 1529 * @param pixels the pixel value for use in source density 1530 * @param sourceDensity the source density 1531 * @param targetDensity the target density 1532 * @param isSize {@code true} to handle the resulting scaled value as a 1533 * size, or {@code false} to handle it as an offset 1534 * @return the scaled pixel value for use in target density 1535 */ scaleFromDensity( int pixels, int sourceDensity, int targetDensity, boolean isSize)1536 static int scaleFromDensity( 1537 int pixels, int sourceDensity, int targetDensity, boolean isSize) { 1538 if (pixels == 0 || sourceDensity == targetDensity) { 1539 return pixels; 1540 } 1541 1542 final float result = pixels * targetDensity / (float) sourceDensity; 1543 if (!isSize) { 1544 return (int) result; 1545 } 1546 1547 final int rounded = Math.round(result); 1548 if (rounded != 0) { 1549 return rounded; 1550 } else if (pixels > 0) { 1551 return 1; 1552 } else { 1553 return -1; 1554 } 1555 } 1556 resolveDensity(@ullable Resources r, int parentDensity)1557 static int resolveDensity(@Nullable Resources r, int parentDensity) { 1558 final int densityDpi = r == null ? parentDensity : r.getDisplayMetrics().densityDpi; 1559 return densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi; 1560 } 1561 1562 /** 1563 * Re-throws an exception as a {@link RuntimeException} with an empty stack 1564 * trace to avoid cluttering the log. The original exception's stack trace 1565 * will still be included. 1566 * 1567 * @param cause the exception to re-throw 1568 * @throws RuntimeException 1569 */ rethrowAsRuntimeException(@onNull Exception cause)1570 static void rethrowAsRuntimeException(@NonNull Exception cause) throws RuntimeException { 1571 final RuntimeException e = new RuntimeException(cause); 1572 e.setStackTrace(new StackTraceElement[0]); 1573 throw e; 1574 } 1575 1576 /** 1577 * Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode 1578 * attribute's enum value. 1579 * 1580 * @hide 1581 */ parseTintMode(int value, Mode defaultMode)1582 public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) { 1583 switch (value) { 1584 case 3: return Mode.SRC_OVER; 1585 case 5: return Mode.SRC_IN; 1586 case 9: return Mode.SRC_ATOP; 1587 case 14: return Mode.MULTIPLY; 1588 case 15: return Mode.SCREEN; 1589 case 16: return Mode.ADD; 1590 default: return defaultMode; 1591 } 1592 } 1593 } 1594 1595