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 static android.content.res.Resources.ID_NULL; 20 import static android.app.ResourcesManager.ApkKey; 21 22 import android.annotation.AnyRes; 23 import android.annotation.ArrayRes; 24 import android.annotation.AttrRes; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.StringRes; 28 import android.annotation.StyleRes; 29 import android.annotation.TestApi; 30 import android.app.ResourcesManager; 31 import android.compat.annotation.UnsupportedAppUsage; 32 import android.content.pm.ActivityInfo; 33 import android.content.res.Configuration.NativeConfig; 34 import android.content.res.loader.ResourcesLoader; 35 import android.os.Build; 36 import android.os.ParcelFileDescriptor; 37 import android.util.ArrayMap; 38 import android.util.ArraySet; 39 import android.util.Log; 40 import android.util.SparseArray; 41 import android.util.TypedValue; 42 43 import com.android.internal.annotations.GuardedBy; 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.internal.content.om.OverlayConfig; 46 47 import java.io.FileDescriptor; 48 import java.io.FileNotFoundException; 49 import java.io.IOException; 50 import java.io.InputStream; 51 import java.io.PrintWriter; 52 import java.lang.ref.Reference; 53 import java.util.ArrayList; 54 import java.util.Arrays; 55 import java.util.Collections; 56 import java.util.HashMap; 57 import java.util.List; 58 import java.util.Locale; 59 import java.util.Map; 60 import java.util.Objects; 61 62 /** 63 * Provides access to an application's raw asset files; see {@link Resources} 64 * for the way most applications will want to retrieve their resource data. 65 * This class presents a lower-level API that allows you to open and read raw 66 * files that have been bundled with the application as a simple stream of 67 * bytes. 68 */ 69 public final class AssetManager implements AutoCloseable { 70 private static final String TAG = "AssetManager"; 71 private static final boolean DEBUG_REFS = false; 72 73 private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk"; 74 75 private static final Object sSync = new Object(); 76 77 private static final ApkAssets[] sEmptyApkAssets = new ApkAssets[0]; 78 79 // Not private for LayoutLib's BridgeAssetManager. 80 @UnsupportedAppUsage 81 @GuardedBy("sSync") static AssetManager sSystem = null; 82 83 @GuardedBy("sSync") private static ApkAssets[] sSystemApkAssets = new ApkAssets[0]; 84 @GuardedBy("sSync") private static ArraySet<ApkAssets> sSystemApkAssetsSet; 85 86 /** 87 * Cookie value to use when the actual cookie is unknown. This value tells the system to search 88 * all the ApkAssets for the asset. 89 * @hide 90 */ 91 public static final int COOKIE_UNKNOWN = -1; 92 93 /** 94 * Mode for {@link #open(String, int)}: no specific information about how 95 * data will be accessed. 96 */ 97 public static final int ACCESS_UNKNOWN = 0; 98 /** 99 * Mode for {@link #open(String, int)}: Read chunks, and seek forward and 100 * backward. 101 */ 102 public static final int ACCESS_RANDOM = 1; 103 /** 104 * Mode for {@link #open(String, int)}: Read sequentially, with an 105 * occasional forward seek. 106 */ 107 public static final int ACCESS_STREAMING = 2; 108 /** 109 * Mode for {@link #open(String, int)}: Attempt to load contents into 110 * memory, for fast small reads. 111 */ 112 public static final int ACCESS_BUFFER = 3; 113 114 @GuardedBy("this") private final TypedValue mValue = new TypedValue(); 115 @GuardedBy("this") private final long[] mOffsets = new long[2]; 116 117 // Pointer to native implementation, stuffed inside a long. 118 @UnsupportedAppUsage 119 @GuardedBy("this") private long mObject; 120 121 // The loaded asset paths. 122 @GuardedBy("this") private ApkAssets[] mApkAssets; 123 124 // Debug/reference counting implementation. 125 @GuardedBy("this") private boolean mOpen = true; 126 @GuardedBy("this") private int mNumRefs = 1; 127 @GuardedBy("this") private HashMap<Long, RuntimeException> mRefStacks; 128 129 private ResourcesLoader[] mLoaders; 130 131 /** 132 * A Builder class that helps create an AssetManager with only a single invocation of 133 * {@link AssetManager#setApkAssets(ApkAssets[], boolean)}. Without using this builder, 134 * AssetManager must ensure there are system ApkAssets loaded at all times, which when combined 135 * with the user's call to add additional ApkAssets, results in multiple calls to 136 * {@link AssetManager#setApkAssets(ApkAssets[], boolean)}. 137 * @hide 138 */ 139 public static class Builder { 140 private ArrayList<ApkAssets> mUserApkAssets = new ArrayList<>(); 141 private ArrayList<ResourcesLoader> mLoaders = new ArrayList<>(); 142 143 private boolean mNoInit = false; 144 addApkAssets(ApkAssets apkAssets)145 public Builder addApkAssets(ApkAssets apkAssets) { 146 mUserApkAssets.add(apkAssets); 147 return this; 148 } 149 addLoader(ResourcesLoader loader)150 public Builder addLoader(ResourcesLoader loader) { 151 mLoaders.add(loader); 152 return this; 153 } 154 setNoInit()155 public Builder setNoInit() { 156 mNoInit = true; 157 return this; 158 } 159 build()160 public AssetManager build() { 161 // Retrieving the system ApkAssets forces their creation as well. 162 final ApkAssets[] systemApkAssets = getSystem().getApkAssets(); 163 164 // Filter ApkAssets so that assets provided by multiple loaders are only included once 165 // in the AssetManager assets. The last appearance of the ApkAssets dictates its load 166 // order. 167 final ArrayList<ApkAssets> loaderApkAssets = new ArrayList<>(); 168 final ArraySet<ApkAssets> uniqueLoaderApkAssets = new ArraySet<>(); 169 for (int i = mLoaders.size() - 1; i >= 0; i--) { 170 final List<ApkAssets> currentLoaderApkAssets = mLoaders.get(i).getApkAssets(); 171 for (int j = currentLoaderApkAssets.size() - 1; j >= 0; j--) { 172 final ApkAssets apkAssets = currentLoaderApkAssets.get(j); 173 if (uniqueLoaderApkAssets.add(apkAssets)) { 174 loaderApkAssets.add(0, apkAssets); 175 } 176 } 177 } 178 179 final int totalApkAssetCount = systemApkAssets.length + mUserApkAssets.size() 180 + loaderApkAssets.size(); 181 final ApkAssets[] apkAssets = new ApkAssets[totalApkAssetCount]; 182 183 System.arraycopy(systemApkAssets, 0, apkAssets, 0, systemApkAssets.length); 184 185 // Append user ApkAssets after system ApkAssets. 186 for (int i = 0, n = mUserApkAssets.size(); i < n; i++) { 187 apkAssets[i + systemApkAssets.length] = mUserApkAssets.get(i); 188 } 189 190 // Append ApkAssets provided by loaders to the end. 191 for (int i = 0, n = loaderApkAssets.size(); i < n; i++) { 192 apkAssets[i + systemApkAssets.length + mUserApkAssets.size()] = 193 loaderApkAssets.get(i); 194 } 195 196 // Calling this constructor prevents creation of system ApkAssets, which we took care 197 // of in this Builder. 198 final AssetManager assetManager = new AssetManager(false /*sentinel*/); 199 assetManager.mApkAssets = apkAssets; 200 AssetManager.nativeSetApkAssets(assetManager.mObject, apkAssets, 201 false /*invalidateCaches*/, mNoInit /*preset*/); 202 assetManager.mLoaders = mLoaders.isEmpty() ? null 203 : mLoaders.toArray(new ResourcesLoader[0]); 204 205 return assetManager; 206 } 207 } 208 209 /** 210 * Create a new AssetManager containing only the basic system assets. 211 * Applications will not generally use this method, instead retrieving the 212 * appropriate asset manager with {@link Resources#getAssets}. Not for 213 * use by applications. 214 * @hide 215 */ 216 @UnsupportedAppUsage AssetManager()217 public AssetManager() { 218 final ApkAssets[] assets; 219 synchronized (sSync) { 220 createSystemAssetsInZygoteLocked(false, FRAMEWORK_APK_PATH); 221 assets = sSystemApkAssets; 222 } 223 224 mObject = nativeCreate(); 225 if (DEBUG_REFS) { 226 mNumRefs = 0; 227 incRefsLocked(hashCode()); 228 } 229 230 // Always set the framework resources. 231 setApkAssets(assets, false /*invalidateCaches*/); 232 } 233 234 /** 235 * Private constructor that doesn't call ensureSystemAssets. 236 * Used for the creation of system assets. 237 */ 238 @SuppressWarnings("unused") AssetManager(boolean sentinel)239 private AssetManager(boolean sentinel) { 240 mObject = nativeCreate(); 241 if (DEBUG_REFS) { 242 mNumRefs = 0; 243 incRefsLocked(hashCode()); 244 } 245 } 246 247 /** 248 * This must be called from Zygote so that system assets are shared by all applications. 249 * @hide 250 */ 251 @GuardedBy("sSync") 252 @VisibleForTesting createSystemAssetsInZygoteLocked(boolean reinitialize, String frameworkPath)253 public static void createSystemAssetsInZygoteLocked(boolean reinitialize, 254 String frameworkPath) { 255 if (sSystem != null && !reinitialize) { 256 return; 257 } 258 259 try { 260 final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); 261 apkAssets.add(ApkAssets.loadFromPath(frameworkPath, ApkAssets.PROPERTY_SYSTEM)); 262 263 final String[] systemIdmapPaths = 264 OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote(); 265 for (String idmapPath : systemIdmapPaths) { 266 apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM)); 267 } 268 269 sSystemApkAssetsSet = new ArraySet<>(apkAssets); 270 sSystemApkAssets = apkAssets.toArray(new ApkAssets[0]); 271 if (sSystem == null) { 272 sSystem = new AssetManager(true /*sentinel*/); 273 } 274 sSystem.setApkAssets(sSystemApkAssets, false /*invalidateCaches*/); 275 } catch (IOException e) { 276 throw new IllegalStateException("Failed to create system AssetManager", e); 277 } 278 } 279 280 /** 281 * Return a global shared asset manager that provides access to only 282 * system assets (no application assets). 283 * @hide 284 */ 285 @UnsupportedAppUsage getSystem()286 public static AssetManager getSystem() { 287 synchronized (sSync) { 288 createSystemAssetsInZygoteLocked(false, FRAMEWORK_APK_PATH); 289 return sSystem; 290 } 291 } 292 293 /** 294 * Close this asset manager. 295 */ 296 @Override close()297 public void close() { 298 synchronized (this) { 299 if (!mOpen) { 300 return; 301 } 302 303 mOpen = false; 304 decRefsLocked(hashCode()); 305 } 306 } 307 308 /** 309 * Changes the asset paths in this AssetManager. This replaces the {@link #addAssetPath(String)} 310 * family of methods. 311 * 312 * @param apkAssets The new set of paths. 313 * @param invalidateCaches Whether to invalidate any caches. This should almost always be true. 314 * Set this to false if you are appending new resources 315 * (not new configurations). 316 * @hide 317 */ setApkAssets(@onNull ApkAssets[] apkAssets, boolean invalidateCaches)318 public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) { 319 Objects.requireNonNull(apkAssets, "apkAssets"); 320 321 ApkAssets[] newApkAssets = new ApkAssets[sSystemApkAssets.length + apkAssets.length]; 322 323 // Copy the system assets first. 324 System.arraycopy(sSystemApkAssets, 0, newApkAssets, 0, sSystemApkAssets.length); 325 326 // Copy the given ApkAssets if they are not already in the system list. 327 int newLength = sSystemApkAssets.length; 328 for (ApkAssets apkAsset : apkAssets) { 329 if (!sSystemApkAssetsSet.contains(apkAsset)) { 330 newApkAssets[newLength++] = apkAsset; 331 } 332 } 333 334 // Truncate if necessary. 335 if (newLength != newApkAssets.length) { 336 newApkAssets = Arrays.copyOf(newApkAssets, newLength); 337 } 338 339 synchronized (this) { 340 ensureOpenLocked(); 341 mApkAssets = newApkAssets; 342 nativeSetApkAssets(mObject, mApkAssets, invalidateCaches, false); 343 if (invalidateCaches) { 344 // Invalidate all caches. 345 invalidateCachesLocked(-1); 346 } 347 } 348 } 349 350 /** 351 * Changes the {@link ResourcesLoader ResourcesLoaders} used in this AssetManager. 352 * @hide 353 */ setLoaders(@onNull List<ResourcesLoader> newLoaders)354 void setLoaders(@NonNull List<ResourcesLoader> newLoaders) { 355 Objects.requireNonNull(newLoaders, "newLoaders"); 356 357 final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); 358 for (int i = 0; i < mApkAssets.length; i++) { 359 // Filter out the previous loader apk assets. 360 if (!mApkAssets[i].isForLoader()) { 361 apkAssets.add(mApkAssets[i]); 362 } 363 } 364 365 if (!newLoaders.isEmpty()) { 366 // Filter so that assets provided by multiple loaders are only included once 367 // in the final assets list. The last appearance of the ApkAssets dictates its load 368 // order. 369 final int loaderStartIndex = apkAssets.size(); 370 final ArraySet<ApkAssets> uniqueLoaderApkAssets = new ArraySet<>(); 371 for (int i = newLoaders.size() - 1; i >= 0; i--) { 372 final List<ApkAssets> currentLoaderApkAssets = newLoaders.get(i).getApkAssets(); 373 for (int j = currentLoaderApkAssets.size() - 1; j >= 0; j--) { 374 final ApkAssets loaderApkAssets = currentLoaderApkAssets.get(j); 375 if (uniqueLoaderApkAssets.add(loaderApkAssets)) { 376 apkAssets.add(loaderStartIndex, loaderApkAssets); 377 } 378 } 379 } 380 } 381 382 mLoaders = newLoaders.toArray(new ResourcesLoader[0]); 383 setApkAssets(apkAssets.toArray(new ApkAssets[0]), true /* invalidate_caches */); 384 } 385 386 /** 387 * Invalidates the caches in this AssetManager according to the bitmask `diff`. 388 * 389 * @param diff The bitmask of changes generated by {@link Configuration#diff(Configuration)}. 390 * @see ActivityInfo.Config 391 */ invalidateCachesLocked(int diff)392 private void invalidateCachesLocked(int diff) { 393 // TODO(adamlesinski): Currently there are no caches to invalidate in Java code. 394 } 395 396 /** 397 * Returns the set of ApkAssets loaded by this AssetManager. If the AssetManager is closed, this 398 * returns a 0-length array. 399 * @hide 400 */ 401 @UnsupportedAppUsage getApkAssets()402 public @NonNull ApkAssets[] getApkAssets() { 403 synchronized (this) { 404 if (mOpen) { 405 return mApkAssets; 406 } 407 } 408 return sEmptyApkAssets; 409 } 410 411 /** @hide */ 412 @TestApi getApkPaths()413 public @NonNull String[] getApkPaths() { 414 synchronized (this) { 415 if (mOpen) { 416 String[] paths = new String[mApkAssets.length]; 417 final int count = mApkAssets.length; 418 for (int i = 0; i < count; i++) { 419 paths[i] = mApkAssets[i].getAssetPath(); 420 } 421 return paths; 422 } 423 } 424 return new String[0]; 425 } 426 427 /** 428 * Returns a cookie for use with the other APIs of AssetManager. 429 * @return 0 if the path was not found, otherwise a positive integer cookie representing 430 * this path in the AssetManager. 431 * @hide 432 */ findCookieForPath(@onNull String path)433 public int findCookieForPath(@NonNull String path) { 434 Objects.requireNonNull(path, "path"); 435 synchronized (this) { 436 ensureValidLocked(); 437 final int count = mApkAssets.length; 438 for (int i = 0; i < count; i++) { 439 if (path.equals(mApkAssets[i].getAssetPath())) { 440 return i + 1; 441 } 442 } 443 } 444 return 0; 445 } 446 447 /** 448 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 449 * @hide 450 */ 451 @Deprecated 452 @UnsupportedAppUsage addAssetPath(String path)453 public int addAssetPath(String path) { 454 return addAssetPathInternal(List.of(new ApkKey(path, false, false)), false); 455 } 456 457 /** 458 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 459 * @hide 460 */ 461 @Deprecated 462 @UnsupportedAppUsage addAssetPathAsSharedLibrary(String path)463 public int addAssetPathAsSharedLibrary(String path) { 464 return addAssetPathInternal(List.of(new ApkKey(path, true, false)), false); 465 } 466 467 /** 468 * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)} 469 * @hide 470 */ 471 @Deprecated 472 @UnsupportedAppUsage addOverlayPath(String path)473 public int addOverlayPath(String path) { 474 return addAssetPathInternal(List.of(new ApkKey(path, false, true)), false); 475 } 476 477 /** 478 * @hide 479 */ addPresetApkKeys(@onNull List<ApkKey> keys)480 public void addPresetApkKeys(@NonNull List<ApkKey> keys) { 481 addAssetPathInternal(keys, true); 482 } 483 addAssetPathInternal(List<ApkKey> apkKeys, boolean presetAssets)484 private int addAssetPathInternal(List<ApkKey> apkKeys, boolean presetAssets) { 485 Objects.requireNonNull(apkKeys, "apkKeys"); 486 if (apkKeys.isEmpty()) { 487 return 0; 488 } 489 490 synchronized (this) { 491 ensureOpenLocked(); 492 final int count = mApkAssets.length; 493 494 // See if we already have some of the apkKeys loaded. 495 final int originalAssetsCount = mApkAssets.length; 496 497 // Getting an assets' path is a relatively expensive operation, cache them. 498 final ArrayMap<String, Integer> assetPaths = new ArrayMap<>(originalAssetsCount); 499 for (int i = 0; i < originalAssetsCount; i++) { 500 assetPaths.put(mApkAssets[i].getAssetPath(), i); 501 } 502 503 final var newKeys = new ArrayList<ApkKey>(apkKeys.size()); 504 int lastFoundIndex = -1; 505 for (int i = 0, pathsSize = apkKeys.size(); i < pathsSize; i++) { 506 final var key = apkKeys.get(i); 507 final var index = assetPaths.get(key.path); 508 if (index == null) { 509 newKeys.add(key); 510 } else { 511 lastFoundIndex = index; 512 } 513 } 514 if (newKeys.isEmpty()) { 515 return lastFoundIndex + 1; 516 } 517 518 final var newAssets = loadAssets(newKeys); 519 if (newAssets.isEmpty()) { 520 return 0; 521 } 522 mApkAssets = makeNewAssetsArrayLocked(newAssets); 523 nativeSetApkAssets(mObject, mApkAssets, true, presetAssets); 524 invalidateCachesLocked(-1); 525 return originalAssetsCount + 1; 526 } 527 } 528 529 /** 530 * Insert the new assets preserving the correct order: all non-loader assets go before all 531 * of the loader assets. 532 */ 533 @GuardedBy("this") makeNewAssetsArrayLocked( @onNull ArrayList<ApkAssets> newNonLoaderAssets)534 private @NonNull ApkAssets[] makeNewAssetsArrayLocked( 535 @NonNull ArrayList<ApkAssets> newNonLoaderAssets) { 536 final int originalAssetsCount = mApkAssets.length; 537 int firstLoaderIndex = originalAssetsCount; 538 for (int i = 0; i < originalAssetsCount; i++) { 539 if (mApkAssets[i].isForLoader()) { 540 firstLoaderIndex = i; 541 break; 542 } 543 } 544 final int newAssetsSize = newNonLoaderAssets.size(); 545 final var newAssetsArray = new ApkAssets[originalAssetsCount + newAssetsSize]; 546 if (firstLoaderIndex > 0) { 547 // This should always be true, but who knows... 548 System.arraycopy(mApkAssets, 0, newAssetsArray, 0, firstLoaderIndex); 549 } 550 for (int i = 0; i < newAssetsSize; i++) { 551 newAssetsArray[firstLoaderIndex + i] = newNonLoaderAssets.get(i); 552 } 553 if (originalAssetsCount > firstLoaderIndex) { 554 System.arraycopy( 555 mApkAssets, firstLoaderIndex, 556 newAssetsArray, firstLoaderIndex + newAssetsSize, 557 originalAssetsCount - firstLoaderIndex); 558 } 559 return newAssetsArray; 560 } 561 loadAssets(@onNull ArrayList<ApkKey> keys)562 private static @NonNull ArrayList<ApkAssets> loadAssets(@NonNull ArrayList<ApkKey> keys) { 563 final int pathsSize = keys.size(); 564 final var loadedAssets = new ArrayList<ApkAssets>(pathsSize); 565 final var resourcesManager = ResourcesManager.getInstance(); 566 for (int i = 0; i < pathsSize; i++) { 567 final var key = keys.get(i); 568 try { 569 // ResourcesManager has a cache of loaded assets, ensuring we don't open the same 570 // file repeatedly, which is useful for the common overlays and registered 571 // shared libraries. 572 loadedAssets.add(resourcesManager.loadApkAssets(key)); 573 } catch (IOException e) { 574 Log.w(TAG, "Failed to load asset, key = " + key, e); 575 } 576 } 577 return loadedAssets; 578 } 579 580 /** @hide */ 581 @NonNull getLoaders()582 public List<ResourcesLoader> getLoaders() { 583 return mLoaders == null ? Collections.emptyList() : Arrays.asList(mLoaders); 584 } 585 586 /** 587 * Ensures that the native implementation has not been destroyed. 588 * The AssetManager may have been closed, but references to it still exist 589 * and therefore the native implementation is not destroyed. 590 */ 591 @GuardedBy("this") ensureValidLocked()592 private void ensureValidLocked() { 593 if (mObject == 0) { 594 throw new RuntimeException("AssetManager has been destroyed"); 595 } 596 } 597 598 /** 599 * Ensures that the AssetManager has not been explicitly closed. If this method passes, 600 * then this implies that ensureValidLocked() also passes. 601 */ 602 @GuardedBy("this") ensureOpenLocked()603 private void ensureOpenLocked() { 604 // If mOpen is true, this implies that mObject != 0. 605 if (!mOpen) { 606 throw new RuntimeException("AssetManager has been closed"); 607 } 608 // Let's still check if the native object exists, given all the memory corruptions. 609 if (mObject == 0) { 610 throw new RuntimeException("AssetManager is open but the native object is gone"); 611 } 612 } 613 614 /** 615 * Populates {@code outValue} with the data associated a particular 616 * resource identifier for the current configuration. 617 * 618 * @param resId the resource identifier to load 619 * @param densityDpi the density bucket for which to load the resource 620 * @param outValue the typed value in which to put the data 621 * @param resolveRefs {@code true} to resolve references, {@code false} 622 * to leave them unresolved 623 * @return {@code true} if the data was loaded into {@code outValue}, 624 * {@code false} otherwise 625 */ 626 @UnsupportedAppUsage getResourceValue(@nyRes int resId, int densityDpi, @NonNull TypedValue outValue, boolean resolveRefs)627 boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue, 628 boolean resolveRefs) { 629 Objects.requireNonNull(outValue, "outValue"); 630 synchronized (this) { 631 ensureValidLocked(); 632 final int cookie = nativeGetResourceValue( 633 mObject, resId, (short) densityDpi, outValue, resolveRefs); 634 if (cookie <= 0) { 635 return false; 636 } 637 638 // Convert the changing configurations flags populated by native code. 639 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 640 outValue.changingConfigurations); 641 642 if (outValue.type == TypedValue.TYPE_STRING) { 643 if ((outValue.string = getPooledStringForCookie(cookie, outValue.data)) == null) { 644 return false; 645 } 646 } 647 return true; 648 } 649 } 650 651 /** 652 * Retrieves the string value associated with a particular resource 653 * identifier for the current configuration. 654 * 655 * @param resId the resource identifier to load 656 * @return the string value, or {@code null} 657 */ 658 @UnsupportedAppUsage getResourceText(@tringRes int resId)659 @Nullable CharSequence getResourceText(@StringRes int resId) { 660 synchronized (this) { 661 final TypedValue outValue = mValue; 662 if (getResourceValue(resId, 0, outValue, true)) { 663 return outValue.coerceToString(); 664 } 665 return null; 666 } 667 } 668 669 /** 670 * Retrieves the string value associated with a particular resource 671 * identifier for the current configuration. 672 * 673 * @param resId the resource identifier to load 674 * @param bagEntryId the index into the bag to load 675 * @return the string value, or {@code null} 676 */ 677 @UnsupportedAppUsage getResourceBagText(@tringRes int resId, int bagEntryId)678 @Nullable CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) { 679 synchronized (this) { 680 ensureValidLocked(); 681 final TypedValue outValue = mValue; 682 final int cookie = nativeGetResourceBagValue(mObject, resId, bagEntryId, outValue); 683 if (cookie <= 0) { 684 return null; 685 } 686 687 // Convert the changing configurations flags populated by native code. 688 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 689 outValue.changingConfigurations); 690 691 if (outValue.type == TypedValue.TYPE_STRING) { 692 return getPooledStringForCookie(cookie, outValue.data); 693 } 694 return outValue.coerceToString(); 695 } 696 } 697 getResourceArraySize(@rrayRes int resId)698 int getResourceArraySize(@ArrayRes int resId) { 699 synchronized (this) { 700 ensureValidLocked(); 701 return nativeGetResourceArraySize(mObject, resId); 702 } 703 } 704 705 /** 706 * Populates `outData` with array elements of `resId`. `outData` is normally 707 * used with 708 * {@link TypedArray}. 709 * 710 * Each logical element in `outData` is {@link TypedArray#STYLE_NUM_ENTRIES} 711 * long, 712 * with the indices of the data representing the type, value, asset cookie, 713 * resource ID, 714 * configuration change mask, and density of the element. 715 * 716 * @param resId The resource ID of an array resource. 717 * @param outData The array to populate with data. 718 * @return The length of the array. 719 * 720 * @see TypedArray#STYLE_TYPE 721 * @see TypedArray#STYLE_DATA 722 * @see TypedArray#STYLE_ASSET_COOKIE 723 * @see TypedArray#STYLE_RESOURCE_ID 724 * @see TypedArray#STYLE_CHANGING_CONFIGURATIONS 725 * @see TypedArray#STYLE_DENSITY 726 */ getResourceArray(@rrayRes int resId, @NonNull int[] outData)727 int getResourceArray(@ArrayRes int resId, @NonNull int[] outData) { 728 Objects.requireNonNull(outData, "outData"); 729 synchronized (this) { 730 ensureValidLocked(); 731 return nativeGetResourceArray(mObject, resId, outData); 732 } 733 } 734 735 /** 736 * Retrieves the string array associated with a particular resource 737 * identifier for the current configuration. 738 * 739 * @param resId the resource identifier of the string array 740 * @return the string array, or {@code null} 741 */ getResourceStringArray(@rrayRes int resId)742 @Nullable String[] getResourceStringArray(@ArrayRes int resId) { 743 synchronized (this) { 744 ensureValidLocked(); 745 return nativeGetResourceStringArray(mObject, resId); 746 } 747 } 748 749 /** 750 * Retrieve the text array associated with a particular resource 751 * identifier. 752 * 753 * @param resId the resource id of the string array 754 */ getResourceTextArray(@rrayRes int resId)755 @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) { 756 synchronized (this) { 757 ensureValidLocked(); 758 final int[] rawInfoArray = nativeGetResourceStringArrayInfo(mObject, resId); 759 if (rawInfoArray == null) { 760 return null; 761 } 762 763 final int rawInfoArrayLen = rawInfoArray.length; 764 final int infoArrayLen = rawInfoArrayLen / 2; 765 final CharSequence[] retArray = new CharSequence[infoArrayLen]; 766 for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) { 767 int cookie = rawInfoArray[i]; 768 int index = rawInfoArray[i + 1]; 769 retArray[j] = (index >= 0 && cookie > 0) 770 ? getPooledStringForCookie(cookie, index) : null; 771 } 772 return retArray; 773 } 774 } 775 getResourceIntArray(@rrayRes int resId)776 @Nullable int[] getResourceIntArray(@ArrayRes int resId) { 777 synchronized (this) { 778 ensureValidLocked(); 779 return nativeGetResourceIntArray(mObject, resId); 780 } 781 } 782 783 /** 784 * Get the attributes for a style resource. These are the <item> 785 * elements in 786 * a <style> resource. 787 * @param resId The resource ID of the style 788 * @return An array of attribute IDs. 789 */ getStyleAttributes(@tyleRes int resId)790 @AttrRes int[] getStyleAttributes(@StyleRes int resId) { 791 synchronized (this) { 792 ensureValidLocked(); 793 return nativeGetStyleAttributes(mObject, resId); 794 } 795 } 796 797 /** 798 * Populates {@code outValue} with the data associated with a particular 799 * resource identifier for the current configuration. Resolves theme 800 * attributes against the specified theme. 801 * 802 * @param theme the native pointer of the theme 803 * @param resId the resource identifier to load 804 * @param outValue the typed value in which to put the data 805 * @param resolveRefs {@code true} to resolve references, {@code false} 806 * to leave them unresolved 807 * @return {@code true} if the data was loaded into {@code outValue}, 808 * {@code false} otherwise 809 */ getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, boolean resolveRefs)810 boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, 811 boolean resolveRefs) { 812 Objects.requireNonNull(outValue, "outValue"); 813 synchronized (this) { 814 ensureValidLocked(); 815 final int cookie = nativeThemeGetAttributeValue(mObject, theme, resId, outValue, 816 resolveRefs); 817 if (cookie <= 0) { 818 return false; 819 } 820 821 // Convert the changing configurations flags populated by native code. 822 outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava( 823 outValue.changingConfigurations); 824 825 if (outValue.type == TypedValue.TYPE_STRING) { 826 if ((outValue.string = getPooledStringForCookie(cookie, outValue.data)) == null) { 827 return false; 828 } 829 } 830 return true; 831 } 832 } 833 dumpTheme(long theme, int priority, String tag, String prefix)834 void dumpTheme(long theme, int priority, String tag, String prefix) { 835 synchronized (this) { 836 ensureValidLocked(); 837 nativeThemeDump(mObject, theme, priority, tag, prefix); 838 } 839 } 840 841 @UnsupportedAppUsage getResourceName(@nyRes int resId)842 @Nullable String getResourceName(@AnyRes int resId) { 843 synchronized (this) { 844 ensureValidLocked(); 845 return nativeGetResourceName(mObject, resId); 846 } 847 } 848 849 @UnsupportedAppUsage getResourcePackageName(@nyRes int resId)850 @Nullable String getResourcePackageName(@AnyRes int resId) { 851 synchronized (this) { 852 ensureValidLocked(); 853 return nativeGetResourcePackageName(mObject, resId); 854 } 855 } 856 857 @UnsupportedAppUsage getResourceTypeName(@nyRes int resId)858 @Nullable String getResourceTypeName(@AnyRes int resId) { 859 synchronized (this) { 860 ensureValidLocked(); 861 return nativeGetResourceTypeName(mObject, resId); 862 } 863 } 864 865 @UnsupportedAppUsage getResourceEntryName(@nyRes int resId)866 @Nullable String getResourceEntryName(@AnyRes int resId) { 867 synchronized (this) { 868 ensureValidLocked(); 869 return nativeGetResourceEntryName(mObject, resId); 870 } 871 } 872 873 @UnsupportedAppUsage getResourceIdentifier(@onNull String name, @Nullable String defType, @Nullable String defPackage)874 @AnyRes int getResourceIdentifier(@NonNull String name, @Nullable String defType, 875 @Nullable String defPackage) { 876 synchronized (this) { 877 ensureValidLocked(); 878 // name is checked in JNI. 879 return nativeGetResourceIdentifier(mObject, name, defType, defPackage); 880 } 881 } 882 883 /** 884 * To get the parent theme resource id according to the parameter theme resource id. 885 * @param resId theme resource id. 886 * @return the parent theme resource id. 887 * @hide 888 */ 889 @StyleRes getParentThemeIdentifier(@tyleRes int resId)890 int getParentThemeIdentifier(@StyleRes int resId) { 891 synchronized (this) { 892 ensureValidLocked(); 893 // name is checked in JNI. 894 return nativeGetParentThemeIdentifier(mObject, resId); 895 } 896 } 897 898 /** 899 * Enable resource resolution logging to track the steps taken to resolve the last resource 900 * entry retrieved. Stores the configuration and package names for each step. 901 * 902 * Default disabled. 903 * 904 * @param enabled Boolean indicating whether to enable or disable logging. 905 * 906 * @hide 907 */ 908 @TestApi setResourceResolutionLoggingEnabled(boolean enabled)909 public void setResourceResolutionLoggingEnabled(boolean enabled) { 910 synchronized (this) { 911 ensureValidLocked(); 912 nativeSetResourceResolutionLoggingEnabled(mObject, enabled); 913 } 914 } 915 916 /** 917 * Retrieve the last resource resolution path logged. 918 * 919 * @return Formatted string containing last resource ID/name and steps taken to resolve final 920 * entry, including configuration and package names. 921 * 922 * @hide 923 */ 924 @TestApi getLastResourceResolution()925 public @Nullable String getLastResourceResolution() { 926 synchronized (this) { 927 ensureValidLocked(); 928 return nativeGetLastResourceResolution(mObject); 929 } 930 } 931 932 /** 933 * Returns whether the {@code resources.arsc} of any loaded apk assets is allocated in RAM 934 * (not mmapped). 935 * 936 * @hide 937 */ containsAllocatedTable()938 public boolean containsAllocatedTable() { 939 synchronized (this) { 940 ensureValidLocked(); 941 return nativeContainsAllocatedTable(mObject); 942 } 943 } 944 945 @Nullable getPooledStringForCookie(int cookie, int id)946 CharSequence getPooledStringForCookie(int cookie, int id) { 947 // Cookies map to ApkAssets starting at 1. 948 return getApkAssets()[cookie - 1].getStringFromPool(id); 949 } 950 951 /** 952 * Open an asset using ACCESS_STREAMING mode. This provides access to 953 * files that have been bundled with an application as assets -- that is, 954 * files placed in to the "assets" directory. 955 * 956 * @param fileName The name of the asset to open. This name can be hierarchical. 957 * 958 * @see #open(String, int) 959 * @see #list 960 */ open(@onNull String fileName)961 public @NonNull InputStream open(@NonNull String fileName) throws IOException { 962 return open(fileName, ACCESS_STREAMING); 963 } 964 965 /** 966 * Open an asset using an explicit access mode, returning an InputStream to 967 * read its contents. This provides access to files that have been bundled 968 * with an application as assets -- that is, files placed in to the 969 * "assets" directory. 970 * 971 * @param fileName The name of the asset to open. This name can be hierarchical. 972 * @param accessMode Desired access mode for retrieving the data. 973 * 974 * @see #ACCESS_UNKNOWN 975 * @see #ACCESS_STREAMING 976 * @see #ACCESS_RANDOM 977 * @see #ACCESS_BUFFER 978 * @see #open(String) 979 * @see #list 980 */ open(@onNull String fileName, int accessMode)981 public @NonNull InputStream open(@NonNull String fileName, int accessMode) throws IOException { 982 Objects.requireNonNull(fileName, "fileName"); 983 synchronized (this) { 984 ensureOpenLocked(); 985 final long asset = nativeOpenAsset(mObject, fileName, accessMode); 986 if (asset == 0) { 987 throw new FileNotFoundException("Asset file: " + fileName); 988 } 989 final AssetInputStream assetInputStream = new AssetInputStream(asset); 990 incRefsLocked(assetInputStream.hashCode()); 991 return assetInputStream; 992 } 993 } 994 995 /** 996 * Open an uncompressed asset by mmapping it and returning an {@link AssetFileDescriptor}. 997 * This provides access to files that have been bundled with an application as assets -- that 998 * is, files placed in to the "assets" directory. 999 * 1000 * The asset must be uncompressed, or an exception will be thrown. 1001 * 1002 * @param fileName The name of the asset to open. This name can be hierarchical. 1003 * @return An open AssetFileDescriptor. 1004 */ openFd(@onNull String fileName)1005 public @NonNull AssetFileDescriptor openFd(@NonNull String fileName) throws IOException { 1006 Objects.requireNonNull(fileName, "fileName"); 1007 synchronized (this) { 1008 ensureOpenLocked(); 1009 final ParcelFileDescriptor pfd = nativeOpenAssetFd(mObject, fileName, mOffsets); 1010 if (pfd == null) { 1011 throw new FileNotFoundException("Asset file: " + fileName); 1012 } 1013 return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); 1014 } 1015 } 1016 1017 /** 1018 * Return a String array of all the assets at the given path. 1019 * 1020 * @param path A relative path within the assets, i.e., "docs/home.html". 1021 * 1022 * @return String[] Array of strings, one for each asset. These file 1023 * names are relative to 'path'. You can open the file by 1024 * concatenating 'path' and a name in the returned string (via 1025 * File) and passing that to open(). 1026 * 1027 * @see #open 1028 */ list(@onNull String path)1029 public @Nullable String[] list(@NonNull String path) throws IOException { 1030 Objects.requireNonNull(path, "path"); 1031 synchronized (this) { 1032 ensureValidLocked(); 1033 return nativeList(mObject, path); 1034 } 1035 } 1036 1037 /** 1038 * Open a non-asset file as an asset using ACCESS_STREAMING mode. This 1039 * provides direct access to all of the files included in an application 1040 * package (not only its assets). Applications should not normally use 1041 * this. 1042 * 1043 * @param fileName Name of the asset to retrieve. 1044 * 1045 * @see #open(String) 1046 * @hide 1047 */ 1048 @UnsupportedAppUsage openNonAsset(@onNull String fileName)1049 public @NonNull InputStream openNonAsset(@NonNull String fileName) throws IOException { 1050 return openNonAsset(0, fileName, ACCESS_STREAMING); 1051 } 1052 1053 /** 1054 * Open a non-asset file as an asset using a specific access mode. This 1055 * provides direct access to all of the files included in an application 1056 * package (not only its assets). Applications should not normally use 1057 * this. 1058 * 1059 * @param fileName Name of the asset to retrieve. 1060 * @param accessMode Desired access mode for retrieving the data. 1061 * 1062 * @see #ACCESS_UNKNOWN 1063 * @see #ACCESS_STREAMING 1064 * @see #ACCESS_RANDOM 1065 * @see #ACCESS_BUFFER 1066 * @see #open(String, int) 1067 * @hide 1068 */ 1069 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) openNonAsset(@onNull String fileName, int accessMode)1070 public @NonNull InputStream openNonAsset(@NonNull String fileName, int accessMode) 1071 throws IOException { 1072 return openNonAsset(0, fileName, accessMode); 1073 } 1074 1075 /** 1076 * Open a non-asset in a specified package. Not for use by applications. 1077 * 1078 * @param cookie Identifier of the package to be opened. 1079 * @param fileName Name of the asset to retrieve. 1080 * @hide 1081 */ 1082 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) openNonAsset(int cookie, @NonNull String fileName)1083 public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName) 1084 throws IOException { 1085 return openNonAsset(cookie, fileName, ACCESS_STREAMING); 1086 } 1087 1088 /** 1089 * Open a non-asset in a specified package. Not for use by applications. 1090 * 1091 * @param cookie Identifier of the package to be opened. 1092 * @param fileName Name of the asset to retrieve. 1093 * @param accessMode Desired access mode for retrieving the data. 1094 * @hide 1095 */ 1096 @UnsupportedAppUsage openNonAsset(int cookie, @NonNull String fileName, int accessMode)1097 public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName, int accessMode) 1098 throws IOException { 1099 Objects.requireNonNull(fileName, "fileName"); 1100 synchronized (this) { 1101 ensureOpenLocked(); 1102 final long asset = nativeOpenNonAsset(mObject, cookie, fileName, accessMode); 1103 if (asset == 0) { 1104 throw new FileNotFoundException("Asset absolute file: " + fileName); 1105 } 1106 final AssetInputStream assetInputStream = new AssetInputStream(asset); 1107 incRefsLocked(assetInputStream.hashCode()); 1108 return assetInputStream; 1109 } 1110 } 1111 1112 /** 1113 * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}. 1114 * This provides direct access to all of the files included in an application 1115 * package (not only its assets). Applications should not normally use this. 1116 * 1117 * The asset must not be compressed, or an exception will be thrown. 1118 * 1119 * @param fileName Name of the asset to retrieve. 1120 */ openNonAssetFd(@onNull String fileName)1121 public @NonNull AssetFileDescriptor openNonAssetFd(@NonNull String fileName) 1122 throws IOException { 1123 return openNonAssetFd(0, fileName); 1124 } 1125 1126 /** 1127 * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}. 1128 * This provides direct access to all of the files included in an application 1129 * package (not only its assets). Applications should not normally use this. 1130 * 1131 * The asset must not be compressed, or an exception will be thrown. 1132 * 1133 * @param cookie Identifier of the package to be opened. 1134 * @param fileName Name of the asset to retrieve. 1135 */ openNonAssetFd(int cookie, @NonNull String fileName)1136 public @NonNull AssetFileDescriptor openNonAssetFd(int cookie, @NonNull String fileName) 1137 throws IOException { 1138 Objects.requireNonNull(fileName, "fileName"); 1139 synchronized (this) { 1140 ensureOpenLocked(); 1141 final ParcelFileDescriptor pfd = 1142 nativeOpenNonAssetFd(mObject, cookie, fileName, mOffsets); 1143 if (pfd == null) { 1144 throw new FileNotFoundException("Asset absolute file: " + fileName); 1145 } 1146 return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]); 1147 } 1148 } 1149 1150 /** 1151 * Retrieve a parser for a compiled XML file. 1152 * 1153 * @param fileName The name of the file to retrieve. 1154 */ openXmlResourceParser(@onNull String fileName)1155 public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName) 1156 throws IOException { 1157 return openXmlResourceParser(0, fileName); 1158 } 1159 1160 /** 1161 * Retrieve a parser for a compiled XML file. 1162 * 1163 * @param cookie Identifier of the package to be opened. 1164 * @param fileName The name of the file to retrieve. 1165 */ openXmlResourceParser(int cookie, @NonNull String fileName)1166 public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName) 1167 throws IOException { 1168 try (XmlBlock block = openXmlBlockAsset(cookie, fileName)) { 1169 XmlResourceParser parser = block.newParser(ID_NULL, new Validator()); 1170 // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with 1171 // a valid native pointer, which makes newParser always return non-null. But let's 1172 // be careful. 1173 if (parser == null) { 1174 throw new AssertionError("block.newParser() returned a null parser"); 1175 } 1176 return parser; 1177 } 1178 } 1179 1180 /** 1181 * Retrieve a non-asset as a compiled XML file. Not for use by applications. 1182 * 1183 * @param fileName The name of the file to retrieve. 1184 * @hide 1185 */ openXmlBlockAsset(@onNull String fileName)1186 @NonNull XmlBlock openXmlBlockAsset(@NonNull String fileName) throws IOException { 1187 return openXmlBlockAsset(0, fileName); 1188 } 1189 1190 /** 1191 * Retrieve a non-asset as a compiled XML file. Not for use by 1192 * applications. 1193 * 1194 * @param cookie Identifier of the package to be opened. 1195 * @param fileName Name of the asset to retrieve. 1196 * @hide 1197 */ openXmlBlockAsset(int cookie, @NonNull String fileName)1198 @NonNull XmlBlock openXmlBlockAsset(int cookie, @NonNull String fileName) throws IOException { 1199 Objects.requireNonNull(fileName, "fileName"); 1200 synchronized (this) { 1201 ensureOpenLocked(); 1202 1203 final long xmlBlock = nativeOpenXmlAsset(mObject, cookie, fileName); 1204 if (xmlBlock == 0) { 1205 throw new FileNotFoundException("Asset XML file: " + fileName); 1206 } 1207 final XmlBlock block = new XmlBlock(this, xmlBlock); 1208 incRefsLocked(block.hashCode()); 1209 return block; 1210 } 1211 } 1212 xmlBlockGone(int id)1213 void xmlBlockGone(int id) { 1214 synchronized (this) { 1215 decRefsLocked(id); 1216 } 1217 } 1218 1219 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, long outIndicesAddress)1220 void applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, 1221 @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, 1222 long outIndicesAddress) { 1223 Objects.requireNonNull(inAttrs, "inAttrs"); 1224 synchronized (this) { 1225 // Need to synchronize on AssetManager because we will be accessing 1226 // the native implementation of AssetManager. 1227 ensureValidLocked(); 1228 nativeApplyStyle(mObject, themePtr, defStyleAttr, defStyleRes, 1229 parser != null ? parser.mParseState : 0, inAttrs, outValuesAddress, 1230 outIndicesAddress); 1231 } 1232 } 1233 getAttributeResolutionStack(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @StyleRes int xmlStyle)1234 int[] getAttributeResolutionStack(long themePtr, @AttrRes int defStyleAttr, 1235 @StyleRes int defStyleRes, @StyleRes int xmlStyle) { 1236 synchronized (this) { 1237 ensureValidLocked(); 1238 return nativeAttributeResolutionStack( 1239 mObject, themePtr, xmlStyle, defStyleAttr, defStyleRes); 1240 } 1241 } 1242 1243 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1244 boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, 1245 @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, 1246 @NonNull int[] outIndices) { 1247 Objects.requireNonNull(inAttrs, "inAttrs"); 1248 Objects.requireNonNull(outValues, "outValues"); 1249 Objects.requireNonNull(outIndices, "outIndices"); 1250 synchronized (this) { 1251 // Need to synchronize on AssetManager because we will be accessing 1252 // the native implementation of AssetManager. 1253 ensureValidLocked(); 1254 return nativeResolveAttrs(mObject, 1255 themePtr, defStyleAttr, defStyleRes, inValues, inAttrs, outValues, outIndices); 1256 } 1257 } 1258 1259 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) retrieveAttributes(@onNull XmlBlock.Parser parser, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1260 boolean retrieveAttributes(@NonNull XmlBlock.Parser parser, @NonNull int[] inAttrs, 1261 @NonNull int[] outValues, @NonNull int[] outIndices) { 1262 Objects.requireNonNull(parser, "parser"); 1263 Objects.requireNonNull(inAttrs, "inAttrs"); 1264 Objects.requireNonNull(outValues, "outValues"); 1265 Objects.requireNonNull(outIndices, "outIndices"); 1266 synchronized (this) { 1267 // Need to synchronize on AssetManager because we will be accessing 1268 // the native implementation of AssetManager. 1269 ensureValidLocked(); 1270 return nativeRetrieveAttributes( 1271 mObject, parser.mParseState, inAttrs, outValues, outIndices); 1272 } 1273 } 1274 1275 @UnsupportedAppUsage createTheme()1276 long createTheme() { 1277 synchronized (this) { 1278 ensureValidLocked(); 1279 long themePtr = nativeThemeCreate(mObject); 1280 incRefsLocked(themePtr); 1281 return themePtr; 1282 } 1283 } 1284 releaseTheme(long themePtr)1285 void releaseTheme(long themePtr) { 1286 synchronized (this) { 1287 decRefsLocked(themePtr); 1288 } 1289 } 1290 getThemeFreeFunction()1291 static long getThemeFreeFunction() { 1292 return nativeGetThemeFreeFunction(); 1293 } 1294 applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force)1295 void applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force) { 1296 synchronized (this) { 1297 // Need to synchronize on AssetManager because we will be accessing 1298 // the native implementation of AssetManager. 1299 ensureValidLocked(); 1300 nativeThemeApplyStyle(mObject, themePtr, resId, force); 1301 } 1302 } 1303 rebaseTheme(long themePtr, @NonNull AssetManager newAssetManager, @StyleRes int[] styleIds, @StyleRes boolean[] force, int count)1304 AssetManager rebaseTheme(long themePtr, @NonNull AssetManager newAssetManager, 1305 @StyleRes int[] styleIds, @StyleRes boolean[] force, int count) { 1306 // Exchange ownership of the theme with the new asset manager. 1307 if (this != newAssetManager) { 1308 synchronized (this) { 1309 ensureValidLocked(); 1310 decRefsLocked(themePtr); 1311 } 1312 synchronized (newAssetManager) { 1313 newAssetManager.ensureValidLocked(); 1314 newAssetManager.incRefsLocked(themePtr); 1315 } 1316 } 1317 1318 try { 1319 synchronized (newAssetManager) { 1320 newAssetManager.ensureValidLocked(); 1321 nativeThemeRebase(newAssetManager.mObject, themePtr, styleIds, force, count); 1322 } 1323 } finally { 1324 Reference.reachabilityFence(newAssetManager); 1325 } 1326 return newAssetManager; 1327 } 1328 1329 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr)1330 void setThemeTo(long dstThemePtr, @NonNull AssetManager srcAssetManager, long srcThemePtr) { 1331 synchronized (this) { 1332 ensureValidLocked(); 1333 synchronized (srcAssetManager) { 1334 srcAssetManager.ensureValidLocked(); 1335 nativeThemeCopy(mObject, dstThemePtr, srcAssetManager.mObject, srcThemePtr); 1336 } 1337 } 1338 } 1339 1340 @Override finalize()1341 protected void finalize() throws Throwable { 1342 if (DEBUG_REFS && mNumRefs != 0) { 1343 Log.w(TAG, "AssetManager " + this + " finalized with non-zero refs: " + mNumRefs); 1344 if (mRefStacks != null) { 1345 for (RuntimeException e : mRefStacks.values()) { 1346 Log.w(TAG, "Reference from here", e); 1347 } 1348 } 1349 } 1350 1351 synchronized (this) { 1352 if (mObject != 0) { 1353 nativeDestroy(mObject); 1354 mObject = 0; 1355 } 1356 } 1357 } 1358 1359 /* No Locking is needed for AssetInputStream because an AssetInputStream is not-thread 1360 safe and it does not rely on AssetManager once it has been created. It completely owns the 1361 underlying Asset. */ 1362 public final class AssetInputStream extends InputStream { 1363 private long mAssetNativePtr; 1364 private long mLength; 1365 private long mMarkPos; 1366 1367 /** 1368 * @hide 1369 */ 1370 @UnsupportedAppUsage getAssetInt()1371 public final int getAssetInt() { 1372 throw new UnsupportedOperationException(); 1373 } 1374 1375 /** 1376 * @hide 1377 */ 1378 @UnsupportedAppUsage getNativeAsset()1379 public final long getNativeAsset() { 1380 return mAssetNativePtr; 1381 } 1382 AssetInputStream(long assetNativePtr)1383 private AssetInputStream(long assetNativePtr) { 1384 mAssetNativePtr = assetNativePtr; 1385 mLength = nativeAssetGetLength(assetNativePtr); 1386 } 1387 1388 @Override read()1389 public final int read() throws IOException { 1390 ensureOpen(); 1391 return nativeAssetReadChar(mAssetNativePtr); 1392 } 1393 1394 @Override read(@onNull byte[] b)1395 public final int read(@NonNull byte[] b) throws IOException { 1396 ensureOpen(); 1397 Objects.requireNonNull(b, "b"); 1398 return nativeAssetRead(mAssetNativePtr, b, 0, b.length); 1399 } 1400 1401 @Override read(@onNull byte[] b, int off, int len)1402 public final int read(@NonNull byte[] b, int off, int len) throws IOException { 1403 ensureOpen(); 1404 Objects.requireNonNull(b, "b"); 1405 return nativeAssetRead(mAssetNativePtr, b, off, len); 1406 } 1407 1408 @Override skip(long n)1409 public final long skip(long n) throws IOException { 1410 ensureOpen(); 1411 long pos = nativeAssetSeek(mAssetNativePtr, 0, 0); 1412 if ((pos + n) > mLength) { 1413 n = mLength - pos; 1414 } 1415 if (n > 0) { 1416 nativeAssetSeek(mAssetNativePtr, n, 0); 1417 } 1418 return n; 1419 } 1420 1421 @Override available()1422 public final int available() throws IOException { 1423 ensureOpen(); 1424 final long len = nativeAssetGetRemainingLength(mAssetNativePtr); 1425 return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) len; 1426 } 1427 1428 @Override markSupported()1429 public final boolean markSupported() { 1430 return true; 1431 } 1432 1433 @Override mark(int readlimit)1434 public final void mark(int readlimit) { 1435 ensureOpen(); 1436 mMarkPos = nativeAssetSeek(mAssetNativePtr, 0, 0); 1437 } 1438 1439 @Override reset()1440 public final void reset() throws IOException { 1441 ensureOpen(); 1442 nativeAssetSeek(mAssetNativePtr, mMarkPos, -1); 1443 } 1444 1445 @Override close()1446 public final void close() throws IOException { 1447 if (mAssetNativePtr != 0) { 1448 nativeAssetDestroy(mAssetNativePtr); 1449 mAssetNativePtr = 0; 1450 1451 synchronized (AssetManager.this) { 1452 decRefsLocked(hashCode()); 1453 } 1454 } 1455 } 1456 1457 @Override finalize()1458 protected void finalize() throws Throwable { 1459 close(); 1460 } 1461 ensureOpen()1462 private void ensureOpen() { 1463 if (mAssetNativePtr == 0) { 1464 throw new IllegalStateException("AssetInputStream is closed"); 1465 } 1466 } 1467 } 1468 1469 /** 1470 * Determine whether the state in this asset manager is up-to-date with 1471 * the files on the filesystem. If false is returned, you need to 1472 * instantiate a new AssetManager class to see the new data. 1473 * @hide 1474 */ 1475 @UnsupportedAppUsage isUpToDate()1476 public boolean isUpToDate() { 1477 synchronized (this) { 1478 if (!mOpen) { 1479 return false; 1480 } 1481 1482 for (ApkAssets apkAssets : mApkAssets) { 1483 if (!apkAssets.isUpToDate()) { 1484 return false; 1485 } 1486 } 1487 1488 return true; 1489 } 1490 } 1491 1492 /** 1493 * Get the locales that this asset manager contains data for. 1494 * 1495 * <p>On SDK 21 (Android 5.0: Lollipop) and above, Locale strings are valid 1496 * <a href="https://tools.ietf.org/html/bcp47">BCP-47</a> language tags and can be 1497 * parsed using {@link Locale#forLanguageTag(String)}. 1498 * 1499 * <p>On SDK 20 (Android 4.4W: KitKat for watches) and below, locale strings 1500 * are of the form {@code ll_CC} where {@code ll} is a two letter language code, 1501 * and {@code CC} is a two letter country code. 1502 */ getLocales()1503 public String[] getLocales() { 1504 synchronized (this) { 1505 ensureValidLocked(); 1506 return nativeGetLocales(mObject, false /*excludeSystem*/); 1507 } 1508 } 1509 1510 /** 1511 * Same as getLocales(), except that locales that are only provided by the system (i.e. those 1512 * present in framework-res.apk or its overlays) will not be listed. 1513 * 1514 * For example, if the "system" assets support English, French, and German, and the additional 1515 * assets support Cherokee and French, getLocales() would return 1516 * [Cherokee, English, French, German], while getNonSystemLocales() would return 1517 * [Cherokee, French]. 1518 * @hide 1519 */ getNonSystemLocales()1520 public String[] getNonSystemLocales() { 1521 synchronized (this) { 1522 ensureValidLocked(); 1523 return nativeGetLocales(mObject, true /*excludeSystem*/); 1524 } 1525 } 1526 1527 /** 1528 * @hide 1529 */ getSizeConfigurations()1530 Configuration[] getSizeConfigurations() { 1531 synchronized (this) { 1532 ensureValidLocked(); 1533 return nativeGetSizeConfigurations(mObject); 1534 } 1535 } 1536 1537 /** 1538 * @hide 1539 */ getSizeAndUiModeConfigurations()1540 Configuration[] getSizeAndUiModeConfigurations() { 1541 synchronized (this) { 1542 ensureValidLocked(); 1543 return nativeGetSizeAndUiModeConfigurations(mObject); 1544 } 1545 } 1546 1547 /** 1548 * Change the configuration used when retrieving resources. Not for use by 1549 * applications. 1550 * @hide 1551 */ 1552 @UnsupportedAppUsage setConfiguration(int mcc, int mnc, @Nullable 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 grammaticalGender, int majorVersion)1553 public void setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation, 1554 int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, 1555 int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, 1556 int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender, 1557 int majorVersion) { 1558 if (locale != null) { 1559 setConfiguration(mcc, mnc, null, new String[]{locale}, orientation, touchscreen, 1560 density, keyboard, keyboardHidden, navigation, screenWidth, screenHeight, 1561 smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode, 1562 colorMode, grammaticalGender, majorVersion); 1563 } else { 1564 setConfiguration(mcc, mnc, null, null, orientation, touchscreen, density, 1565 keyboard, keyboardHidden, navigation, screenWidth, screenHeight, 1566 smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode, 1567 colorMode, grammaticalGender, majorVersion); 1568 } 1569 } 1570 1571 /** 1572 * Change the configuration used when retrieving resources. Not for use by 1573 * applications. 1574 * @hide 1575 */ setConfiguration(int mcc, int mnc, String defaultLocale, String[] locales, 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 grammaticalGender, int majorVersion)1576 public void setConfiguration(int mcc, int mnc, String defaultLocale, String[] locales, 1577 int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, 1578 int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, 1579 int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode, 1580 int grammaticalGender, int majorVersion) { 1581 setConfigurationInternal(mcc, mnc, defaultLocale, locales, orientation, 1582 touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth, 1583 screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp, 1584 screenLayout, uiMode, colorMode, grammaticalGender, majorVersion, false); 1585 } 1586 1587 /** 1588 * Change the configuration used when retrieving resources, and potentially force a refresh of 1589 * the state. Not for use by applications. 1590 * @hide 1591 */ setConfigurationInternal(int mcc, int mnc, String defaultLocale, String[] locales, 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 grammaticalGender, int majorVersion, boolean forceRefresh)1592 void setConfigurationInternal(int mcc, int mnc, String defaultLocale, String[] locales, 1593 int orientation, int touchscreen, int density, int keyboard, int keyboardHidden, 1594 int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp, 1595 int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode, 1596 int grammaticalGender, int majorVersion, boolean forceRefresh) { 1597 synchronized (this) { 1598 ensureValidLocked(); 1599 nativeSetConfiguration(mObject, mcc, mnc, defaultLocale, locales, orientation, 1600 touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth, 1601 screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp, 1602 screenLayout, uiMode, colorMode, grammaticalGender, majorVersion, 1603 forceRefresh); 1604 } 1605 } 1606 1607 /** 1608 * @hide 1609 */ 1610 @UnsupportedAppUsage getAssignedPackageIdentifiers()1611 public SparseArray<String> getAssignedPackageIdentifiers() { 1612 return getAssignedPackageIdentifiers(true, true); 1613 } 1614 1615 /** 1616 * @hide 1617 */ getAssignedPackageIdentifiers(boolean includeOverlays, boolean includeLoaders)1618 public SparseArray<String> getAssignedPackageIdentifiers(boolean includeOverlays, 1619 boolean includeLoaders) { 1620 synchronized (this) { 1621 ensureValidLocked(); 1622 return nativeGetAssignedPackageIdentifiers(mObject, includeOverlays, includeLoaders); 1623 } 1624 } 1625 1626 /** 1627 * @hide 1628 */ 1629 @GuardedBy("this") getOverlayableMap(String packageName)1630 public @Nullable Map<String, String> getOverlayableMap(String packageName) { 1631 synchronized (this) { 1632 ensureValidLocked(); 1633 return nativeGetOverlayableMap(mObject, packageName); 1634 } 1635 } 1636 1637 /** 1638 * @hide 1639 */ 1640 @TestApi 1641 @GuardedBy("this") getOverlayablesToString(String packageName)1642 public @Nullable String getOverlayablesToString(String packageName) { 1643 synchronized (this) { 1644 ensureValidLocked(); 1645 return nativeGetOverlayablesToString(mObject, packageName); 1646 } 1647 } 1648 1649 @GuardedBy("this") incRefsLocked(long id)1650 private void incRefsLocked(long id) { 1651 if (DEBUG_REFS) { 1652 if (mRefStacks == null) { 1653 mRefStacks = new HashMap<>(); 1654 } 1655 RuntimeException ex = new RuntimeException(); 1656 ex.fillInStackTrace(); 1657 mRefStacks.put(id, ex); 1658 } 1659 mNumRefs++; 1660 } 1661 1662 @GuardedBy("this") decRefsLocked(long id)1663 private void decRefsLocked(long id) { 1664 if (DEBUG_REFS && mRefStacks != null) { 1665 mRefStacks.remove(id); 1666 } 1667 mNumRefs--; 1668 if (mNumRefs == 0 && mObject != 0) { 1669 nativeDestroy(mObject); 1670 mObject = 0; 1671 mApkAssets = sEmptyApkAssets; 1672 } 1673 } 1674 dump(PrintWriter pw, String prefix)1675 synchronized void dump(PrintWriter pw, String prefix) { 1676 pw.println(prefix + "class=" + getClass()); 1677 pw.println(prefix + "apkAssets="); 1678 for (int i = 0; i < mApkAssets.length; i++) { 1679 pw.println(prefix + i); 1680 mApkAssets[i].dump(pw, prefix + " "); 1681 } 1682 } 1683 1684 // AssetManager setup native methods. nativeCreate()1685 private static native long nativeCreate(); nativeDestroy(long ptr)1686 private static native void nativeDestroy(long ptr); nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets, boolean invalidateCaches, boolean preset)1687 private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets, 1688 boolean invalidateCaches, boolean preset); nativeSetConfiguration(long ptr, int mcc, int mnc, @Nullable String defaultLocale, @NonNull String[] locales, 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 grammaticalGender, int majorVersion, boolean forceRefresh)1689 private static native void nativeSetConfiguration(long ptr, int mcc, int mnc, 1690 @Nullable String defaultLocale, @NonNull String[] locales, int orientation, 1691 int touchscreen, int density, int keyboard, int keyboardHidden, int navigation, 1692 int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp, 1693 int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender, 1694 int majorVersion, boolean forceRefresh); nativeGetAssignedPackageIdentifiers( long ptr, boolean includeOverlays, boolean includeLoaders)1695 private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers( 1696 long ptr, boolean includeOverlays, boolean includeLoaders); 1697 1698 // File native methods. nativeContainsAllocatedTable(long ptr)1699 private static native boolean nativeContainsAllocatedTable(long ptr); nativeList(long ptr, @NonNull String path)1700 private static native @Nullable String[] nativeList(long ptr, @NonNull String path) 1701 throws IOException; nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode)1702 private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode); nativeOpenAssetFd(long ptr, @NonNull String fileName, long[] outOffsets)1703 private static native @Nullable ParcelFileDescriptor nativeOpenAssetFd(long ptr, 1704 @NonNull String fileName, long[] outOffsets) throws IOException; nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName, int accessMode)1705 private static native long nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName, 1706 int accessMode); nativeOpenNonAssetFd(long ptr, int cookie, @NonNull String fileName, @NonNull long[] outOffsets)1707 private static native @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int cookie, 1708 @NonNull String fileName, @NonNull long[] outOffsets) throws IOException; nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName)1709 private static native long nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName); nativeOpenXmlAssetFd(long ptr, int cookie, @NonNull FileDescriptor fileDescriptor)1710 private static native long nativeOpenXmlAssetFd(long ptr, int cookie, 1711 @NonNull FileDescriptor fileDescriptor); 1712 1713 // Primitive resource native methods. nativeGetResourceValue(long ptr, @AnyRes int resId, short density, @NonNull TypedValue outValue, boolean resolveReferences)1714 private static native int nativeGetResourceValue(long ptr, @AnyRes int resId, short density, 1715 @NonNull TypedValue outValue, boolean resolveReferences); nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId, @NonNull TypedValue outValue)1716 private static native int nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId, 1717 @NonNull TypedValue outValue); 1718 nativeGetStyleAttributes(long ptr, @StyleRes int resId)1719 private static native @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr, 1720 @StyleRes int resId); nativeGetResourceStringArray(long ptr, @ArrayRes int resId)1721 private static native @Nullable String[] nativeGetResourceStringArray(long ptr, 1722 @ArrayRes int resId); nativeGetResourceStringArrayInfo(long ptr, @ArrayRes int resId)1723 private static native @Nullable int[] nativeGetResourceStringArrayInfo(long ptr, 1724 @ArrayRes int resId); nativeGetResourceIntArray(long ptr, @ArrayRes int resId)1725 private static native @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resId); nativeGetResourceArraySize(long ptr, @ArrayRes int resId)1726 private static native int nativeGetResourceArraySize(long ptr, @ArrayRes int resId); nativeGetResourceArray(long ptr, @ArrayRes int resId, @NonNull int[] outValues)1727 private static native int nativeGetResourceArray(long ptr, @ArrayRes int resId, 1728 @NonNull int[] outValues); 1729 1730 // Resource name/ID native methods. nativeGetResourceIdentifier(long ptr, @NonNull String name, @Nullable String defType, @Nullable String defPackage)1731 private static native @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name, 1732 @Nullable String defType, @Nullable String defPackage); nativeGetResourceName(long ptr, @AnyRes int resid)1733 private static native @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid); nativeGetResourcePackageName(long ptr, @AnyRes int resid)1734 private static native @Nullable String nativeGetResourcePackageName(long ptr, 1735 @AnyRes int resid); nativeGetResourceTypeName(long ptr, @AnyRes int resid)1736 private static native @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid); nativeGetResourceEntryName(long ptr, @AnyRes int resid)1737 private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid); nativeGetLocales(long ptr, boolean excludeSystem)1738 private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem); nativeGetSizeConfigurations(long ptr)1739 private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr); nativeGetSizeAndUiModeConfigurations(long ptr)1740 private static native @Nullable Configuration[] nativeGetSizeAndUiModeConfigurations(long ptr); nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled)1741 private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled); nativeGetLastResourceResolution(long ptr)1742 private static native @Nullable String nativeGetLastResourceResolution(long ptr); 1743 1744 // Style attribute retrieval native methods. nativeAttributeResolutionStack(long ptr, long themePtr, @StyleRes int xmlStyleRes, @AttrRes int defStyleAttr, @StyleRes int defStyleRes)1745 private static native int[] nativeAttributeResolutionStack(long ptr, long themePtr, 1746 @StyleRes int xmlStyleRes, @AttrRes int defStyleAttr, @StyleRes int defStyleRes); nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs, long outValuesAddress, long outIndicesAddress)1747 private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, 1748 @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs, 1749 long outValuesAddress, long outIndicesAddress); nativeResolveAttrs(long ptr, long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1750 private static native boolean nativeResolveAttrs(long ptr, long themePtr, 1751 @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues, 1752 @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices); nativeRetrieveAttributes(long ptr, long xmlParserPtr, @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices)1753 private static native boolean nativeRetrieveAttributes(long ptr, long xmlParserPtr, 1754 @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices); 1755 1756 // Theme related native methods nativeThemeCreate(long ptr)1757 private static native long nativeThemeCreate(long ptr); nativeGetThemeFreeFunction()1758 private static native long nativeGetThemeFreeFunction(); nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId, boolean force)1759 private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId, 1760 boolean force); nativeThemeRebase(long ptr, long themePtr, @NonNull int[] styleIds, @NonNull boolean[] force, int styleSize)1761 private static native void nativeThemeRebase(long ptr, long themePtr, @NonNull int[] styleIds, 1762 @NonNull boolean[] force, int styleSize); nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr, long srcAssetManagerPtr, long srcThemePtr)1763 private static native void nativeThemeCopy(long dstAssetManagerPtr, long dstThemePtr, 1764 long srcAssetManagerPtr, long srcThemePtr); nativeThemeGetAttributeValue(long ptr, long themePtr, @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve)1765 private static native int nativeThemeGetAttributeValue(long ptr, long themePtr, 1766 @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve); nativeThemeDump(long ptr, long themePtr, int priority, String tag, String prefix)1767 private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag, 1768 String prefix); nativeThemeGetChangingConfigurations(long themePtr)1769 static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr); 1770 @StyleRes nativeGetParentThemeIdentifier(long ptr, @StyleRes int styleId)1771 private static native int nativeGetParentThemeIdentifier(long ptr, @StyleRes int styleId); 1772 1773 // AssetInputStream related native methods. nativeAssetDestroy(long assetPtr)1774 private static native void nativeAssetDestroy(long assetPtr); nativeAssetReadChar(long assetPtr)1775 private static native int nativeAssetReadChar(long assetPtr); nativeAssetRead(long assetPtr, byte[] b, int off, int len)1776 private static native int nativeAssetRead(long assetPtr, byte[] b, int off, int len); nativeAssetSeek(long assetPtr, long offset, int whence)1777 private static native long nativeAssetSeek(long assetPtr, long offset, int whence); nativeAssetGetLength(long assetPtr)1778 private static native long nativeAssetGetLength(long assetPtr); nativeAssetGetRemainingLength(long assetPtr)1779 private static native long nativeAssetGetRemainingLength(long assetPtr); 1780 nativeGetOverlayableMap(long ptr, @NonNull String packageName)1781 private static native @Nullable Map nativeGetOverlayableMap(long ptr, 1782 @NonNull String packageName); nativeGetOverlayablesToString(long ptr, @NonNull String packageName)1783 private static native @Nullable String nativeGetOverlayablesToString(long ptr, 1784 @NonNull String packageName); 1785 1786 // Global debug native methods. 1787 /** 1788 * @hide 1789 */ 1790 @UnsupportedAppUsage getGlobalAssetCount()1791 public static native int getGlobalAssetCount(); 1792 1793 /** 1794 * @hide 1795 */ getAssetAllocations()1796 public static native String getAssetAllocations(); 1797 1798 /** 1799 * @hide 1800 */ 1801 @UnsupportedAppUsage getGlobalAssetManagerCount()1802 public static native int getGlobalAssetManagerCount(); 1803 } 1804