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