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