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.annotation.AnyRes; 20 import android.annotation.ArrayRes; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.StringRes; 24 import android.content.pm.ActivityInfo; 25 import android.content.res.Configuration.NativeConfig; 26 import android.os.ParcelFileDescriptor; 27 import android.util.Log; 28 import android.util.SparseArray; 29 import android.util.TypedValue; 30 31 import dalvik.annotation.optimization.FastNative; 32 33 import java.io.FileNotFoundException; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.util.HashMap; 37 38 /** 39 * Provides access to an application's raw asset files; see {@link Resources} 40 * for the way most applications will want to retrieve their resource data. 41 * This class presents a lower-level API that allows you to open and read raw 42 * files that have been bundled with the application as a simple stream of 43 * bytes. 44 */ 45 public final class AssetManager implements AutoCloseable { 46 /* modes used when opening an asset */ 47 48 /** 49 * Mode for {@link #open(String, int)}: no specific information about how 50 * data will be accessed. 51 */ 52 public static final int ACCESS_UNKNOWN = 0; 53 /** 54 * Mode for {@link #open(String, int)}: Read chunks, and seek forward and 55 * backward. 56 */ 57 public static final int ACCESS_RANDOM = 1; 58 /** 59 * Mode for {@link #open(String, int)}: Read sequentially, with an 60 * occasional forward seek. 61 */ 62 public static final int ACCESS_STREAMING = 2; 63 /** 64 * Mode for {@link #open(String, int)}: Attempt to load contents into 65 * memory, for fast small reads. 66 */ 67 public static final int ACCESS_BUFFER = 3; 68 69 private static final String TAG = "AssetManager"; 70 private static final boolean localLOGV = false || false; 71 72 private static final boolean DEBUG_REFS = false; 73 74 private static final Object sSync = new Object(); 75 /*package*/ static AssetManager sSystem = null; 76 77 private final TypedValue mValue = new TypedValue(); 78 private final long[] mOffsets = new long[2]; 79 80 // For communication with native code. 81 private long mObject; 82 83 private StringBlock mStringBlocks[] = null; 84 85 private int mNumRefs = 1; 86 private boolean mOpen = true; 87 private HashMap<Long, RuntimeException> mRefStacks; 88 89 /** 90 * Create a new AssetManager containing only the basic system assets. 91 * Applications will not generally use this method, instead retrieving the 92 * appropriate asset manager with {@link Resources#getAssets}. Not for 93 * use by applications. 94 * {@hide} 95 */ AssetManager()96 public AssetManager() { 97 synchronized (this) { 98 if (DEBUG_REFS) { 99 mNumRefs = 0; 100 incRefsLocked(this.hashCode()); 101 } 102 init(false); 103 if (localLOGV) Log.v(TAG, "New asset manager: " + this); 104 ensureSystemAssets(); 105 } 106 } 107 ensureSystemAssets()108 private static void ensureSystemAssets() { 109 synchronized (sSync) { 110 if (sSystem == null) { 111 AssetManager system = new AssetManager(true); 112 system.makeStringBlocks(null); 113 sSystem = system; 114 } 115 } 116 } 117 AssetManager(boolean isSystem)118 private AssetManager(boolean isSystem) { 119 if (DEBUG_REFS) { 120 synchronized (this) { 121 mNumRefs = 0; 122 incRefsLocked(this.hashCode()); 123 } 124 } 125 init(true); 126 if (localLOGV) Log.v(TAG, "New asset manager: " + this); 127 } 128 129 /** 130 * Return a global shared asset manager that provides access to only 131 * system assets (no application assets). 132 * {@hide} 133 */ getSystem()134 public static AssetManager getSystem() { 135 ensureSystemAssets(); 136 return sSystem; 137 } 138 139 /** 140 * Close this asset manager. 141 */ close()142 public void close() { 143 synchronized(this) { 144 //System.out.println("Release: num=" + mNumRefs 145 // + ", released=" + mReleased); 146 if (mOpen) { 147 mOpen = false; 148 decRefsLocked(this.hashCode()); 149 } 150 } 151 } 152 153 /** 154 * Retrieves the string value associated with a particular resource 155 * identifier for the current configuration. 156 * 157 * @param resId the resource identifier to load 158 * @return the string value, or {@code null} 159 */ 160 @Nullable getResourceText(@tringRes int resId)161 final CharSequence getResourceText(@StringRes int resId) { 162 synchronized (this) { 163 final TypedValue outValue = mValue; 164 if (getResourceValue(resId, 0, outValue, true)) { 165 return outValue.coerceToString(); 166 } 167 return null; 168 } 169 } 170 171 /** 172 * Retrieves the string value associated with a particular resource 173 * identifier for the current configuration. 174 * 175 * @param resId the resource identifier to load 176 * @param bagEntryId 177 * @return the string value, or {@code null} 178 */ 179 @Nullable getResourceBagText(@tringRes int resId, int bagEntryId)180 final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) { 181 synchronized (this) { 182 final TypedValue outValue = mValue; 183 final int block = loadResourceBagValue(resId, bagEntryId, outValue, true); 184 if (block < 0) { 185 return null; 186 } 187 188 // Convert the changing configurations flags populated by native code. 189 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 190 outValue.changingConfigurations); 191 192 if (outValue.type == TypedValue.TYPE_STRING) { 193 return mStringBlocks[block].get(outValue.data); 194 } 195 return outValue.coerceToString(); 196 } 197 } 198 199 /** 200 * Retrieves the string array associated with a particular resource 201 * identifier for the current configuration. 202 * 203 * @param resId the resource identifier of the string array 204 * @return the string array, or {@code null} 205 */ 206 @Nullable getResourceStringArray(@rrayRes int resId)207 final String[] getResourceStringArray(@ArrayRes int resId) { 208 return getArrayStringResource(resId); 209 } 210 211 /** 212 * Populates {@code outValue} with the data associated a particular 213 * resource identifier for the current configuration. 214 * 215 * @param resId the resource identifier to load 216 * @param densityDpi the density bucket for which to load the resource 217 * @param outValue the typed value in which to put the data 218 * @param resolveRefs {@code true} to resolve references, {@code false} 219 * to leave them unresolved 220 * @return {@code true} if the data was loaded into {@code outValue}, 221 * {@code false} otherwise 222 */ getResourceValue(@nyRes int resId, int densityDpi, @NonNull TypedValue outValue, boolean resolveRefs)223 final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue, 224 boolean resolveRefs) { 225 synchronized (this) { 226 final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs); 227 if (block < 0) { 228 return false; 229 } 230 231 // Convert the changing configurations flags populated by native code. 232 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 233 outValue.changingConfigurations); 234 235 if (outValue.type == TypedValue.TYPE_STRING) { 236 outValue.string = mStringBlocks[block].get(outValue.data); 237 } 238 return true; 239 } 240 } 241 242 /** 243 * Retrieve the text array associated with a particular resource 244 * identifier. 245 * 246 * @param resId the resource id of the string array 247 */ getResourceTextArray(@rrayRes int resId)248 final @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) { 249 synchronized (this) { 250 final int[] rawInfoArray = getArrayStringInfo(resId); 251 if (rawInfoArray == null) { 252 return null; 253 } 254 final int rawInfoArrayLen = rawInfoArray.length; 255 final int infoArrayLen = rawInfoArrayLen / 2; 256 int block; 257 int index; 258 final CharSequence[] retArray = new CharSequence[infoArrayLen]; 259 for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) { 260 block = rawInfoArray[i]; 261 index = rawInfoArray[i + 1]; 262 retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null; 263 } 264 return retArray; 265 } 266 } 267 268 /** 269 * Populates {@code outValue} with the data associated with a particular 270 * resource identifier for the current configuration. Resolves theme 271 * attributes against the specified theme. 272 * 273 * @param theme the native pointer of the theme 274 * @param resId the resource identifier to load 275 * @param outValue the typed value in which to put the data 276 * @param resolveRefs {@code true} to resolve references, {@code false} 277 * to leave them unresolved 278 * @return {@code true} if the data was loaded into {@code outValue}, 279 * {@code false} otherwise 280 */ getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, boolean resolveRefs)281 final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, 282 boolean resolveRefs) { 283 final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs); 284 if (block < 0) { 285 return false; 286 } 287 288 // Convert the changing configurations flags populated by native code. 289 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 290 outValue.changingConfigurations); 291 292 if (outValue.type == TypedValue.TYPE_STRING) { 293 final StringBlock[] blocks = ensureStringBlocks(); 294 outValue.string = blocks[block].get(outValue.data); 295 } 296 return true; 297 } 298 299 /** 300 * Ensures the string blocks are loaded. 301 * 302 * @return the string blocks 303 */ 304 @NonNull ensureStringBlocks()305 final StringBlock[] ensureStringBlocks() { 306 synchronized (this) { 307 if (mStringBlocks == null) { 308 makeStringBlocks(sSystem.mStringBlocks); 309 } 310 return mStringBlocks; 311 } 312 } 313 makeStringBlocks(StringBlock[] seed)314 /*package*/ final void makeStringBlocks(StringBlock[] seed) { 315 final int seedNum = (seed != null) ? seed.length : 0; 316 final int num = getStringBlockCount(); 317 mStringBlocks = new StringBlock[num]; 318 if (localLOGV) Log.v(TAG, "Making string blocks for " + this 319 + ": " + num); 320 for (int i=0; i<num; i++) { 321 if (i < seedNum) { 322 mStringBlocks[i] = seed[i]; 323 } else { 324 mStringBlocks[i] = new StringBlock(getNativeStringBlock(i), true); 325 } 326 } 327 } 328 getPooledStringForCookie(int cookie, int id)329 /*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) { 330 synchronized (this) { 331 // Cookies map to string blocks starting at 1. 332 return mStringBlocks[cookie - 1].get(id); 333 } 334 } 335 336 /** 337 * Open an asset using ACCESS_STREAMING mode. This provides access to 338 * files that have been bundled with an application as assets -- that is, 339 * files placed in to the "assets" directory. 340 * 341 * @param fileName The name of the asset to open. This name can be 342 * hierarchical. 343 * 344 * @see #open(String, int) 345 * @see #list 346 */ open(String fileName)347 public final InputStream open(String fileName) throws IOException { 348 return open(fileName, ACCESS_STREAMING); 349 } 350 351 /** 352 * Open an asset using an explicit access mode, returning an InputStream to 353 * read its contents. This provides access to files that have been bundled 354 * with an application as assets -- that is, files placed in to the 355 * "assets" directory. 356 * 357 * @param fileName The name of the asset to open. This name can be 358 * hierarchical. 359 * @param accessMode Desired access mode for retrieving the data. 360 * 361 * @see #ACCESS_UNKNOWN 362 * @see #ACCESS_STREAMING 363 * @see #ACCESS_RANDOM 364 * @see #ACCESS_BUFFER 365 * @see #open(String) 366 * @see #list 367 */ open(String fileName, int accessMode)368 public final InputStream open(String fileName, int accessMode) 369 throws IOException { 370 synchronized (this) { 371 if (!mOpen) { 372 throw new RuntimeException("Assetmanager has been closed"); 373 } 374 long asset = openAsset(fileName, accessMode); 375 if (asset != 0) { 376 AssetInputStream res = new AssetInputStream(asset); 377 incRefsLocked(res.hashCode()); 378 return res; 379 } 380 } 381 throw new FileNotFoundException("Asset file: " + fileName); 382 } 383 openFd(String fileName)384 public final AssetFileDescriptor openFd(String fileName) 385 throws IOException { 386 synchronized (this) { 387 if (!mOpen) { 388 throw new RuntimeException("Assetmanager has been closed"); 389 } 390 ParcelFileDescriptor pfd = openAssetFd(fileName, mOffsets); 391 if (pfd != null) { 392 return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); 393 } 394 } 395 throw new FileNotFoundException("Asset file: " + fileName); 396 } 397 398 /** 399 * Return a String array of all the assets at the given path. 400 * 401 * @param path A relative path within the assets, i.e., "docs/home.html". 402 * 403 * @return String[] Array of strings, one for each asset. These file 404 * names are relative to 'path'. You can open the file by 405 * concatenating 'path' and a name in the returned string (via 406 * File) and passing that to open(). 407 * 408 * @see #open 409 */ list(String path)410 public native final String[] list(String path) 411 throws IOException; 412 413 /** 414 * {@hide} 415 * Open a non-asset file as an asset using ACCESS_STREAMING mode. This 416 * provides direct access to all of the files included in an application 417 * package (not only its assets). Applications should not normally use 418 * this. 419 * 420 * @see #open(String) 421 */ openNonAsset(String fileName)422 public final InputStream openNonAsset(String fileName) throws IOException { 423 return openNonAsset(0, fileName, ACCESS_STREAMING); 424 } 425 426 /** 427 * {@hide} 428 * Open a non-asset file as an asset using a specific access mode. This 429 * provides direct access to all of the files included in an application 430 * package (not only its assets). Applications should not normally use 431 * this. 432 * 433 * @see #open(String, int) 434 */ openNonAsset(String fileName, int accessMode)435 public final InputStream openNonAsset(String fileName, int accessMode) 436 throws IOException { 437 return openNonAsset(0, fileName, accessMode); 438 } 439 440 /** 441 * {@hide} 442 * Open a non-asset in a specified package. Not for use by applications. 443 * 444 * @param cookie Identifier of the package to be opened. 445 * @param fileName Name of the asset to retrieve. 446 */ openNonAsset(int cookie, String fileName)447 public final InputStream openNonAsset(int cookie, String fileName) 448 throws IOException { 449 return openNonAsset(cookie, fileName, ACCESS_STREAMING); 450 } 451 452 /** 453 * {@hide} 454 * Open a non-asset in a specified package. Not for use by applications. 455 * 456 * @param cookie Identifier of the package to be opened. 457 * @param fileName Name of the asset to retrieve. 458 * @param accessMode Desired access mode for retrieving the data. 459 */ openNonAsset(int cookie, String fileName, int accessMode)460 public final InputStream openNonAsset(int cookie, String fileName, int accessMode) 461 throws IOException { 462 synchronized (this) { 463 if (!mOpen) { 464 throw new RuntimeException("Assetmanager has been closed"); 465 } 466 long asset = openNonAssetNative(cookie, fileName, accessMode); 467 if (asset != 0) { 468 AssetInputStream res = new AssetInputStream(asset); 469 incRefsLocked(res.hashCode()); 470 return res; 471 } 472 } 473 throw new FileNotFoundException("Asset absolute file: " + fileName); 474 } 475 openNonAssetFd(String fileName)476 public final AssetFileDescriptor openNonAssetFd(String fileName) 477 throws IOException { 478 return openNonAssetFd(0, fileName); 479 } 480 openNonAssetFd(int cookie, String fileName)481 public final AssetFileDescriptor openNonAssetFd(int cookie, 482 String fileName) throws IOException { 483 synchronized (this) { 484 if (!mOpen) { 485 throw new RuntimeException("Assetmanager has been closed"); 486 } 487 ParcelFileDescriptor pfd = openNonAssetFdNative(cookie, 488 fileName, mOffsets); 489 if (pfd != null) { 490 return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); 491 } 492 } 493 throw new FileNotFoundException("Asset absolute file: " + fileName); 494 } 495 496 /** 497 * Retrieve a parser for a compiled XML file. 498 * 499 * @param fileName The name of the file to retrieve. 500 */ openXmlResourceParser(String fileName)501 public final XmlResourceParser openXmlResourceParser(String fileName) 502 throws IOException { 503 return openXmlResourceParser(0, fileName); 504 } 505 506 /** 507 * Retrieve a parser for a compiled XML file. 508 * 509 * @param cookie Identifier of the package to be opened. 510 * @param fileName The name of the file to retrieve. 511 */ openXmlResourceParser(int cookie, String fileName)512 public final XmlResourceParser openXmlResourceParser(int cookie, 513 String fileName) throws IOException { 514 XmlBlock block = openXmlBlockAsset(cookie, fileName); 515 XmlResourceParser rp = block.newParser(); 516 block.close(); 517 return rp; 518 } 519 520 /** 521 * {@hide} 522 * Retrieve a non-asset as a compiled XML file. Not for use by 523 * applications. 524 * 525 * @param fileName The name of the file to retrieve. 526 */ openXmlBlockAsset(String fileName)527 /*package*/ final XmlBlock openXmlBlockAsset(String fileName) 528 throws IOException { 529 return openXmlBlockAsset(0, fileName); 530 } 531 532 /** 533 * {@hide} 534 * Retrieve a non-asset as a compiled XML file. Not for use by 535 * applications. 536 * 537 * @param cookie Identifier of the package to be opened. 538 * @param fileName Name of the asset to retrieve. 539 */ openXmlBlockAsset(int cookie, String fileName)540 /*package*/ final XmlBlock openXmlBlockAsset(int cookie, String fileName) 541 throws IOException { 542 synchronized (this) { 543 if (!mOpen) { 544 throw new RuntimeException("Assetmanager has been closed"); 545 } 546 long xmlBlock = openXmlAssetNative(cookie, fileName); 547 if (xmlBlock != 0) { 548 XmlBlock res = new XmlBlock(this, xmlBlock); 549 incRefsLocked(res.hashCode()); 550 return res; 551 } 552 } 553 throw new FileNotFoundException("Asset XML file: " + fileName); 554 } 555 xmlBlockGone(int id)556 /*package*/ void xmlBlockGone(int id) { 557 synchronized (this) { 558 decRefsLocked(id); 559 } 560 } 561 createTheme()562 /*package*/ final long createTheme() { 563 synchronized (this) { 564 if (!mOpen) { 565 throw new RuntimeException("Assetmanager has been closed"); 566 } 567 long res = newTheme(); 568 incRefsLocked(res); 569 return res; 570 } 571 } 572 releaseTheme(long theme)573 /*package*/ final void releaseTheme(long theme) { 574 synchronized (this) { 575 deleteTheme(theme); 576 decRefsLocked(theme); 577 } 578 } 579 finalize()580 protected void finalize() throws Throwable { 581 try { 582 if (DEBUG_REFS && mNumRefs != 0) { 583 Log.w(TAG, "AssetManager " + this 584 + " finalized with non-zero refs: " + mNumRefs); 585 if (mRefStacks != null) { 586 for (RuntimeException e : mRefStacks.values()) { 587 Log.w(TAG, "Reference from here", e); 588 } 589 } 590 } 591 destroy(); 592 } finally { 593 super.finalize(); 594 } 595 } 596 597 public final class AssetInputStream extends InputStream { 598 /** 599 * @hide 600 */ getAssetInt()601 public final int getAssetInt() { 602 throw new UnsupportedOperationException(); 603 } 604 /** 605 * @hide 606 */ getNativeAsset()607 public final long getNativeAsset() { 608 return mAsset; 609 } AssetInputStream(long asset)610 private AssetInputStream(long asset) 611 { 612 mAsset = asset; 613 mLength = getAssetLength(asset); 614 } read()615 public final int read() throws IOException { 616 return readAssetChar(mAsset); 617 } markSupported()618 public final boolean markSupported() { 619 return true; 620 } available()621 public final int available() throws IOException { 622 long len = getAssetRemainingLength(mAsset); 623 return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)len; 624 } close()625 public final void close() throws IOException { 626 synchronized (AssetManager.this) { 627 if (mAsset != 0) { 628 destroyAsset(mAsset); 629 mAsset = 0; 630 decRefsLocked(hashCode()); 631 } 632 } 633 } mark(int readlimit)634 public final void mark(int readlimit) { 635 mMarkPos = seekAsset(mAsset, 0, 0); 636 } reset()637 public final void reset() throws IOException { 638 seekAsset(mAsset, mMarkPos, -1); 639 } read(byte[] b)640 public final int read(byte[] b) throws IOException { 641 return readAsset(mAsset, b, 0, b.length); 642 } read(byte[] b, int off, int len)643 public final int read(byte[] b, int off, int len) throws IOException { 644 return readAsset(mAsset, b, off, len); 645 } skip(long n)646 public final long skip(long n) throws IOException { 647 long pos = seekAsset(mAsset, 0, 0); 648 if ((pos+n) > mLength) { 649 n = mLength-pos; 650 } 651 if (n > 0) { 652 seekAsset(mAsset, n, 0); 653 } 654 return n; 655 } 656 finalize()657 protected void finalize() throws Throwable 658 { 659 close(); 660 } 661 662 private long mAsset; 663 private long mLength; 664 private long mMarkPos; 665 } 666 667 /** 668 * Add an additional set of assets to the asset manager. This can be 669 * either a directory or ZIP file. Not for use by applications. Returns 670 * the cookie of the added asset, or 0 on failure. 671 * {@hide} 672 */ addAssetPath(String path)673 public final int addAssetPath(String path) { 674 return addAssetPathInternal(path, false); 675 } 676 677 /** 678 * Add an application assets to the asset manager and loading it as shared library. 679 * This can be either a directory or ZIP file. Not for use by applications. Returns 680 * the cookie of the added asset, or 0 on failure. 681 * {@hide} 682 */ addAssetPathAsSharedLibrary(String path)683 public final int addAssetPathAsSharedLibrary(String path) { 684 return addAssetPathInternal(path, true); 685 } 686 addAssetPathInternal(String path, boolean appAsLib)687 private final int addAssetPathInternal(String path, boolean appAsLib) { 688 synchronized (this) { 689 int res = addAssetPathNative(path, appAsLib); 690 makeStringBlocks(mStringBlocks); 691 return res; 692 } 693 } 694 addAssetPathNative(String path, boolean appAsLib)695 private native final int addAssetPathNative(String path, boolean appAsLib); 696 697 /** 698 * Add a set of assets to overlay an already added set of assets. 699 * 700 * This is only intended for application resources. System wide resources 701 * are handled before any Java code is executed. 702 * 703 * {@hide} 704 */ 705 addOverlayPath(String idmapPath)706 public final int addOverlayPath(String idmapPath) { 707 synchronized (this) { 708 int res = addOverlayPathNative(idmapPath); 709 makeStringBlocks(mStringBlocks); 710 return res; 711 } 712 } 713 714 /** 715 * See addOverlayPath. 716 * 717 * {@hide} 718 */ addOverlayPathNative(String idmapPath)719 public native final int addOverlayPathNative(String idmapPath); 720 721 /** 722 * Add multiple sets of assets to the asset manager at once. See 723 * {@link #addAssetPath(String)} for more information. Returns array of 724 * cookies for each added asset with 0 indicating failure, or null if 725 * the input array of paths is null. 726 * {@hide} 727 */ addAssetPaths(String[] paths)728 public final int[] addAssetPaths(String[] paths) { 729 if (paths == null) { 730 return null; 731 } 732 733 int[] cookies = new int[paths.length]; 734 for (int i = 0; i < paths.length; i++) { 735 cookies[i] = addAssetPath(paths[i]); 736 } 737 738 return cookies; 739 } 740 741 /** 742 * Determine whether the state in this asset manager is up-to-date with 743 * the files on the filesystem. If false is returned, you need to 744 * instantiate a new AssetManager class to see the new data. 745 * {@hide} 746 */ isUpToDate()747 public native final boolean isUpToDate(); 748 749 /** 750 * Get the locales that this asset manager contains data for. 751 * 752 * <p>On SDK 21 (Android 5.0: Lollipop) and above, Locale strings are valid 753 * <a href="https://tools.ietf.org/html/bcp47">BCP-47</a> language tags and can be 754 * parsed using {@link java.util.Locale#forLanguageTag(String)}. 755 * 756 * <p>On SDK 20 (Android 4.4W: Kitkat for watches) and below, locale strings 757 * are of the form {@code ll_CC} where {@code ll} is a two letter language code, 758 * and {@code CC} is a two letter country code. 759 */ getLocales()760 public native final String[] getLocales(); 761 762 /** 763 * Same as getLocales(), except that locales that are only provided by the system (i.e. those 764 * present in framework-res.apk or its overlays) will not be listed. 765 * 766 * For example, if the "system" assets support English, French, and German, and the additional 767 * assets support Cherokee and French, getLocales() would return 768 * [Cherokee, English, French, German], while getNonSystemLocales() would return 769 * [Cherokee, French]. 770 * {@hide} 771 */ getNonSystemLocales()772 public native final String[] getNonSystemLocales(); 773 774 /** {@hide} */ getSizeConfigurations()775 public native final Configuration[] getSizeConfigurations(); 776 777 /** 778 * Change the configuation used when retrieving resources. Not for use by 779 * applications. 780 * {@hide} 781 */ setConfiguration(int mcc, int mnc, String locale, int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion)782 public native final void setConfiguration(int mcc, int mnc, String locale, 783 int orientation, int touchscreen, int density, int keyboard, 784 int keyboardHidden, int navigation, int screenWidth, int screenHeight, 785 int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, 786 int screenLayout, int uiMode, int colorMode, int majorVersion); 787 788 /** 789 * Retrieve the resource identifier for the given resource name. 790 */ getResourceIdentifier(String name, String defType, String defPackage)791 /*package*/ native final int getResourceIdentifier(String name, 792 String defType, 793 String defPackage); 794 getResourceName(int resid)795 /*package*/ native final String getResourceName(int resid); getResourcePackageName(int resid)796 /*package*/ native final String getResourcePackageName(int resid); getResourceTypeName(int resid)797 /*package*/ native final String getResourceTypeName(int resid); getResourceEntryName(int resid)798 /*package*/ native final String getResourceEntryName(int resid); 799 openAsset(String fileName, int accessMode)800 private native final long openAsset(String fileName, int accessMode); openAssetFd(String fileName, long[] outOffsets)801 private final native ParcelFileDescriptor openAssetFd(String fileName, 802 long[] outOffsets) throws IOException; openNonAssetNative(int cookie, String fileName, int accessMode)803 private native final long openNonAssetNative(int cookie, String fileName, 804 int accessMode); openNonAssetFdNative(int cookie, String fileName, long[] outOffsets)805 private native ParcelFileDescriptor openNonAssetFdNative(int cookie, 806 String fileName, long[] outOffsets) throws IOException; destroyAsset(long asset)807 private native final void destroyAsset(long asset); readAssetChar(long asset)808 private native final int readAssetChar(long asset); readAsset(long asset, byte[] b, int off, int len)809 private native final int readAsset(long asset, byte[] b, int off, int len); seekAsset(long asset, long offset, int whence)810 private native final long seekAsset(long asset, long offset, int whence); getAssetLength(long asset)811 private native final long getAssetLength(long asset); getAssetRemainingLength(long asset)812 private native final long getAssetRemainingLength(long asset); 813 814 /** Returns true if the resource was found, filling in mRetStringBlock and 815 * mRetData. */ loadResourceValue(int ident, short density, TypedValue outValue, boolean resolve)816 private native final int loadResourceValue(int ident, short density, TypedValue outValue, 817 boolean resolve); 818 /** Returns true if the resource was found, filling in mRetStringBlock and 819 * mRetData. */ loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue, boolean resolve)820 private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue, 821 boolean resolve); 822 /*package*/ static final int STYLE_NUM_ENTRIES = 6; 823 /*package*/ static final int STYLE_TYPE = 0; 824 /*package*/ static final int STYLE_DATA = 1; 825 /*package*/ static final int STYLE_ASSET_COOKIE = 2; 826 /*package*/ static final int STYLE_RESOURCE_ID = 3; 827 828 /* Offset within typed data array for native changingConfigurations. */ 829 static final int STYLE_CHANGING_CONFIGURATIONS = 4; 830 831 /*package*/ static final int STYLE_DENSITY = 5; applyStyle(long theme, int defStyleAttr, int defStyleRes, long xmlParser, int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress)832 /*package*/ native static final void applyStyle(long theme, 833 int defStyleAttr, int defStyleRes, long xmlParser, 834 int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress); resolveAttrs(long theme, int defStyleAttr, int defStyleRes, int[] inValues, int[] inAttrs, int[] outValues, int[] outIndices)835 /*package*/ native static final boolean resolveAttrs(long theme, 836 int defStyleAttr, int defStyleRes, int[] inValues, 837 int[] inAttrs, int[] outValues, int[] outIndices); retrieveAttributes( long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices)838 /*package*/ native final boolean retrieveAttributes( 839 long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices); getArraySize(int resource)840 /*package*/ native final int getArraySize(int resource); retrieveArray(int resource, int[] outValues)841 /*package*/ native final int retrieveArray(int resource, int[] outValues); getStringBlockCount()842 private native final int getStringBlockCount(); getNativeStringBlock(int block)843 private native final long getNativeStringBlock(int block); 844 845 /** 846 * {@hide} 847 */ getCookieName(int cookie)848 public native final String getCookieName(int cookie); 849 850 /** 851 * {@hide} 852 */ getAssignedPackageIdentifiers()853 public native final SparseArray<String> getAssignedPackageIdentifiers(); 854 855 /** 856 * {@hide} 857 */ getGlobalAssetCount()858 public native static final int getGlobalAssetCount(); 859 860 /** 861 * {@hide} 862 */ getAssetAllocations()863 public native static final String getAssetAllocations(); 864 865 /** 866 * {@hide} 867 */ getGlobalAssetManagerCount()868 public native static final int getGlobalAssetManagerCount(); 869 newTheme()870 private native final long newTheme(); deleteTheme(long theme)871 private native final void deleteTheme(long theme); applyThemeStyle(long theme, int styleRes, boolean force)872 /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force); copyTheme(long dest, long source)873 /*package*/ native static final void copyTheme(long dest, long source); clearTheme(long theme)874 /*package*/ native static final void clearTheme(long theme); loadThemeAttributeValue(long theme, int ident, TypedValue outValue, boolean resolve)875 /*package*/ native static final int loadThemeAttributeValue(long theme, int ident, 876 TypedValue outValue, 877 boolean resolve); dumpTheme(long theme, int priority, String tag, String prefix)878 /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix); getThemeChangingConfigurations(long theme)879 /*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme); 880 openXmlAssetNative(int cookie, String fileName)881 private native final long openXmlAssetNative(int cookie, String fileName); 882 getArrayStringResource(int arrayRes)883 private native final String[] getArrayStringResource(int arrayRes); getArrayStringInfo(int arrayRes)884 private native final int[] getArrayStringInfo(int arrayRes); getArrayIntResource(int arrayRes)885 /*package*/ native final int[] getArrayIntResource(int arrayRes); getStyleAttributes(int themeRes)886 /*package*/ native final int[] getStyleAttributes(int themeRes); 887 init(boolean isSystem)888 private native final void init(boolean isSystem); destroy()889 private native final void destroy(); 890 incRefsLocked(long id)891 private final void incRefsLocked(long id) { 892 if (DEBUG_REFS) { 893 if (mRefStacks == null) { 894 mRefStacks = new HashMap<Long, RuntimeException>(); 895 } 896 RuntimeException ex = new RuntimeException(); 897 ex.fillInStackTrace(); 898 mRefStacks.put(id, ex); 899 } 900 mNumRefs++; 901 } 902 decRefsLocked(long id)903 private final void decRefsLocked(long id) { 904 if (DEBUG_REFS && mRefStacks != null) { 905 mRefStacks.remove(id); 906 } 907 mNumRefs--; 908 //System.out.println("Dec streams: mNumRefs=" + mNumRefs 909 // + " mReleased=" + mReleased); 910 if (mNumRefs == 0) { 911 destroy(); 912 } 913 } 914 } 915