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