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