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