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 592 synchronized (this) { 593 if (mObject != 0) { 594 destroy(); 595 mObject = 0; 596 } 597 } 598 } finally { 599 super.finalize(); 600 } 601 } 602 603 public final class AssetInputStream extends InputStream { 604 /** 605 * @hide 606 */ getAssetInt()607 public final int getAssetInt() { 608 throw new UnsupportedOperationException(); 609 } 610 /** 611 * @hide 612 */ getNativeAsset()613 public final long getNativeAsset() { 614 return mAsset; 615 } AssetInputStream(long asset)616 private AssetInputStream(long asset) 617 { 618 mAsset = asset; 619 mLength = getAssetLength(asset); 620 } read()621 public final int read() throws IOException { 622 return readAssetChar(mAsset); 623 } markSupported()624 public final boolean markSupported() { 625 return true; 626 } available()627 public final int available() throws IOException { 628 long len = getAssetRemainingLength(mAsset); 629 return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)len; 630 } close()631 public final void close() throws IOException { 632 synchronized (AssetManager.this) { 633 if (mAsset != 0) { 634 destroyAsset(mAsset); 635 mAsset = 0; 636 decRefsLocked(hashCode()); 637 } 638 } 639 } mark(int readlimit)640 public final void mark(int readlimit) { 641 mMarkPos = seekAsset(mAsset, 0, 0); 642 } reset()643 public final void reset() throws IOException { 644 seekAsset(mAsset, mMarkPos, -1); 645 } read(byte[] b)646 public final int read(byte[] b) throws IOException { 647 return readAsset(mAsset, b, 0, b.length); 648 } read(byte[] b, int off, int len)649 public final int read(byte[] b, int off, int len) throws IOException { 650 return readAsset(mAsset, b, off, len); 651 } skip(long n)652 public final long skip(long n) throws IOException { 653 long pos = seekAsset(mAsset, 0, 0); 654 if ((pos+n) > mLength) { 655 n = mLength-pos; 656 } 657 if (n > 0) { 658 seekAsset(mAsset, n, 0); 659 } 660 return n; 661 } 662 finalize()663 protected void finalize() throws Throwable 664 { 665 close(); 666 } 667 668 private long mAsset; 669 private long mLength; 670 private long mMarkPos; 671 } 672 673 /** 674 * Add an additional set of assets to the asset manager. This can be 675 * either a directory or ZIP file. Not for use by applications. Returns 676 * the cookie of the added asset, or 0 on failure. 677 * {@hide} 678 */ addAssetPath(String path)679 public final int addAssetPath(String path) { 680 return addAssetPathInternal(path, false); 681 } 682 683 /** 684 * Add an application assets to the asset manager and loading it as shared library. 685 * This can be either a directory or ZIP file. Not for use by applications. Returns 686 * the cookie of the added asset, or 0 on failure. 687 * {@hide} 688 */ addAssetPathAsSharedLibrary(String path)689 public final int addAssetPathAsSharedLibrary(String path) { 690 return addAssetPathInternal(path, true); 691 } 692 addAssetPathInternal(String path, boolean appAsLib)693 private final int addAssetPathInternal(String path, boolean appAsLib) { 694 synchronized (this) { 695 int res = addAssetPathNative(path, appAsLib); 696 makeStringBlocks(mStringBlocks); 697 return res; 698 } 699 } 700 addAssetPathNative(String path, boolean appAsLib)701 private native final int addAssetPathNative(String path, boolean appAsLib); 702 703 /** 704 * Add a set of assets to overlay an already added set of assets. 705 * 706 * This is only intended for application resources. System wide resources 707 * are handled before any Java code is executed. 708 * 709 * {@hide} 710 */ 711 addOverlayPath(String idmapPath)712 public final int addOverlayPath(String idmapPath) { 713 synchronized (this) { 714 int res = addOverlayPathNative(idmapPath); 715 makeStringBlocks(mStringBlocks); 716 return res; 717 } 718 } 719 720 /** 721 * See addOverlayPath. 722 * 723 * {@hide} 724 */ addOverlayPathNative(String idmapPath)725 public native final int addOverlayPathNative(String idmapPath); 726 727 /** 728 * Add multiple sets of assets to the asset manager at once. See 729 * {@link #addAssetPath(String)} for more information. Returns array of 730 * cookies for each added asset with 0 indicating failure, or null if 731 * the input array of paths is null. 732 * {@hide} 733 */ addAssetPaths(String[] paths)734 public final int[] addAssetPaths(String[] paths) { 735 if (paths == null) { 736 return null; 737 } 738 739 int[] cookies = new int[paths.length]; 740 for (int i = 0; i < paths.length; i++) { 741 cookies[i] = addAssetPath(paths[i]); 742 } 743 744 return cookies; 745 } 746 747 /** 748 * Determine whether the state in this asset manager is up-to-date with 749 * the files on the filesystem. If false is returned, you need to 750 * instantiate a new AssetManager class to see the new data. 751 * {@hide} 752 */ isUpToDate()753 public native final boolean isUpToDate(); 754 755 /** 756 * Get the locales that this asset manager contains data for. 757 * 758 * <p>On SDK 21 (Android 5.0: Lollipop) and above, Locale strings are valid 759 * <a href="https://tools.ietf.org/html/bcp47">BCP-47</a> language tags and can be 760 * parsed using {@link java.util.Locale#forLanguageTag(String)}. 761 * 762 * <p>On SDK 20 (Android 4.4W: Kitkat for watches) and below, locale strings 763 * are of the form {@code ll_CC} where {@code ll} is a two letter language code, 764 * and {@code CC} is a two letter country code. 765 */ getLocales()766 public native final String[] getLocales(); 767 768 /** 769 * Same as getLocales(), except that locales that are only provided by the system (i.e. those 770 * present in framework-res.apk or its overlays) will not be listed. 771 * 772 * For example, if the "system" assets support English, French, and German, and the additional 773 * assets support Cherokee and French, getLocales() would return 774 * [Cherokee, English, French, German], while getNonSystemLocales() would return 775 * [Cherokee, French]. 776 * {@hide} 777 */ getNonSystemLocales()778 public native final String[] getNonSystemLocales(); 779 780 /** {@hide} */ getSizeConfigurations()781 public native final Configuration[] getSizeConfigurations(); 782 783 /** 784 * Change the configuation used when retrieving resources. Not for use by 785 * applications. 786 * {@hide} 787 */ 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)788 public native final void setConfiguration(int mcc, int mnc, String locale, 789 int orientation, int touchscreen, int density, int keyboard, 790 int keyboardHidden, int navigation, int screenWidth, int screenHeight, 791 int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, 792 int screenLayout, int uiMode, int colorMode, int majorVersion); 793 794 /** 795 * Retrieve the resource identifier for the given resource name. 796 */ getResourceIdentifier(String name, String defType, String defPackage)797 /*package*/ native final int getResourceIdentifier(String name, 798 String defType, 799 String defPackage); 800 getResourceName(int resid)801 /*package*/ native final String getResourceName(int resid); getResourcePackageName(int resid)802 /*package*/ native final String getResourcePackageName(int resid); getResourceTypeName(int resid)803 /*package*/ native final String getResourceTypeName(int resid); getResourceEntryName(int resid)804 /*package*/ native final String getResourceEntryName(int resid); 805 openAsset(String fileName, int accessMode)806 private native final long openAsset(String fileName, int accessMode); openAssetFd(String fileName, long[] outOffsets)807 private final native ParcelFileDescriptor openAssetFd(String fileName, 808 long[] outOffsets) throws IOException; openNonAssetNative(int cookie, String fileName, int accessMode)809 private native final long openNonAssetNative(int cookie, String fileName, 810 int accessMode); openNonAssetFdNative(int cookie, String fileName, long[] outOffsets)811 private native ParcelFileDescriptor openNonAssetFdNative(int cookie, 812 String fileName, long[] outOffsets) throws IOException; destroyAsset(long asset)813 private native final void destroyAsset(long asset); readAssetChar(long asset)814 private native final int readAssetChar(long asset); readAsset(long asset, byte[] b, int off, int len)815 private native final int readAsset(long asset, byte[] b, int off, int len); seekAsset(long asset, long offset, int whence)816 private native final long seekAsset(long asset, long offset, int whence); getAssetLength(long asset)817 private native final long getAssetLength(long asset); getAssetRemainingLength(long asset)818 private native final long getAssetRemainingLength(long asset); 819 820 /** Returns true if the resource was found, filling in mRetStringBlock and 821 * mRetData. */ loadResourceValue(int ident, short density, TypedValue outValue, boolean resolve)822 private native final int loadResourceValue(int ident, short density, TypedValue outValue, 823 boolean resolve); 824 /** Returns true if the resource was found, filling in mRetStringBlock and 825 * mRetData. */ loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue, boolean resolve)826 private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue, 827 boolean resolve); 828 /*package*/ static final int STYLE_NUM_ENTRIES = 6; 829 /*package*/ static final int STYLE_TYPE = 0; 830 /*package*/ static final int STYLE_DATA = 1; 831 /*package*/ static final int STYLE_ASSET_COOKIE = 2; 832 /*package*/ static final int STYLE_RESOURCE_ID = 3; 833 834 /* Offset within typed data array for native changingConfigurations. */ 835 static final int STYLE_CHANGING_CONFIGURATIONS = 4; 836 837 /*package*/ static final int STYLE_DENSITY = 5; applyStyle(long theme, int defStyleAttr, int defStyleRes, long xmlParser, int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress)838 /*package*/ native static final void applyStyle(long theme, 839 int defStyleAttr, int defStyleRes, long xmlParser, 840 int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress); resolveAttrs(long theme, int defStyleAttr, int defStyleRes, int[] inValues, int[] inAttrs, int[] outValues, int[] outIndices)841 /*package*/ native static final boolean resolveAttrs(long theme, 842 int defStyleAttr, int defStyleRes, int[] inValues, 843 int[] inAttrs, int[] outValues, int[] outIndices); retrieveAttributes( long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices)844 /*package*/ native final boolean retrieveAttributes( 845 long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices); getArraySize(int resource)846 /*package*/ native final int getArraySize(int resource); retrieveArray(int resource, int[] outValues)847 /*package*/ native final int retrieveArray(int resource, int[] outValues); getStringBlockCount()848 private native final int getStringBlockCount(); getNativeStringBlock(int block)849 private native final long getNativeStringBlock(int block); 850 851 /** 852 * {@hide} 853 */ getCookieName(int cookie)854 public native final String getCookieName(int cookie); 855 856 /** 857 * {@hide} 858 */ getAssignedPackageIdentifiers()859 public native final SparseArray<String> getAssignedPackageIdentifiers(); 860 861 /** 862 * {@hide} 863 */ getGlobalAssetCount()864 public native static final int getGlobalAssetCount(); 865 866 /** 867 * {@hide} 868 */ getAssetAllocations()869 public native static final String getAssetAllocations(); 870 871 /** 872 * {@hide} 873 */ getGlobalAssetManagerCount()874 public native static final int getGlobalAssetManagerCount(); 875 newTheme()876 private native final long newTheme(); deleteTheme(long theme)877 private native final void deleteTheme(long theme); applyThemeStyle(long theme, int styleRes, boolean force)878 /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force); copyTheme(long dest, long source)879 /*package*/ native static final void copyTheme(long dest, long source); clearTheme(long theme)880 /*package*/ native static final void clearTheme(long theme); loadThemeAttributeValue(long theme, int ident, TypedValue outValue, boolean resolve)881 /*package*/ native static final int loadThemeAttributeValue(long theme, int ident, 882 TypedValue outValue, 883 boolean resolve); dumpTheme(long theme, int priority, String tag, String prefix)884 /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix); getThemeChangingConfigurations(long theme)885 /*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme); 886 openXmlAssetNative(int cookie, String fileName)887 private native final long openXmlAssetNative(int cookie, String fileName); 888 getArrayStringResource(int arrayRes)889 private native final String[] getArrayStringResource(int arrayRes); getArrayStringInfo(int arrayRes)890 private native final int[] getArrayStringInfo(int arrayRes); getArrayIntResource(int arrayRes)891 /*package*/ native final int[] getArrayIntResource(int arrayRes); getStyleAttributes(int themeRes)892 /*package*/ native final int[] getStyleAttributes(int themeRes); 893 init(boolean isSystem)894 private native final void init(boolean isSystem); destroy()895 private native final void destroy(); 896 incRefsLocked(long id)897 private final void incRefsLocked(long id) { 898 if (DEBUG_REFS) { 899 if (mRefStacks == null) { 900 mRefStacks = new HashMap<Long, RuntimeException>(); 901 } 902 RuntimeException ex = new RuntimeException(); 903 ex.fillInStackTrace(); 904 mRefStacks.put(id, ex); 905 } 906 mNumRefs++; 907 } 908 decRefsLocked(long id)909 private final void decRefsLocked(long id) { 910 if (DEBUG_REFS && mRefStacks != null) { 911 mRefStacks.remove(id); 912 } 913 mNumRefs--; 914 //System.out.println("Dec streams: mNumRefs=" + mNumRefs 915 // + " mReleased=" + mReleased); 916 if (mNumRefs == 0 && mObject != 0) { 917 destroy(); 918 mObject = 0; 919 } 920 } 921 } 922