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