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