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.content.res; 18 19 import android.animation.Animator; 20 import android.animation.StateListAnimator; 21 import android.annotation.AnimRes; 22 import android.annotation.AnimatorRes; 23 import android.annotation.AnyRes; 24 import android.annotation.ArrayRes; 25 import android.annotation.AttrRes; 26 import android.annotation.BoolRes; 27 import android.annotation.ColorInt; 28 import android.annotation.ColorRes; 29 import android.annotation.DimenRes; 30 import android.annotation.DrawableRes; 31 import android.annotation.FontRes; 32 import android.annotation.FractionRes; 33 import android.annotation.IntegerRes; 34 import android.annotation.LayoutRes; 35 import android.annotation.NonNull; 36 import android.annotation.Nullable; 37 import android.annotation.PluralsRes; 38 import android.annotation.RawRes; 39 import android.annotation.StringRes; 40 import android.annotation.StyleRes; 41 import android.annotation.StyleableRes; 42 import android.annotation.XmlRes; 43 import android.content.pm.ActivityInfo; 44 import android.content.pm.ActivityInfo.Config; 45 import android.graphics.Movie; 46 import android.graphics.Typeface; 47 import android.graphics.drawable.Drawable; 48 import android.graphics.drawable.Drawable.ConstantState; 49 import android.graphics.drawable.DrawableInflater; 50 import android.os.Build; 51 import android.os.Bundle; 52 import android.util.AttributeSet; 53 import android.util.DisplayMetrics; 54 import android.util.Log; 55 import android.util.LongSparseArray; 56 import android.util.Pools.SynchronizedPool; 57 import android.util.TypedValue; 58 import android.view.DisplayAdjustments; 59 import android.view.ViewDebug; 60 import android.view.ViewHierarchyEncoder; 61 62 import com.android.internal.annotations.VisibleForTesting; 63 import com.android.internal.util.GrowingArrayUtils; 64 import com.android.internal.util.XmlUtils; 65 66 import org.xmlpull.v1.XmlPullParser; 67 import org.xmlpull.v1.XmlPullParserException; 68 69 import java.io.IOException; 70 import java.io.InputStream; 71 import java.lang.ref.WeakReference; 72 import java.util.ArrayList; 73 74 /** 75 * Class for accessing an application's resources. This sits on top of the 76 * asset manager of the application (accessible through {@link #getAssets}) and 77 * provides a high-level API for getting typed data from the assets. 78 * 79 * <p>The Android resource system keeps track of all non-code assets associated with an 80 * application. You can use this class to access your application's resources. You can generally 81 * acquire the {@link android.content.res.Resources} instance associated with your application 82 * with {@link android.content.Context#getResources getResources()}.</p> 83 * 84 * <p>The Android SDK tools compile your application's resources into the application binary 85 * at build time. To use a resource, you must install it correctly in the source tree (inside 86 * your project's {@code res/} directory) and build your application. As part of the build 87 * process, the SDK tools generate symbols for each resource, which you can use in your application 88 * code to access the resources.</p> 89 * 90 * <p>Using application resources makes it easy to update various characteristics of your 91 * application without modifying code, and—by providing sets of alternative 92 * resources—enables you to optimize your application for a variety of device configurations 93 * (such as for different languages and screen sizes). This is an important aspect of developing 94 * Android applications that are compatible on different types of devices.</p> 95 * 96 * <p>For more information about using resources, see the documentation about <a 97 * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p> 98 */ 99 public class Resources { 100 static final String TAG = "Resources"; 101 102 private static final Object sSync = new Object(); 103 104 // Used by BridgeResources in layoutlib 105 static Resources mSystem = null; 106 107 private ResourcesImpl mResourcesImpl; 108 109 // Pool of TypedArrays targeted to this Resources object. 110 final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5); 111 112 /** Used to inflate drawable objects from XML. */ 113 private DrawableInflater mDrawableInflater; 114 115 /** Lock object used to protect access to {@link #mTmpValue}. */ 116 private final Object mTmpValueLock = new Object(); 117 118 /** Single-item pool used to minimize TypedValue allocations. */ 119 private TypedValue mTmpValue = new TypedValue(); 120 121 final ClassLoader mClassLoader; 122 123 /** 124 * WeakReferences to Themes that were constructed from this Resources object. 125 * We keep track of these in case our underlying implementation is changed, in which case 126 * the Themes must also get updated ThemeImpls. 127 */ 128 private final ArrayList<WeakReference<Theme>> mThemeRefs = new ArrayList<>(); 129 130 /** 131 * To avoid leaking WeakReferences to garbage collected Themes on the 132 * mThemeRefs list, we flush the list of stale references any time the 133 * mThemeRefNextFlushSize is reached. 134 */ 135 private static final int MIN_THEME_REFS_FLUSH_SIZE = 32; 136 private int mThemeRefsNextFlushSize = MIN_THEME_REFS_FLUSH_SIZE; 137 138 /** 139 * Returns the most appropriate default theme for the specified target SDK version. 140 * <ul> 141 * <li>Below API 11: Gingerbread 142 * <li>APIs 12 thru 14: Holo 143 * <li>APIs 15 thru 23: Device default dark 144 * <li>APIs 24 and above: Device default light with dark action bar 145 * </ul> 146 * 147 * @param curTheme The current theme, or 0 if not specified. 148 * @param targetSdkVersion The target SDK version. 149 * @return A theme resource identifier 150 * @hide 151 */ selectDefaultTheme(int curTheme, int targetSdkVersion)152 public static int selectDefaultTheme(int curTheme, int targetSdkVersion) { 153 return selectSystemTheme(curTheme, targetSdkVersion, 154 com.android.internal.R.style.Theme, 155 com.android.internal.R.style.Theme_Holo, 156 com.android.internal.R.style.Theme_DeviceDefault, 157 com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar); 158 } 159 160 /** @hide */ selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo, int dark, int deviceDefault)161 public static int selectSystemTheme(int curTheme, int targetSdkVersion, int orig, int holo, 162 int dark, int deviceDefault) { 163 if (curTheme != ResourceId.ID_NULL) { 164 return curTheme; 165 } 166 if (targetSdkVersion < Build.VERSION_CODES.HONEYCOMB) { 167 return orig; 168 } 169 if (targetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 170 return holo; 171 } 172 if (targetSdkVersion < Build.VERSION_CODES.N) { 173 return dark; 174 } 175 return deviceDefault; 176 } 177 178 /** 179 * Return a global shared Resources object that provides access to only 180 * system resources (no application resources), and is not configured for 181 * the current screen (can not use dimension units, does not change based 182 * on orientation, etc). 183 */ getSystem()184 public static Resources getSystem() { 185 synchronized (sSync) { 186 Resources ret = mSystem; 187 if (ret == null) { 188 ret = new Resources(); 189 mSystem = ret; 190 } 191 return ret; 192 } 193 } 194 195 /** 196 * This exception is thrown by the resource APIs when a requested resource 197 * can not be found. 198 */ 199 public static class NotFoundException extends RuntimeException { NotFoundException()200 public NotFoundException() { 201 } 202 NotFoundException(String name)203 public NotFoundException(String name) { 204 super(name); 205 } 206 NotFoundException(String name, Exception cause)207 public NotFoundException(String name, Exception cause) { 208 super(name, cause); 209 } 210 } 211 212 /** 213 * Create a new Resources object on top of an existing set of assets in an 214 * AssetManager. 215 * 216 * @deprecated Resources should not be constructed by apps. 217 * See {@link android.content.Context#createConfigurationContext(Configuration)}. 218 * 219 * @param assets Previously created AssetManager. 220 * @param metrics Current display metrics to consider when 221 * selecting/computing resource values. 222 * @param config Desired device configuration to consider when 223 * selecting/computing resource values (optional). 224 */ 225 @Deprecated Resources(AssetManager assets, DisplayMetrics metrics, Configuration config)226 public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) { 227 this(null); 228 mResourcesImpl = new ResourcesImpl(assets, metrics, config, new DisplayAdjustments()); 229 } 230 231 /** 232 * Creates a new Resources object with CompatibilityInfo. 233 * 234 * @param classLoader class loader for the package used to load custom 235 * resource classes, may be {@code null} to use system 236 * class loader 237 * @hide 238 */ Resources(@ullable ClassLoader classLoader)239 public Resources(@Nullable ClassLoader classLoader) { 240 mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader; 241 } 242 243 /** 244 * Only for creating the System resources. 245 */ Resources()246 private Resources() { 247 this(null); 248 249 final DisplayMetrics metrics = new DisplayMetrics(); 250 metrics.setToDefaults(); 251 252 final Configuration config = new Configuration(); 253 config.setToDefaults(); 254 255 mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config, 256 new DisplayAdjustments()); 257 } 258 259 /** 260 * Set the underlying implementation (containing all the resources and caches) 261 * and updates all Theme references to new implementations as well. 262 * @hide 263 */ setImpl(ResourcesImpl impl)264 public void setImpl(ResourcesImpl impl) { 265 if (impl == mResourcesImpl) { 266 return; 267 } 268 269 mResourcesImpl = impl; 270 271 // Create new ThemeImpls that are identical to the ones we have. 272 synchronized (mThemeRefs) { 273 final int count = mThemeRefs.size(); 274 for (int i = 0; i < count; i++) { 275 WeakReference<Theme> weakThemeRef = mThemeRefs.get(i); 276 Theme theme = weakThemeRef != null ? weakThemeRef.get() : null; 277 if (theme != null) { 278 theme.setImpl(mResourcesImpl.newThemeImpl(theme.getKey())); 279 } 280 } 281 } 282 } 283 284 /** 285 * @hide 286 */ getImpl()287 public ResourcesImpl getImpl() { 288 return mResourcesImpl; 289 } 290 291 /** 292 * @hide 293 */ getClassLoader()294 public ClassLoader getClassLoader() { 295 return mClassLoader; 296 } 297 298 /** 299 * @return the inflater used to create drawable objects 300 * @hide Pending API finalization. 301 */ getDrawableInflater()302 public final DrawableInflater getDrawableInflater() { 303 if (mDrawableInflater == null) { 304 mDrawableInflater = new DrawableInflater(this, mClassLoader); 305 } 306 return mDrawableInflater; 307 } 308 309 /** 310 * Used by AnimatorInflater. 311 * 312 * @hide 313 */ getAnimatorCache()314 public ConfigurationBoundResourceCache<Animator> getAnimatorCache() { 315 return mResourcesImpl.getAnimatorCache(); 316 } 317 318 /** 319 * Used by AnimatorInflater. 320 * 321 * @hide 322 */ getStateListAnimatorCache()323 public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() { 324 return mResourcesImpl.getStateListAnimatorCache(); 325 } 326 327 /** 328 * Return the string value associated with a particular resource ID. The 329 * returned object will be a String if this is a plain string; it will be 330 * some other type of CharSequence if it is styled. 331 * {@more} 332 * 333 * @param id The desired resource identifier, as generated by the aapt 334 * tool. This integer encodes the package, type, and resource 335 * entry. The value 0 is an invalid identifier. 336 * 337 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 338 * 339 * @return CharSequence The string data associated with the resource, plus 340 * possibly styled text information. 341 */ getText(@tringRes int id)342 @NonNull public CharSequence getText(@StringRes int id) throws NotFoundException { 343 CharSequence res = mResourcesImpl.getAssets().getResourceText(id); 344 if (res != null) { 345 return res; 346 } 347 throw new NotFoundException("String resource ID #0x" 348 + Integer.toHexString(id)); 349 } 350 351 /** 352 * Return the Typeface value associated with a particular resource ID. 353 * {@more} 354 * 355 * @param id The desired resource identifier, as generated by the aapt 356 * tool. This integer encodes the package, type, and resource 357 * entry. The value 0 is an invalid identifier. 358 * 359 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 360 * 361 * @return Typeface The Typeface data associated with the resource. 362 */ getFont(@ontRes int id)363 @NonNull public Typeface getFont(@FontRes int id) throws NotFoundException { 364 final TypedValue value = obtainTempTypedValue(); 365 try { 366 final ResourcesImpl impl = mResourcesImpl; 367 impl.getValue(id, value, true); 368 Typeface typeface = impl.loadFont(this, value, id); 369 if (typeface != null) { 370 return typeface; 371 } 372 } finally { 373 releaseTempTypedValue(value); 374 } 375 throw new NotFoundException("Font resource ID #0x" 376 + Integer.toHexString(id)); 377 } 378 379 @NonNull getFont(@onNull TypedValue value, @FontRes int id)380 Typeface getFont(@NonNull TypedValue value, @FontRes int id) throws NotFoundException { 381 return mResourcesImpl.loadFont(this, value, id); 382 } 383 384 /** 385 * @hide 386 */ preloadFonts(@rrayRes int id)387 public void preloadFonts(@ArrayRes int id) { 388 final TypedArray array = obtainTypedArray(id); 389 try { 390 final int size = array.length(); 391 for (int i = 0; i < size; i++) { 392 array.getFont(i); 393 } 394 } finally { 395 array.recycle(); 396 } 397 } 398 399 /** 400 * Returns the character sequence necessary for grammatically correct pluralization 401 * of the given resource ID for the given quantity. 402 * Note that the character sequence is selected based solely on grammatical necessity, 403 * and that such rules differ between languages. Do not assume you know which string 404 * will be returned for a given quantity. See 405 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a> 406 * for more detail. 407 * 408 * @param id The desired resource identifier, as generated by the aapt 409 * tool. This integer encodes the package, type, and resource 410 * entry. The value 0 is an invalid identifier. 411 * @param quantity The number used to get the correct string for the current language's 412 * plural rules. 413 * 414 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 415 * 416 * @return CharSequence The string data associated with the resource, plus 417 * possibly styled text information. 418 */ 419 @NonNull getQuantityText(@luralsRes int id, int quantity)420 public CharSequence getQuantityText(@PluralsRes int id, int quantity) 421 throws NotFoundException { 422 return mResourcesImpl.getQuantityText(id, quantity); 423 } 424 425 /** 426 * Return the string value associated with a particular resource ID. It 427 * will be stripped of any styled text information. 428 * {@more} 429 * 430 * @param id The desired resource identifier, as generated by the aapt 431 * tool. This integer encodes the package, type, and resource 432 * entry. The value 0 is an invalid identifier. 433 * 434 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 435 * 436 * @return String The string data associated with the resource, 437 * stripped of styled text information. 438 */ 439 @NonNull getString(@tringRes int id)440 public String getString(@StringRes int id) throws NotFoundException { 441 return getText(id).toString(); 442 } 443 444 445 /** 446 * Return the string value associated with a particular resource ID, 447 * substituting the format arguments as defined in {@link java.util.Formatter} 448 * and {@link java.lang.String#format}. It will be stripped of any styled text 449 * information. 450 * {@more} 451 * 452 * @param id The desired resource identifier, as generated by the aapt 453 * tool. This integer encodes the package, type, and resource 454 * entry. The value 0 is an invalid identifier. 455 * 456 * @param formatArgs The format arguments that will be used for substitution. 457 * 458 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 459 * 460 * @return String The string data associated with the resource, 461 * stripped of styled text information. 462 */ 463 @NonNull getString(@tringRes int id, Object... formatArgs)464 public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException { 465 final String raw = getString(id); 466 return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw, 467 formatArgs); 468 } 469 470 /** 471 * Formats the string necessary for grammatically correct pluralization 472 * of the given resource ID for the given quantity, using the given arguments. 473 * Note that the string is selected based solely on grammatical necessity, 474 * and that such rules differ between languages. Do not assume you know which string 475 * will be returned for a given quantity. See 476 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a> 477 * for more detail. 478 * 479 * <p>Substitution of format arguments works as if using 480 * {@link java.util.Formatter} and {@link java.lang.String#format}. 481 * The resulting string will be stripped of any styled text information. 482 * 483 * @param id The desired resource identifier, as generated by the aapt 484 * tool. This integer encodes the package, type, and resource 485 * entry. The value 0 is an invalid identifier. 486 * @param quantity The number used to get the correct string for the current language's 487 * plural rules. 488 * @param formatArgs The format arguments that will be used for substitution. 489 * 490 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 491 * 492 * @return String The string data associated with the resource, 493 * stripped of styled text information. 494 */ 495 @NonNull getQuantityString(@luralsRes int id, int quantity, Object... formatArgs)496 public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs) 497 throws NotFoundException { 498 String raw = getQuantityText(id, quantity).toString(); 499 return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw, 500 formatArgs); 501 } 502 503 /** 504 * Returns the string necessary for grammatically correct pluralization 505 * of the given resource ID for the given quantity. 506 * Note that the string is selected based solely on grammatical necessity, 507 * and that such rules differ between languages. Do not assume you know which string 508 * will be returned for a given quantity. See 509 * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a> 510 * for more detail. 511 * 512 * @param id The desired resource identifier, as generated by the aapt 513 * tool. This integer encodes the package, type, and resource 514 * entry. The value 0 is an invalid identifier. 515 * @param quantity The number used to get the correct string for the current language's 516 * plural rules. 517 * 518 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 519 * 520 * @return String The string data associated with the resource, 521 * stripped of styled text information. 522 */ 523 @NonNull getQuantityString(@luralsRes int id, int quantity)524 public String getQuantityString(@PluralsRes int id, int quantity) throws NotFoundException { 525 return getQuantityText(id, quantity).toString(); 526 } 527 528 /** 529 * Return the string value associated with a particular resource ID. The 530 * returned object will be a String if this is a plain string; it will be 531 * some other type of CharSequence if it is styled. 532 * 533 * @param id The desired resource identifier, as generated by the aapt 534 * tool. This integer encodes the package, type, and resource 535 * entry. The value 0 is an invalid identifier. 536 * 537 * @param def The default CharSequence to return. 538 * 539 * @return CharSequence The string data associated with the resource, plus 540 * possibly styled text information, or def if id is 0 or not found. 541 */ getText(@tringRes int id, CharSequence def)542 public CharSequence getText(@StringRes int id, CharSequence def) { 543 CharSequence res = id != 0 ? mResourcesImpl.getAssets().getResourceText(id) : null; 544 return res != null ? res : def; 545 } 546 547 /** 548 * Return the styled text array associated with a particular resource ID. 549 * 550 * @param id The desired resource identifier, as generated by the aapt 551 * tool. This integer encodes the package, type, and resource 552 * entry. The value 0 is an invalid identifier. 553 * 554 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 555 * 556 * @return The styled text array associated with the resource. 557 */ 558 @NonNull getTextArray(@rrayRes int id)559 public CharSequence[] getTextArray(@ArrayRes int id) throws NotFoundException { 560 CharSequence[] res = mResourcesImpl.getAssets().getResourceTextArray(id); 561 if (res != null) { 562 return res; 563 } 564 throw new NotFoundException("Text array resource ID #0x" + Integer.toHexString(id)); 565 } 566 567 /** 568 * Return the string array associated with a particular resource ID. 569 * 570 * @param id The desired resource identifier, as generated by the aapt 571 * tool. This integer encodes the package, type, and resource 572 * entry. The value 0 is an invalid identifier. 573 * 574 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 575 * 576 * @return The string array associated with the resource. 577 */ 578 @NonNull getStringArray(@rrayRes int id)579 public String[] getStringArray(@ArrayRes int id) 580 throws NotFoundException { 581 String[] res = mResourcesImpl.getAssets().getResourceStringArray(id); 582 if (res != null) { 583 return res; 584 } 585 throw new NotFoundException("String array resource ID #0x" + Integer.toHexString(id)); 586 } 587 588 /** 589 * Return the int array associated with a particular resource ID. 590 * 591 * @param id The desired resource identifier, as generated by the aapt 592 * tool. This integer encodes the package, type, and resource 593 * entry. The value 0 is an invalid identifier. 594 * 595 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 596 * 597 * @return The int array associated with the resource. 598 */ 599 @NonNull getIntArray(@rrayRes int id)600 public int[] getIntArray(@ArrayRes int id) throws NotFoundException { 601 int[] res = mResourcesImpl.getAssets().getResourceIntArray(id); 602 if (res != null) { 603 return res; 604 } 605 throw new NotFoundException("Int array resource ID #0x" + Integer.toHexString(id)); 606 } 607 608 /** 609 * Return an array of heterogeneous values. 610 * 611 * @param id The desired resource identifier, as generated by the aapt 612 * tool. This integer encodes the package, type, and resource 613 * entry. The value 0 is an invalid identifier. 614 * 615 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 616 * 617 * @return Returns a TypedArray holding an array of the array values. 618 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} 619 * when done with it. 620 */ 621 @NonNull obtainTypedArray(@rrayRes int id)622 public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException { 623 final ResourcesImpl impl = mResourcesImpl; 624 int len = impl.getAssets().getResourceArraySize(id); 625 if (len < 0) { 626 throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id)); 627 } 628 629 TypedArray array = TypedArray.obtain(this, len); 630 array.mLength = impl.getAssets().getResourceArray(id, array.mData); 631 array.mIndices[0] = 0; 632 633 return array; 634 } 635 636 /** 637 * Retrieve a dimensional for a particular resource ID. Unit 638 * conversions are based on the current {@link DisplayMetrics} associated 639 * with the resources. 640 * 641 * @param id The desired resource identifier, as generated by the aapt 642 * tool. This integer encodes the package, type, and resource 643 * entry. The value 0 is an invalid identifier. 644 * 645 * @return Resource dimension value multiplied by the appropriate 646 * metric. 647 * 648 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 649 * 650 * @see #getDimensionPixelOffset 651 * @see #getDimensionPixelSize 652 */ getDimension(@imenRes int id)653 public float getDimension(@DimenRes int id) throws NotFoundException { 654 final TypedValue value = obtainTempTypedValue(); 655 try { 656 final ResourcesImpl impl = mResourcesImpl; 657 impl.getValue(id, value, true); 658 if (value.type == TypedValue.TYPE_DIMENSION) { 659 return TypedValue.complexToDimension(value.data, impl.getDisplayMetrics()); 660 } 661 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 662 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 663 } finally { 664 releaseTempTypedValue(value); 665 } 666 } 667 668 /** 669 * Retrieve a dimensional for a particular resource ID for use 670 * as an offset in raw pixels. This is the same as 671 * {@link #getDimension}, except the returned value is converted to 672 * integer pixels for you. An offset conversion involves simply 673 * truncating the base value to an integer. 674 * 675 * @param id The desired resource identifier, as generated by the aapt 676 * tool. This integer encodes the package, type, and resource 677 * entry. The value 0 is an invalid identifier. 678 * 679 * @return Resource dimension value multiplied by the appropriate 680 * metric and truncated to integer pixels. 681 * 682 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 683 * 684 * @see #getDimension 685 * @see #getDimensionPixelSize 686 */ getDimensionPixelOffset(@imenRes int id)687 public int getDimensionPixelOffset(@DimenRes int id) throws NotFoundException { 688 final TypedValue value = obtainTempTypedValue(); 689 try { 690 final ResourcesImpl impl = mResourcesImpl; 691 impl.getValue(id, value, true); 692 if (value.type == TypedValue.TYPE_DIMENSION) { 693 return TypedValue.complexToDimensionPixelOffset(value.data, 694 impl.getDisplayMetrics()); 695 } 696 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 697 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 698 } finally { 699 releaseTempTypedValue(value); 700 } 701 } 702 703 /** 704 * Retrieve a dimensional for a particular resource ID for use 705 * as a size in raw pixels. This is the same as 706 * {@link #getDimension}, except the returned value is converted to 707 * integer pixels for use as a size. A size conversion involves 708 * rounding the base value, and ensuring that a non-zero base value 709 * is at least one pixel in size. 710 * 711 * @param id The desired resource identifier, as generated by the aapt 712 * tool. This integer encodes the package, type, and resource 713 * entry. The value 0 is an invalid identifier. 714 * 715 * @return Resource dimension value multiplied by the appropriate 716 * metric and truncated to integer pixels. 717 * 718 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 719 * 720 * @see #getDimension 721 * @see #getDimensionPixelOffset 722 */ getDimensionPixelSize(@imenRes int id)723 public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException { 724 final TypedValue value = obtainTempTypedValue(); 725 try { 726 final ResourcesImpl impl = mResourcesImpl; 727 impl.getValue(id, value, true); 728 if (value.type == TypedValue.TYPE_DIMENSION) { 729 return TypedValue.complexToDimensionPixelSize(value.data, impl.getDisplayMetrics()); 730 } 731 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 732 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 733 } finally { 734 releaseTempTypedValue(value); 735 } 736 } 737 738 /** 739 * Retrieve a fractional unit for a particular resource ID. 740 * 741 * @param id The desired resource identifier, as generated by the aapt 742 * tool. This integer encodes the package, type, and resource 743 * entry. The value 0 is an invalid identifier. 744 * @param base The base value of this fraction. In other words, a 745 * standard fraction is multiplied by this value. 746 * @param pbase The parent base value of this fraction. In other 747 * words, a parent fraction (nn%p) is multiplied by this 748 * value. 749 * 750 * @return Attribute fractional value multiplied by the appropriate 751 * base value. 752 * 753 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 754 */ getFraction(@ractionRes int id, int base, int pbase)755 public float getFraction(@FractionRes int id, int base, int pbase) { 756 final TypedValue value = obtainTempTypedValue(); 757 try { 758 mResourcesImpl.getValue(id, value, true); 759 if (value.type == TypedValue.TYPE_FRACTION) { 760 return TypedValue.complexToFraction(value.data, base, pbase); 761 } 762 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 763 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 764 } finally { 765 releaseTempTypedValue(value); 766 } 767 } 768 769 /** 770 * Return a drawable object associated with a particular resource ID. 771 * Various types of objects will be returned depending on the underlying 772 * resource -- for example, a solid color, PNG image, scalable image, etc. 773 * The Drawable API hides these implementation details. 774 * 775 * <p class="note"><strong>Note:</strong> Prior to 776 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN}, this function 777 * would not correctly retrieve the final configuration density when 778 * the resource ID passed here is an alias to another Drawable resource. 779 * This means that if the density configuration of the alias resource 780 * is different than the actual resource, the density of the returned 781 * Drawable would be incorrect, resulting in bad scaling. To work 782 * around this, you can instead manually resolve the aliased reference 783 * by using {@link #getValue(int, TypedValue, boolean)} and passing 784 * {@code true} for {@code resolveRefs}. The resulting 785 * {@link TypedValue#resourceId} value may be passed to this method.</p> 786 * 787 * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use 788 * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)} 789 * or {@link #getDrawable(int, Theme)} passing the desired theme.</p> 790 * 791 * @param id The desired resource identifier, as generated by the aapt 792 * tool. This integer encodes the package, type, and resource 793 * entry. The value 0 is an invalid identifier. 794 * @return Drawable An object that can be used to draw this resource. 795 * @throws NotFoundException Throws NotFoundException if the given ID does 796 * not exist. 797 * @see #getDrawable(int, Theme) 798 * @deprecated Use {@link #getDrawable(int, Theme)} instead. 799 */ 800 @Deprecated getDrawable(@rawableRes int id)801 public Drawable getDrawable(@DrawableRes int id) throws NotFoundException { 802 final Drawable d = getDrawable(id, null); 803 if (d != null && d.canApplyTheme()) { 804 Log.w(TAG, "Drawable " + getResourceName(id) + " has unresolved theme " 805 + "attributes! Consider using Resources.getDrawable(int, Theme) or " 806 + "Context.getDrawable(int).", new RuntimeException()); 807 } 808 return d; 809 } 810 811 /** 812 * Return a drawable object associated with a particular resource ID and 813 * styled for the specified theme. Various types of objects will be 814 * returned depending on the underlying resource -- for example, a solid 815 * color, PNG image, scalable image, etc. 816 * 817 * @param id The desired resource identifier, as generated by the aapt 818 * tool. This integer encodes the package, type, and resource 819 * entry. The value 0 is an invalid identifier. 820 * @param theme The theme used to style the drawable attributes, may be {@code null}. 821 * @return Drawable An object that can be used to draw this resource. 822 * @throws NotFoundException Throws NotFoundException if the given ID does 823 * not exist. 824 */ getDrawable(@rawableRes int id, @Nullable Theme theme)825 public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) 826 throws NotFoundException { 827 return getDrawableForDensity(id, 0, theme); 828 } 829 830 /** 831 * Return a drawable object associated with a particular resource ID for the 832 * given screen density in DPI. This will set the drawable's density to be 833 * the device's density multiplied by the ratio of actual drawable density 834 * to requested density. This allows the drawable to be scaled up to the 835 * correct size if needed. Various types of objects will be returned 836 * depending on the underlying resource -- for example, a solid color, PNG 837 * image, scalable image, etc. The Drawable API hides these implementation 838 * details. 839 * 840 * <p class="note"><strong>Note:</strong> To obtain a themed drawable, use 841 * {@link android.content.Context#getDrawable(int) Context.getDrawable(int)} 842 * or {@link #getDrawableForDensity(int, int, Theme)} passing the desired 843 * theme.</p> 844 * 845 * @param id The desired resource identifier, as generated by the aapt tool. 846 * This integer encodes the package, type, and resource entry. 847 * The value 0 is an invalid identifier. 848 * @param density the desired screen density indicated by the resource as 849 * found in {@link DisplayMetrics}. A value of 0 means to use the 850 * density returned from {@link #getConfiguration()}. 851 * This is equivalent to calling {@link #getDrawable(int)}. 852 * @return Drawable An object that can be used to draw this resource. 853 * @throws NotFoundException Throws NotFoundException if the given ID does 854 * not exist. 855 * @see #getDrawableForDensity(int, int, Theme) 856 * @deprecated Use {@link #getDrawableForDensity(int, int, Theme)} instead. 857 */ 858 @Nullable 859 @Deprecated getDrawableForDensity(@rawableRes int id, int density)860 public Drawable getDrawableForDensity(@DrawableRes int id, int density) 861 throws NotFoundException { 862 return getDrawableForDensity(id, density, null); 863 } 864 865 /** 866 * Return a drawable object associated with a particular resource ID for the 867 * given screen density in DPI and styled for the specified theme. 868 * 869 * @param id The desired resource identifier, as generated by the aapt tool. 870 * This integer encodes the package, type, and resource entry. 871 * The value 0 is an invalid identifier. 872 * @param density The desired screen density indicated by the resource as 873 * found in {@link DisplayMetrics}. A value of 0 means to use the 874 * density returned from {@link #getConfiguration()}. 875 * This is equivalent to calling {@link #getDrawable(int, Theme)}. 876 * @param theme The theme used to style the drawable attributes, may be {@code null} if the 877 * drawable cannot be decoded. 878 * @return Drawable An object that can be used to draw this resource. 879 * @throws NotFoundException Throws NotFoundException if the given ID does 880 * not exist. 881 */ 882 @Nullable getDrawableForDensity(@rawableRes int id, int density, @Nullable Theme theme)883 public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) { 884 final TypedValue value = obtainTempTypedValue(); 885 try { 886 final ResourcesImpl impl = mResourcesImpl; 887 impl.getValueForDensity(id, density, value, true); 888 return impl.loadDrawable(this, value, id, density, theme); 889 } finally { 890 releaseTempTypedValue(value); 891 } 892 } 893 894 @NonNull loadDrawable(@onNull TypedValue value, int id, int density, @Nullable Theme theme)895 Drawable loadDrawable(@NonNull TypedValue value, int id, int density, @Nullable Theme theme) 896 throws NotFoundException { 897 return mResourcesImpl.loadDrawable(this, value, id, density, theme); 898 } 899 900 /** 901 * Return a movie object associated with the particular resource ID. 902 * @param id The desired resource identifier, as generated by the aapt 903 * tool. This integer encodes the package, type, and resource 904 * entry. The value 0 is an invalid identifier. 905 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 906 * 907 */ getMovie(@awRes int id)908 public Movie getMovie(@RawRes int id) throws NotFoundException { 909 final InputStream is = openRawResource(id); 910 final Movie movie = Movie.decodeStream(is); 911 try { 912 is.close(); 913 } catch (IOException e) { 914 // No one cares. 915 } 916 return movie; 917 } 918 919 /** 920 * Returns a color integer associated with a particular resource ID. If the 921 * resource holds a complex {@link ColorStateList}, then the default color 922 * from the set is returned. 923 * 924 * @param id The desired resource identifier, as generated by the aapt 925 * tool. This integer encodes the package, type, and resource 926 * entry. The value 0 is an invalid identifier. 927 * 928 * @throws NotFoundException Throws NotFoundException if the given ID does 929 * not exist. 930 * 931 * @return A single color value in the form 0xAARRGGBB. 932 * @deprecated Use {@link #getColor(int, Theme)} instead. 933 */ 934 @ColorInt 935 @Deprecated getColor(@olorRes int id)936 public int getColor(@ColorRes int id) throws NotFoundException { 937 return getColor(id, null); 938 } 939 940 /** 941 * Returns a themed color integer associated with a particular resource ID. 942 * If the resource holds a complex {@link ColorStateList}, then the default 943 * color from the set is returned. 944 * 945 * @param id The desired resource identifier, as generated by the aapt 946 * tool. This integer encodes the package, type, and resource 947 * entry. The value 0 is an invalid identifier. 948 * @param theme The theme used to style the color attributes, may be 949 * {@code null}. 950 * 951 * @throws NotFoundException Throws NotFoundException if the given ID does 952 * not exist. 953 * 954 * @return A single color value in the form 0xAARRGGBB. 955 */ 956 @ColorInt getColor(@olorRes int id, @Nullable Theme theme)957 public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException { 958 final TypedValue value = obtainTempTypedValue(); 959 try { 960 final ResourcesImpl impl = mResourcesImpl; 961 impl.getValue(id, value, true); 962 if (value.type >= TypedValue.TYPE_FIRST_INT 963 && value.type <= TypedValue.TYPE_LAST_INT) { 964 return value.data; 965 } else if (value.type != TypedValue.TYPE_STRING) { 966 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 967 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 968 } 969 970 final ColorStateList csl = impl.loadColorStateList(this, value, id, theme); 971 return csl.getDefaultColor(); 972 } finally { 973 releaseTempTypedValue(value); 974 } 975 } 976 977 /** 978 * Returns a color state list associated with a particular resource ID. The 979 * resource may contain either a single raw color value or a complex 980 * {@link ColorStateList} holding multiple possible colors. 981 * 982 * @param id The desired resource identifier of a {@link ColorStateList}, 983 * as generated by the aapt tool. This integer encodes the 984 * package, type, and resource entry. The value 0 is an invalid 985 * identifier. 986 * 987 * @throws NotFoundException Throws NotFoundException if the given ID does 988 * not exist. 989 * 990 * @return A ColorStateList object containing either a single solid color 991 * or multiple colors that can be selected based on a state. 992 * @deprecated Use {@link #getColorStateList(int, Theme)} instead. 993 */ 994 @NonNull 995 @Deprecated getColorStateList(@olorRes int id)996 public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException { 997 final ColorStateList csl = getColorStateList(id, null); 998 if (csl != null && csl.canApplyTheme()) { 999 Log.w(TAG, "ColorStateList " + getResourceName(id) + " has " 1000 + "unresolved theme attributes! Consider using " 1001 + "Resources.getColorStateList(int, Theme) or " 1002 + "Context.getColorStateList(int).", new RuntimeException()); 1003 } 1004 return csl; 1005 } 1006 1007 /** 1008 * Returns a themed color state list associated with a particular resource 1009 * ID. The resource may contain either a single raw color value or a 1010 * complex {@link ColorStateList} holding multiple possible colors. 1011 * 1012 * @param id The desired resource identifier of a {@link ColorStateList}, 1013 * as generated by the aapt tool. This integer encodes the 1014 * package, type, and resource entry. The value 0 is an invalid 1015 * identifier. 1016 * @param theme The theme used to style the color attributes, may be 1017 * {@code null}. 1018 * 1019 * @throws NotFoundException Throws NotFoundException if the given ID does 1020 * not exist. 1021 * 1022 * @return A themed ColorStateList object containing either a single solid 1023 * color or multiple colors that can be selected based on a state. 1024 */ 1025 @NonNull getColorStateList(@olorRes int id, @Nullable Theme theme)1026 public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme) 1027 throws NotFoundException { 1028 final TypedValue value = obtainTempTypedValue(); 1029 try { 1030 final ResourcesImpl impl = mResourcesImpl; 1031 impl.getValue(id, value, true); 1032 return impl.loadColorStateList(this, value, id, theme); 1033 } finally { 1034 releaseTempTypedValue(value); 1035 } 1036 } 1037 1038 @NonNull loadColorStateList(@onNull TypedValue value, int id, @Nullable Theme theme)1039 ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme) 1040 throws NotFoundException { 1041 return mResourcesImpl.loadColorStateList(this, value, id, theme); 1042 } 1043 1044 /** 1045 * @hide 1046 */ 1047 @NonNull loadComplexColor(@onNull TypedValue value, int id, @Nullable Theme theme)1048 public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) { 1049 return mResourcesImpl.loadComplexColor(this, value, id, theme); 1050 } 1051 1052 /** 1053 * Return a boolean associated with a particular resource ID. This can be 1054 * used with any integral resource value, and will return true if it is 1055 * non-zero. 1056 * 1057 * @param id The desired resource identifier, as generated by the aapt 1058 * tool. This integer encodes the package, type, and resource 1059 * entry. The value 0 is an invalid identifier. 1060 * 1061 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1062 * 1063 * @return Returns the boolean value contained in the resource. 1064 */ getBoolean(@oolRes int id)1065 public boolean getBoolean(@BoolRes int id) throws NotFoundException { 1066 final TypedValue value = obtainTempTypedValue(); 1067 try { 1068 mResourcesImpl.getValue(id, value, true); 1069 if (value.type >= TypedValue.TYPE_FIRST_INT 1070 && value.type <= TypedValue.TYPE_LAST_INT) { 1071 return value.data != 0; 1072 } 1073 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 1074 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 1075 } finally { 1076 releaseTempTypedValue(value); 1077 } 1078 } 1079 1080 /** 1081 * Return an integer associated with a particular resource ID. 1082 * 1083 * @param id The desired resource identifier, as generated by the aapt 1084 * tool. This integer encodes the package, type, and resource 1085 * entry. The value 0 is an invalid identifier. 1086 * 1087 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1088 * 1089 * @return Returns the integer value contained in the resource. 1090 */ getInteger(@ntegerRes int id)1091 public int getInteger(@IntegerRes int id) throws NotFoundException { 1092 final TypedValue value = obtainTempTypedValue(); 1093 try { 1094 mResourcesImpl.getValue(id, value, true); 1095 if (value.type >= TypedValue.TYPE_FIRST_INT 1096 && value.type <= TypedValue.TYPE_LAST_INT) { 1097 return value.data; 1098 } 1099 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 1100 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 1101 } finally { 1102 releaseTempTypedValue(value); 1103 } 1104 } 1105 1106 /** 1107 * Retrieve a floating-point value for a particular resource ID. 1108 * 1109 * @param id The desired resource identifier, as generated by the aapt 1110 * tool. This integer encodes the package, type, and resource 1111 * entry. The value 0 is an invalid identifier. 1112 * 1113 * @return Returns the floating-point value contained in the resource. 1114 * 1115 * @throws NotFoundException Throws NotFoundException if the given ID does 1116 * not exist or is not a floating-point value. 1117 * @hide Pending API council approval. 1118 */ getFloat(int id)1119 public float getFloat(int id) { 1120 final TypedValue value = obtainTempTypedValue(); 1121 try { 1122 mResourcesImpl.getValue(id, value, true); 1123 if (value.type == TypedValue.TYPE_FLOAT) { 1124 return value.getFloat(); 1125 } 1126 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 1127 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 1128 } finally { 1129 releaseTempTypedValue(value); 1130 } 1131 } 1132 1133 /** 1134 * Return an XmlResourceParser through which you can read a view layout 1135 * description for the given resource ID. This parser has limited 1136 * functionality -- in particular, you can't change its input, and only 1137 * the high-level events are available. 1138 * 1139 * <p>This function is really a simple wrapper for calling 1140 * {@link #getXml} with a layout resource. 1141 * 1142 * @param id The desired resource identifier, as generated by the aapt 1143 * tool. This integer encodes the package, type, and resource 1144 * entry. The value 0 is an invalid identifier. 1145 * 1146 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1147 * 1148 * @return A new parser object through which you can read 1149 * the XML data. 1150 * 1151 * @see #getXml 1152 */ 1153 @NonNull getLayout(@ayoutRes int id)1154 public XmlResourceParser getLayout(@LayoutRes int id) throws NotFoundException { 1155 return loadXmlResourceParser(id, "layout"); 1156 } 1157 1158 /** 1159 * Return an XmlResourceParser through which you can read an animation 1160 * description for the given resource ID. This parser has limited 1161 * functionality -- in particular, you can't change its input, and only 1162 * the high-level events are available. 1163 * 1164 * <p>This function is really a simple wrapper for calling 1165 * {@link #getXml} with an animation resource. 1166 * 1167 * @param id The desired resource identifier, as generated by the aapt 1168 * tool. This integer encodes the package, type, and resource 1169 * entry. The value 0 is an invalid identifier. 1170 * 1171 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1172 * 1173 * @return A new parser object through which you can read 1174 * the XML data. 1175 * 1176 * @see #getXml 1177 */ 1178 @NonNull getAnimation(@nimatorRes @nimRes int id)1179 public XmlResourceParser getAnimation(@AnimatorRes @AnimRes int id) throws NotFoundException { 1180 return loadXmlResourceParser(id, "anim"); 1181 } 1182 1183 /** 1184 * Return an XmlResourceParser through which you can read a generic XML 1185 * resource for the given resource ID. 1186 * 1187 * <p>The XmlPullParser implementation returned here has some limited 1188 * functionality. In particular, you can't change its input, and only 1189 * high-level parsing events are available (since the document was 1190 * pre-parsed for you at build time, which involved merging text and 1191 * stripping comments). 1192 * 1193 * @param id The desired resource identifier, as generated by the aapt 1194 * tool. This integer encodes the package, type, and resource 1195 * entry. The value 0 is an invalid identifier. 1196 * 1197 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1198 * 1199 * @return A new parser object through which you can read 1200 * the XML data. 1201 * 1202 * @see android.util.AttributeSet 1203 */ 1204 @NonNull getXml(@mlRes int id)1205 public XmlResourceParser getXml(@XmlRes int id) throws NotFoundException { 1206 return loadXmlResourceParser(id, "xml"); 1207 } 1208 1209 /** 1210 * Open a data stream for reading a raw resource. This can only be used 1211 * with resources whose value is the name of an asset files -- that is, it can be 1212 * used to open drawable, sound, and raw resources; it will fail on string 1213 * and color resources. 1214 * 1215 * @param id The resource identifier to open, as generated by the aapt tool. 1216 * 1217 * @return InputStream Access to the resource data. 1218 * 1219 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1220 */ 1221 @NonNull openRawResource(@awRes int id)1222 public InputStream openRawResource(@RawRes int id) throws NotFoundException { 1223 final TypedValue value = obtainTempTypedValue(); 1224 try { 1225 return openRawResource(id, value); 1226 } finally { 1227 releaseTempTypedValue(value); 1228 } 1229 } 1230 1231 /** 1232 * Returns a TypedValue suitable for temporary use. The obtained TypedValue 1233 * should be released using {@link #releaseTempTypedValue(TypedValue)}. 1234 * 1235 * @return a typed value suitable for temporary use 1236 */ obtainTempTypedValue()1237 private TypedValue obtainTempTypedValue() { 1238 TypedValue tmpValue = null; 1239 synchronized (mTmpValueLock) { 1240 if (mTmpValue != null) { 1241 tmpValue = mTmpValue; 1242 mTmpValue = null; 1243 } 1244 } 1245 if (tmpValue == null) { 1246 return new TypedValue(); 1247 } 1248 return tmpValue; 1249 } 1250 1251 /** 1252 * Returns a TypedValue to the pool. After calling this method, the 1253 * specified TypedValue should no longer be accessed. 1254 * 1255 * @param value the typed value to return to the pool 1256 */ releaseTempTypedValue(TypedValue value)1257 private void releaseTempTypedValue(TypedValue value) { 1258 synchronized (mTmpValueLock) { 1259 if (mTmpValue == null) { 1260 mTmpValue = value; 1261 } 1262 } 1263 } 1264 1265 /** 1266 * Open a data stream for reading a raw resource. This can only be used 1267 * with resources whose value is the name of an asset file -- that is, it can be 1268 * used to open drawable, sound, and raw resources; it will fail on string 1269 * and color resources. 1270 * 1271 * @param id The resource identifier to open, as generated by the aapt tool. 1272 * @param value The TypedValue object to hold the resource information. 1273 * 1274 * @return InputStream Access to the resource data. 1275 * 1276 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1277 */ 1278 @NonNull openRawResource(@awRes int id, TypedValue value)1279 public InputStream openRawResource(@RawRes int id, TypedValue value) 1280 throws NotFoundException { 1281 return mResourcesImpl.openRawResource(id, value); 1282 } 1283 1284 /** 1285 * Open a file descriptor for reading a raw resource. This can only be used 1286 * with resources whose value is the name of an asset files -- that is, it can be 1287 * used to open drawable, sound, and raw resources; it will fail on string 1288 * and color resources. 1289 * 1290 * <p>This function only works for resources that are stored in the package 1291 * as uncompressed data, which typically includes things like mp3 files 1292 * and png images. 1293 * 1294 * @param id The resource identifier to open, as generated by the aapt tool. 1295 * 1296 * @return AssetFileDescriptor A new file descriptor you can use to read 1297 * the resource. This includes the file descriptor itself, as well as the 1298 * offset and length of data where the resource appears in the file. A 1299 * null is returned if the file exists but is compressed. 1300 * 1301 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1302 * 1303 */ openRawResourceFd(@awRes int id)1304 public AssetFileDescriptor openRawResourceFd(@RawRes int id) 1305 throws NotFoundException { 1306 final TypedValue value = obtainTempTypedValue(); 1307 try { 1308 return mResourcesImpl.openRawResourceFd(id, value); 1309 } finally { 1310 releaseTempTypedValue(value); 1311 } 1312 } 1313 1314 /** 1315 * Return the raw data associated with a particular resource ID. 1316 * 1317 * @param id The desired resource identifier, as generated by the aapt 1318 * tool. This integer encodes the package, type, and resource 1319 * entry. The value 0 is an invalid identifier. 1320 * @param outValue Object in which to place the resource data. 1321 * @param resolveRefs If true, a resource that is a reference to another 1322 * resource will be followed so that you receive the 1323 * actual final resource data. If false, the TypedValue 1324 * will be filled in with the reference itself. 1325 * 1326 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1327 * 1328 */ getValue(@nyRes int id, TypedValue outValue, boolean resolveRefs)1329 public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs) 1330 throws NotFoundException { 1331 mResourcesImpl.getValue(id, outValue, resolveRefs); 1332 } 1333 1334 /** 1335 * Get the raw value associated with a resource with associated density. 1336 * 1337 * @param id resource identifier 1338 * @param density density in DPI 1339 * @param resolveRefs If true, a resource that is a reference to another 1340 * resource will be followed so that you receive the actual final 1341 * resource data. If false, the TypedValue will be filled in with 1342 * the reference itself. 1343 * @throws NotFoundException Throws NotFoundException if the given ID does 1344 * not exist. 1345 * @see #getValue(String, TypedValue, boolean) 1346 */ getValueForDensity(@nyRes int id, int density, TypedValue outValue, boolean resolveRefs)1347 public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue, 1348 boolean resolveRefs) throws NotFoundException { 1349 mResourcesImpl.getValueForDensity(id, density, outValue, resolveRefs); 1350 } 1351 1352 /** 1353 * Return the raw data associated with a particular resource ID. 1354 * See getIdentifier() for information on how names are mapped to resource 1355 * IDs, and getString(int) for information on how string resources are 1356 * retrieved. 1357 * 1358 * <p>Note: use of this function is discouraged. It is much more 1359 * efficient to retrieve resources by identifier than by name. 1360 * 1361 * @param name The name of the desired resource. This is passed to 1362 * getIdentifier() with a default type of "string". 1363 * @param outValue Object in which to place the resource data. 1364 * @param resolveRefs If true, a resource that is a reference to another 1365 * resource will be followed so that you receive the 1366 * actual final resource data. If false, the TypedValue 1367 * will be filled in with the reference itself. 1368 * 1369 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1370 * 1371 */ getValue(String name, TypedValue outValue, boolean resolveRefs)1372 public void getValue(String name, TypedValue outValue, boolean resolveRefs) 1373 throws NotFoundException { 1374 mResourcesImpl.getValue(name, outValue, resolveRefs); 1375 } 1376 1377 /** 1378 * This class holds the current attribute values for a particular theme. 1379 * In other words, a Theme is a set of values for resource attributes; 1380 * these are used in conjunction with {@link TypedArray} 1381 * to resolve the final value for an attribute. 1382 * 1383 * <p>The Theme's attributes come into play in two ways: (1) a styled 1384 * attribute can explicit reference a value in the theme through the 1385 * "?themeAttribute" syntax; (2) if no value has been defined for a 1386 * particular styled attribute, as a last resort we will try to find that 1387 * attribute's value in the Theme. 1388 * 1389 * <p>You will normally use the {@link #obtainStyledAttributes} APIs to 1390 * retrieve XML attributes with style and theme information applied. 1391 */ 1392 public final class Theme { 1393 private ResourcesImpl.ThemeImpl mThemeImpl; 1394 Theme()1395 private Theme() { 1396 } 1397 setImpl(ResourcesImpl.ThemeImpl impl)1398 void setImpl(ResourcesImpl.ThemeImpl impl) { 1399 mThemeImpl = impl; 1400 } 1401 1402 /** 1403 * Place new attribute values into the theme. The style resource 1404 * specified by <var>resid</var> will be retrieved from this Theme's 1405 * resources, its values placed into the Theme object. 1406 * 1407 * <p>The semantics of this function depends on the <var>force</var> 1408 * argument: If false, only values that are not already defined in 1409 * the theme will be copied from the system resource; otherwise, if 1410 * any of the style's attributes are already defined in the theme, the 1411 * current values in the theme will be overwritten. 1412 * 1413 * @param resId The resource ID of a style resource from which to 1414 * obtain attribute values. 1415 * @param force If true, values in the style resource will always be 1416 * used in the theme; otherwise, they will only be used 1417 * if not already defined in the theme. 1418 */ applyStyle(int resId, boolean force)1419 public void applyStyle(int resId, boolean force) { 1420 mThemeImpl.applyStyle(resId, force); 1421 } 1422 1423 /** 1424 * Set this theme to hold the same contents as the theme 1425 * <var>other</var>. If both of these themes are from the same 1426 * Resources object, they will be identical after this function 1427 * returns. If they are from different Resources, only the resources 1428 * they have in common will be set in this theme. 1429 * 1430 * @param other The existing Theme to copy from. 1431 */ setTo(Theme other)1432 public void setTo(Theme other) { 1433 mThemeImpl.setTo(other.mThemeImpl); 1434 } 1435 1436 /** 1437 * Return a TypedArray holding the values defined by 1438 * <var>Theme</var> which are listed in <var>attrs</var>. 1439 * 1440 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done 1441 * with the array. 1442 * 1443 * @param attrs The desired attributes. These attribute IDs must be sorted in ascending 1444 * order. 1445 * 1446 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1447 * 1448 * @return Returns a TypedArray holding an array of the attribute values. 1449 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} 1450 * when done with it. 1451 * 1452 * @see Resources#obtainAttributes 1453 * @see #obtainStyledAttributes(int, int[]) 1454 * @see #obtainStyledAttributes(AttributeSet, int[], int, int) 1455 */ obtainStyledAttributes(@tyleableRes int[] attrs)1456 public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) { 1457 return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0); 1458 } 1459 1460 /** 1461 * Return a TypedArray holding the values defined by the style 1462 * resource <var>resid</var> which are listed in <var>attrs</var>. 1463 * 1464 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done 1465 * with the array. 1466 * 1467 * @param resId The desired style resource. 1468 * @param attrs The desired attributes in the style. These attribute IDs must be sorted in 1469 * ascending order. 1470 * 1471 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1472 * 1473 * @return Returns a TypedArray holding an array of the attribute values. 1474 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} 1475 * when done with it. 1476 * 1477 * @see Resources#obtainAttributes 1478 * @see #obtainStyledAttributes(int[]) 1479 * @see #obtainStyledAttributes(AttributeSet, int[], int, int) 1480 */ obtainStyledAttributes(@tyleRes int resId, @StyleableRes int[] attrs)1481 public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs) 1482 throws NotFoundException { 1483 return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId); 1484 } 1485 1486 /** 1487 * Return a TypedArray holding the attribute values in 1488 * <var>set</var> 1489 * that are listed in <var>attrs</var>. In addition, if the given 1490 * AttributeSet specifies a style class (through the "style" attribute), 1491 * that style will be applied on top of the base attributes it defines. 1492 * 1493 * <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done 1494 * with the array. 1495 * 1496 * <p>When determining the final value of a particular attribute, there 1497 * are four inputs that come into play:</p> 1498 * 1499 * <ol> 1500 * <li> Any attribute values in the given AttributeSet. 1501 * <li> The style resource specified in the AttributeSet (named 1502 * "style"). 1503 * <li> The default style specified by <var>defStyleAttr</var> and 1504 * <var>defStyleRes</var> 1505 * <li> The base values in this theme. 1506 * </ol> 1507 * 1508 * <p>Each of these inputs is considered in-order, with the first listed 1509 * taking precedence over the following ones. In other words, if in the 1510 * AttributeSet you have supplied <code><Button 1511 * textColor="#ff000000"></code>, then the button's text will 1512 * <em>always</em> be black, regardless of what is specified in any of 1513 * the styles. 1514 * 1515 * @param set The base set of attribute values. May be null. 1516 * @param attrs The desired attributes to be retrieved. These attribute IDs must be sorted 1517 * in ascending order. 1518 * @param defStyleAttr An attribute in the current theme that contains a 1519 * reference to a style resource that supplies 1520 * defaults values for the TypedArray. Can be 1521 * 0 to not look for defaults. 1522 * @param defStyleRes A resource identifier of a style resource that 1523 * supplies default values for the TypedArray, 1524 * used only if defStyleAttr is 0 or can not be found 1525 * in the theme. Can be 0 to not look for defaults. 1526 * 1527 * @return Returns a TypedArray holding an array of the attribute values. 1528 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} 1529 * when done with it. 1530 * 1531 * @see Resources#obtainAttributes 1532 * @see #obtainStyledAttributes(int[]) 1533 * @see #obtainStyledAttributes(int, int[]) 1534 */ obtainStyledAttributes(AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes)1535 public TypedArray obtainStyledAttributes(AttributeSet set, 1536 @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { 1537 return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes); 1538 } 1539 1540 /** 1541 * Retrieve the values for a set of attributes in the Theme. The 1542 * contents of the typed array are ultimately filled in by 1543 * {@link Resources#getValue}. 1544 * 1545 * @param values The base set of attribute values, must be equal in 1546 * length to {@code attrs}. All values must be of type 1547 * {@link TypedValue#TYPE_ATTRIBUTE}. 1548 * @param attrs The desired attributes to be retrieved. These attribute IDs must be sorted 1549 * in ascending order. 1550 * @return Returns a TypedArray holding an array of the attribute 1551 * values. Be sure to call {@link TypedArray#recycle()} 1552 * when done with it. 1553 * @hide 1554 */ 1555 @NonNull resolveAttributes(@onNull int[] values, @NonNull int[] attrs)1556 public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) { 1557 return mThemeImpl.resolveAttributes(this, values, attrs); 1558 } 1559 1560 /** 1561 * Retrieve the value of an attribute in the Theme. The contents of 1562 * <var>outValue</var> are ultimately filled in by 1563 * {@link Resources#getValue}. 1564 * 1565 * @param resid The resource identifier of the desired theme 1566 * attribute. 1567 * @param outValue Filled in with the ultimate resource value supplied 1568 * by the attribute. 1569 * @param resolveRefs If true, resource references will be walked; if 1570 * false, <var>outValue</var> may be a 1571 * TYPE_REFERENCE. In either case, it will never 1572 * be a TYPE_ATTRIBUTE. 1573 * 1574 * @return boolean Returns true if the attribute was found and 1575 * <var>outValue</var> is valid, else false. 1576 */ resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs)1577 public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) { 1578 return mThemeImpl.resolveAttribute(resid, outValue, resolveRefs); 1579 } 1580 1581 /** 1582 * Gets all of the attribute ids associated with this {@link Theme}. For debugging only. 1583 * 1584 * @return The int array containing attribute ids associated with this {@link Theme}. 1585 * @hide 1586 */ getAllAttributes()1587 public int[] getAllAttributes() { 1588 return mThemeImpl.getAllAttributes(); 1589 } 1590 1591 /** 1592 * Returns the resources to which this theme belongs. 1593 * 1594 * @return Resources to which this theme belongs. 1595 */ getResources()1596 public Resources getResources() { 1597 return Resources.this; 1598 } 1599 1600 /** 1601 * Return a drawable object associated with a particular resource ID 1602 * and styled for the Theme. 1603 * 1604 * @param id The desired resource identifier, as generated by the aapt 1605 * tool. This integer encodes the package, type, and resource 1606 * entry. The value 0 is an invalid identifier. 1607 * @return Drawable An object that can be used to draw this resource. 1608 * @throws NotFoundException Throws NotFoundException if the given ID 1609 * does not exist. 1610 */ getDrawable(@rawableRes int id)1611 public Drawable getDrawable(@DrawableRes int id) throws NotFoundException { 1612 return Resources.this.getDrawable(id, this); 1613 } 1614 1615 /** 1616 * Returns a bit mask of configuration changes that will impact this 1617 * theme (and thus require completely reloading it). 1618 * 1619 * @return a bit mask of configuration changes, as defined by 1620 * {@link ActivityInfo} 1621 * @see ActivityInfo 1622 */ getChangingConfigurations()1623 public @Config int getChangingConfigurations() { 1624 return mThemeImpl.getChangingConfigurations(); 1625 } 1626 1627 /** 1628 * Print contents of this theme out to the log. For debugging only. 1629 * 1630 * @param priority The log priority to use. 1631 * @param tag The log tag to use. 1632 * @param prefix Text to prefix each line printed. 1633 */ dump(int priority, String tag, String prefix)1634 public void dump(int priority, String tag, String prefix) { 1635 mThemeImpl.dump(priority, tag, prefix); 1636 } 1637 1638 // Needed by layoutlib. getNativeTheme()1639 /*package*/ long getNativeTheme() { 1640 return mThemeImpl.getNativeTheme(); 1641 } 1642 getAppliedStyleResId()1643 /*package*/ int getAppliedStyleResId() { 1644 return mThemeImpl.getAppliedStyleResId(); 1645 } 1646 1647 /** 1648 * @hide 1649 */ getKey()1650 public ThemeKey getKey() { 1651 return mThemeImpl.getKey(); 1652 } 1653 getResourceNameFromHexString(String hexString)1654 private String getResourceNameFromHexString(String hexString) { 1655 return getResourceName(Integer.parseInt(hexString, 16)); 1656 } 1657 1658 /** 1659 * Parses {@link #getKey()} and returns a String array that holds pairs of 1660 * adjacent Theme data: resource name followed by whether or not it was 1661 * forced, as specified by {@link #applyStyle(int, boolean)}. 1662 * 1663 * @hide 1664 */ 1665 @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true) getTheme()1666 public String[] getTheme() { 1667 return mThemeImpl.getTheme(); 1668 } 1669 1670 /** @hide */ encode(@onNull ViewHierarchyEncoder encoder)1671 public void encode(@NonNull ViewHierarchyEncoder encoder) { 1672 encoder.beginObject(this); 1673 final String[] properties = getTheme(); 1674 for (int i = 0; i < properties.length; i += 2) { 1675 encoder.addProperty(properties[i], properties[i+1]); 1676 } 1677 encoder.endObject(); 1678 } 1679 1680 /** 1681 * Rebases the theme against the parent Resource object's current 1682 * configuration by re-applying the styles passed to 1683 * {@link #applyStyle(int, boolean)}. 1684 * 1685 * @hide 1686 */ rebase()1687 public void rebase() { 1688 mThemeImpl.rebase(); 1689 } 1690 } 1691 1692 static class ThemeKey implements Cloneable { 1693 int[] mResId; 1694 boolean[] mForce; 1695 int mCount; 1696 1697 private int mHashCode = 0; 1698 append(int resId, boolean force)1699 public void append(int resId, boolean force) { 1700 if (mResId == null) { 1701 mResId = new int[4]; 1702 } 1703 1704 if (mForce == null) { 1705 mForce = new boolean[4]; 1706 } 1707 1708 mResId = GrowingArrayUtils.append(mResId, mCount, resId); 1709 mForce = GrowingArrayUtils.append(mForce, mCount, force); 1710 mCount++; 1711 1712 mHashCode = 31 * (31 * mHashCode + resId) + (force ? 1 : 0); 1713 } 1714 1715 /** 1716 * Sets up this key as a deep copy of another key. 1717 * 1718 * @param other the key to deep copy into this key 1719 */ setTo(ThemeKey other)1720 public void setTo(ThemeKey other) { 1721 mResId = other.mResId == null ? null : other.mResId.clone(); 1722 mForce = other.mForce == null ? null : other.mForce.clone(); 1723 mCount = other.mCount; 1724 } 1725 1726 @Override hashCode()1727 public int hashCode() { 1728 return mHashCode; 1729 } 1730 1731 @Override equals(Object o)1732 public boolean equals(Object o) { 1733 if (this == o) { 1734 return true; 1735 } 1736 1737 if (o == null || getClass() != o.getClass() || hashCode() != o.hashCode()) { 1738 return false; 1739 } 1740 1741 final ThemeKey t = (ThemeKey) o; 1742 if (mCount != t.mCount) { 1743 return false; 1744 } 1745 1746 final int N = mCount; 1747 for (int i = 0; i < N; i++) { 1748 if (mResId[i] != t.mResId[i] || mForce[i] != t.mForce[i]) { 1749 return false; 1750 } 1751 } 1752 1753 return true; 1754 } 1755 1756 /** 1757 * @return a shallow copy of this key 1758 */ 1759 @Override clone()1760 public ThemeKey clone() { 1761 final ThemeKey other = new ThemeKey(); 1762 other.mResId = mResId; 1763 other.mForce = mForce; 1764 other.mCount = mCount; 1765 other.mHashCode = mHashCode; 1766 return other; 1767 } 1768 } 1769 1770 /** 1771 * Generate a new Theme object for this set of Resources. It initially 1772 * starts out empty. 1773 * 1774 * @return Theme The newly created Theme container. 1775 */ newTheme()1776 public final Theme newTheme() { 1777 Theme theme = new Theme(); 1778 theme.setImpl(mResourcesImpl.newThemeImpl()); 1779 synchronized (mThemeRefs) { 1780 mThemeRefs.add(new WeakReference<>(theme)); 1781 1782 // Clean up references to garbage collected themes 1783 if (mThemeRefs.size() > mThemeRefsNextFlushSize) { 1784 mThemeRefs.removeIf(ref -> ref.get() == null); 1785 mThemeRefsNextFlushSize = Math.max(MIN_THEME_REFS_FLUSH_SIZE, 1786 2 * mThemeRefs.size()); 1787 } 1788 } 1789 return theme; 1790 } 1791 1792 /** 1793 * Retrieve a set of basic attribute values from an AttributeSet, not 1794 * performing styling of them using a theme and/or style resources. 1795 * 1796 * @param set The current attribute values to retrieve. 1797 * @param attrs The specific attributes to be retrieved. These attribute IDs must be sorted in 1798 * ascending order. 1799 * @return Returns a TypedArray holding an array of the attribute values. 1800 * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} 1801 * when done with it. 1802 * 1803 * @see Theme#obtainStyledAttributes(AttributeSet, int[], int, int) 1804 */ obtainAttributes(AttributeSet set, @StyleableRes int[] attrs)1805 public TypedArray obtainAttributes(AttributeSet set, @StyleableRes int[] attrs) { 1806 int len = attrs.length; 1807 TypedArray array = TypedArray.obtain(this, len); 1808 1809 // XXX note that for now we only work with compiled XML files. 1810 // To support generic XML files we will need to manually parse 1811 // out the attributes from the XML file (applying type information 1812 // contained in the resources and such). 1813 XmlBlock.Parser parser = (XmlBlock.Parser)set; 1814 mResourcesImpl.getAssets().retrieveAttributes(parser, attrs, array.mData, array.mIndices); 1815 1816 array.mXml = parser; 1817 1818 return array; 1819 } 1820 1821 /** 1822 * Store the newly updated configuration. 1823 * 1824 * @deprecated See {@link android.content.Context#createConfigurationContext(Configuration)}. 1825 */ 1826 @Deprecated updateConfiguration(Configuration config, DisplayMetrics metrics)1827 public void updateConfiguration(Configuration config, DisplayMetrics metrics) { 1828 updateConfiguration(config, metrics, null); 1829 } 1830 1831 /** 1832 * @hide 1833 */ updateConfiguration(Configuration config, DisplayMetrics metrics, CompatibilityInfo compat)1834 public void updateConfiguration(Configuration config, DisplayMetrics metrics, 1835 CompatibilityInfo compat) { 1836 mResourcesImpl.updateConfiguration(config, metrics, compat); 1837 } 1838 1839 /** 1840 * Update the system resources configuration if they have previously 1841 * been initialized. 1842 * 1843 * @hide 1844 */ updateSystemConfiguration(Configuration config, DisplayMetrics metrics, CompatibilityInfo compat)1845 public static void updateSystemConfiguration(Configuration config, DisplayMetrics metrics, 1846 CompatibilityInfo compat) { 1847 if (mSystem != null) { 1848 mSystem.updateConfiguration(config, metrics, compat); 1849 //Log.i(TAG, "Updated system resources " + mSystem 1850 // + ": " + mSystem.getConfiguration()); 1851 } 1852 } 1853 1854 /** 1855 * Return the current display metrics that are in effect for this resource 1856 * object. The returned object should be treated as read-only. 1857 * 1858 * @return The resource's current display metrics. 1859 */ getDisplayMetrics()1860 public DisplayMetrics getDisplayMetrics() { 1861 return mResourcesImpl.getDisplayMetrics(); 1862 } 1863 1864 /** @hide */ getDisplayAdjustments()1865 public DisplayAdjustments getDisplayAdjustments() { 1866 return mResourcesImpl.getDisplayAdjustments(); 1867 } 1868 1869 /** 1870 * Return the current configuration that is in effect for this resource 1871 * object. The returned object should be treated as read-only. 1872 * 1873 * @return The resource's current configuration. 1874 */ getConfiguration()1875 public Configuration getConfiguration() { 1876 return mResourcesImpl.getConfiguration(); 1877 } 1878 1879 /** @hide */ getSizeConfigurations()1880 public Configuration[] getSizeConfigurations() { 1881 return mResourcesImpl.getSizeConfigurations(); 1882 } 1883 1884 /** 1885 * Return the compatibility mode information for the application. 1886 * The returned object should be treated as read-only. 1887 * 1888 * @return compatibility info. 1889 * @hide 1890 */ getCompatibilityInfo()1891 public CompatibilityInfo getCompatibilityInfo() { 1892 return mResourcesImpl.getCompatibilityInfo(); 1893 } 1894 1895 /** 1896 * This is just for testing. 1897 * @hide 1898 */ 1899 @VisibleForTesting setCompatibilityInfo(CompatibilityInfo ci)1900 public void setCompatibilityInfo(CompatibilityInfo ci) { 1901 if (ci != null) { 1902 mResourcesImpl.updateConfiguration(null, null, ci); 1903 } 1904 } 1905 1906 /** 1907 * Return a resource identifier for the given resource name. A fully 1908 * qualified resource name is of the form "package:type/entry". The first 1909 * two components (package and type) are optional if defType and 1910 * defPackage, respectively, are specified here. 1911 * 1912 * <p>Note: use of this function is discouraged. It is much more 1913 * efficient to retrieve resources by identifier than by name. 1914 * 1915 * @param name The name of the desired resource. 1916 * @param defType Optional default resource type to find, if "type/" is 1917 * not included in the name. Can be null to require an 1918 * explicit type. 1919 * @param defPackage Optional default package to find, if "package:" is 1920 * not included in the name. Can be null to require an 1921 * explicit package. 1922 * 1923 * @return int The associated resource identifier. Returns 0 if no such 1924 * resource was found. (0 is not a valid resource ID.) 1925 */ getIdentifier(String name, String defType, String defPackage)1926 public int getIdentifier(String name, String defType, String defPackage) { 1927 return mResourcesImpl.getIdentifier(name, defType, defPackage); 1928 } 1929 1930 /** 1931 * Return true if given resource identifier includes a package. 1932 * 1933 * @hide 1934 */ resourceHasPackage(@nyRes int resid)1935 public static boolean resourceHasPackage(@AnyRes int resid) { 1936 return (resid >>> 24) != 0; 1937 } 1938 1939 /** 1940 * Return the full name for a given resource identifier. This name is 1941 * a single string of the form "package:type/entry". 1942 * 1943 * @param resid The resource identifier whose name is to be retrieved. 1944 * 1945 * @return A string holding the name of the resource. 1946 * 1947 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1948 * 1949 * @see #getResourcePackageName 1950 * @see #getResourceTypeName 1951 * @see #getResourceEntryName 1952 */ getResourceName(@nyRes int resid)1953 public String getResourceName(@AnyRes int resid) throws NotFoundException { 1954 return mResourcesImpl.getResourceName(resid); 1955 } 1956 1957 /** 1958 * Return the package name for a given resource identifier. 1959 * 1960 * @param resid The resource identifier whose package name is to be 1961 * retrieved. 1962 * 1963 * @return A string holding the package name of the resource. 1964 * 1965 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1966 * 1967 * @see #getResourceName 1968 */ getResourcePackageName(@nyRes int resid)1969 public String getResourcePackageName(@AnyRes int resid) throws NotFoundException { 1970 return mResourcesImpl.getResourcePackageName(resid); 1971 } 1972 1973 /** 1974 * Return the type name for a given resource identifier. 1975 * 1976 * @param resid The resource identifier whose type name is to be 1977 * retrieved. 1978 * 1979 * @return A string holding the type name of the resource. 1980 * 1981 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1982 * 1983 * @see #getResourceName 1984 */ getResourceTypeName(@nyRes int resid)1985 public String getResourceTypeName(@AnyRes int resid) throws NotFoundException { 1986 return mResourcesImpl.getResourceTypeName(resid); 1987 } 1988 1989 /** 1990 * Return the entry name for a given resource identifier. 1991 * 1992 * @param resid The resource identifier whose entry name is to be 1993 * retrieved. 1994 * 1995 * @return A string holding the entry name of the resource. 1996 * 1997 * @throws NotFoundException Throws NotFoundException if the given ID does not exist. 1998 * 1999 * @see #getResourceName 2000 */ getResourceEntryName(@nyRes int resid)2001 public String getResourceEntryName(@AnyRes int resid) throws NotFoundException { 2002 return mResourcesImpl.getResourceEntryName(resid); 2003 } 2004 2005 /** 2006 * Parse a series of {@link android.R.styleable#Extra <extra>} tags from 2007 * an XML file. You call this when you are at the parent tag of the 2008 * extra tags, and it will return once all of the child tags have been parsed. 2009 * This will call {@link #parseBundleExtra} for each extra tag encountered. 2010 * 2011 * @param parser The parser from which to retrieve the extras. 2012 * @param outBundle A Bundle in which to place all parsed extras. 2013 * @throws XmlPullParserException 2014 * @throws IOException 2015 */ parseBundleExtras(XmlResourceParser parser, Bundle outBundle)2016 public void parseBundleExtras(XmlResourceParser parser, Bundle outBundle) 2017 throws XmlPullParserException, IOException { 2018 int outerDepth = parser.getDepth(); 2019 int type; 2020 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 2021 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 2022 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 2023 continue; 2024 } 2025 2026 String nodeName = parser.getName(); 2027 if (nodeName.equals("extra")) { 2028 parseBundleExtra("extra", parser, outBundle); 2029 XmlUtils.skipCurrentTag(parser); 2030 2031 } else { 2032 XmlUtils.skipCurrentTag(parser); 2033 } 2034 } 2035 } 2036 2037 /** 2038 * Parse a name/value pair out of an XML tag holding that data. The 2039 * AttributeSet must be holding the data defined by 2040 * {@link android.R.styleable#Extra}. The following value types are supported: 2041 * <ul> 2042 * <li> {@link TypedValue#TYPE_STRING}: 2043 * {@link Bundle#putCharSequence Bundle.putCharSequence()} 2044 * <li> {@link TypedValue#TYPE_INT_BOOLEAN}: 2045 * {@link Bundle#putCharSequence Bundle.putBoolean()} 2046 * <li> {@link TypedValue#TYPE_FIRST_INT}-{@link TypedValue#TYPE_LAST_INT}: 2047 * {@link Bundle#putCharSequence Bundle.putBoolean()} 2048 * <li> {@link TypedValue#TYPE_FLOAT}: 2049 * {@link Bundle#putCharSequence Bundle.putFloat()} 2050 * </ul> 2051 * 2052 * @param tagName The name of the tag these attributes come from; this is 2053 * only used for reporting error messages. 2054 * @param attrs The attributes from which to retrieve the name/value pair. 2055 * @param outBundle The Bundle in which to place the parsed value. 2056 * @throws XmlPullParserException If the attributes are not valid. 2057 */ parseBundleExtra(String tagName, AttributeSet attrs, Bundle outBundle)2058 public void parseBundleExtra(String tagName, AttributeSet attrs, 2059 Bundle outBundle) throws XmlPullParserException { 2060 TypedArray sa = obtainAttributes(attrs, 2061 com.android.internal.R.styleable.Extra); 2062 2063 String name = sa.getString( 2064 com.android.internal.R.styleable.Extra_name); 2065 if (name == null) { 2066 sa.recycle(); 2067 throw new XmlPullParserException("<" + tagName 2068 + "> requires an android:name attribute at " 2069 + attrs.getPositionDescription()); 2070 } 2071 2072 TypedValue v = sa.peekValue( 2073 com.android.internal.R.styleable.Extra_value); 2074 if (v != null) { 2075 if (v.type == TypedValue.TYPE_STRING) { 2076 CharSequence cs = v.coerceToString(); 2077 outBundle.putCharSequence(name, cs); 2078 } else if (v.type == TypedValue.TYPE_INT_BOOLEAN) { 2079 outBundle.putBoolean(name, v.data != 0); 2080 } else if (v.type >= TypedValue.TYPE_FIRST_INT 2081 && v.type <= TypedValue.TYPE_LAST_INT) { 2082 outBundle.putInt(name, v.data); 2083 } else if (v.type == TypedValue.TYPE_FLOAT) { 2084 outBundle.putFloat(name, v.getFloat()); 2085 } else { 2086 sa.recycle(); 2087 throw new XmlPullParserException("<" + tagName 2088 + "> only supports string, integer, float, color, and boolean at " 2089 + attrs.getPositionDescription()); 2090 } 2091 } else { 2092 sa.recycle(); 2093 throw new XmlPullParserException("<" + tagName 2094 + "> requires an android:value or android:resource attribute at " 2095 + attrs.getPositionDescription()); 2096 } 2097 2098 sa.recycle(); 2099 } 2100 2101 /** 2102 * Retrieve underlying AssetManager storage for these resources. 2103 */ getAssets()2104 public final AssetManager getAssets() { 2105 return mResourcesImpl.getAssets(); 2106 } 2107 2108 /** 2109 * Call this to remove all cached loaded layout resources from the 2110 * Resources object. Only intended for use with performance testing 2111 * tools. 2112 */ flushLayoutCache()2113 public final void flushLayoutCache() { 2114 mResourcesImpl.flushLayoutCache(); 2115 } 2116 2117 /** 2118 * Start preloading of resource data using this Resources object. Only 2119 * for use by the zygote process for loading common system resources. 2120 * {@hide} 2121 */ startPreloading()2122 public final void startPreloading() { 2123 mResourcesImpl.startPreloading(); 2124 } 2125 2126 /** 2127 * Called by zygote when it is done preloading resources, to change back 2128 * to normal Resources operation. 2129 */ finishPreloading()2130 public final void finishPreloading() { 2131 mResourcesImpl.finishPreloading(); 2132 } 2133 2134 /** 2135 * @hide 2136 */ getPreloadedDrawables()2137 public LongSparseArray<ConstantState> getPreloadedDrawables() { 2138 return mResourcesImpl.getPreloadedDrawables(); 2139 } 2140 2141 /** 2142 * Loads an XML parser for the specified file. 2143 * 2144 * @param id the resource identifier for the file 2145 * @param type the type of resource (used for logging) 2146 * @return a parser for the specified XML file 2147 * @throws NotFoundException if the file could not be loaded 2148 */ 2149 @NonNull loadXmlResourceParser(@nyRes int id, @NonNull String type)2150 XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type) 2151 throws NotFoundException { 2152 final TypedValue value = obtainTempTypedValue(); 2153 try { 2154 final ResourcesImpl impl = mResourcesImpl; 2155 impl.getValue(id, value, true); 2156 if (value.type == TypedValue.TYPE_STRING) { 2157 return impl.loadXmlResourceParser(value.string.toString(), id, 2158 value.assetCookie, type); 2159 } 2160 throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id) 2161 + " type #0x" + Integer.toHexString(value.type) + " is not valid"); 2162 } finally { 2163 releaseTempTypedValue(value); 2164 } 2165 } 2166 2167 /** 2168 * Loads an XML parser for the specified file. 2169 * 2170 * @param file the path for the XML file to parse 2171 * @param id the resource identifier for the file 2172 * @param assetCookie the asset cookie for the file 2173 * @param type the type of resource (used for logging) 2174 * @return a parser for the specified XML file 2175 * @throws NotFoundException if the file could not be loaded 2176 */ 2177 @NonNull loadXmlResourceParser(String file, int id, int assetCookie, String type)2178 XmlResourceParser loadXmlResourceParser(String file, int id, int assetCookie, 2179 String type) throws NotFoundException { 2180 return mResourcesImpl.loadXmlResourceParser(file, id, assetCookie, type); 2181 } 2182 2183 /** 2184 * Called by ConfigurationBoundResourceCacheTest. 2185 * @hide 2186 */ 2187 @VisibleForTesting calcConfigChanges(Configuration config)2188 public int calcConfigChanges(Configuration config) { 2189 return mResourcesImpl.calcConfigChanges(config); 2190 } 2191 2192 /** 2193 * Obtains styled attributes from the theme, if available, or unstyled 2194 * resources if the theme is null. 2195 * 2196 * @hide 2197 */ obtainAttributes( Resources res, Theme theme, AttributeSet set, int[] attrs)2198 public static TypedArray obtainAttributes( 2199 Resources res, Theme theme, AttributeSet set, int[] attrs) { 2200 if (theme == null) { 2201 return res.obtainAttributes(set, attrs); 2202 } 2203 return theme.obtainStyledAttributes(set, attrs, 0, 0); 2204 } 2205 } 2206