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.pm.ActivityInfo;
25import android.content.res.Configuration.NativeConfig;
26import android.os.ParcelFileDescriptor;
27import android.util.Log;
28import android.util.SparseArray;
29import android.util.TypedValue;
30
31import dalvik.annotation.optimization.FastNative;
32
33import java.io.FileNotFoundException;
34import java.io.IOException;
35import java.io.InputStream;
36import 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 */
45public 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     */
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
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
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     */
134    public static AssetManager getSystem() {
135        ensureSystemAssets();
136        return sSystem;
137    }
138
139    /**
140     * Close this asset manager.
141     */
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
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
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
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     */
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     */
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     */
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
305    final StringBlock[] ensureStringBlocks() {
306        synchronized (this) {
307            if (mStringBlocks == null) {
308                makeStringBlocks(sSystem.mStringBlocks);
309            }
310            return mStringBlocks;
311        }
312    }
313
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
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     */
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     */
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
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     */
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     */
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     */
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     */
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     */
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
476    public final AssetFileDescriptor openNonAssetFd(String fileName)
477            throws IOException {
478        return openNonAssetFd(0, fileName);
479    }
480
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     */
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     */
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     */
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     */
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
556    /*package*/ void xmlBlockGone(int id) {
557        synchronized (this) {
558            decRefsLocked(id);
559        }
560    }
561
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
573    /*package*/ final void releaseTheme(long theme) {
574        synchronized (this) {
575            deleteTheme(theme);
576            decRefsLocked(theme);
577        }
578    }
579
580    protected void finalize() throws Throwable {
581        try {
582            if (DEBUG_REFS && mNumRefs != 0) {
583                Log.w(TAG, "AssetManager " + this
584                        + " finalized with non-zero refs: " + mNumRefs);
585                if (mRefStacks != null) {
586                    for (RuntimeException e : mRefStacks.values()) {
587                        Log.w(TAG, "Reference from here", e);
588                    }
589                }
590            }
591            destroy();
592        } finally {
593            super.finalize();
594        }
595    }
596
597    public final class AssetInputStream extends InputStream {
598        /**
599         * @hide
600         */
601        public final int getAssetInt() {
602            throw new UnsupportedOperationException();
603        }
604        /**
605         * @hide
606         */
607        public final long getNativeAsset() {
608            return mAsset;
609        }
610        private AssetInputStream(long asset)
611        {
612            mAsset = asset;
613            mLength = getAssetLength(asset);
614        }
615        public final int read() throws IOException {
616            return readAssetChar(mAsset);
617        }
618        public final boolean markSupported() {
619            return true;
620        }
621        public final int available() throws IOException {
622            long len = getAssetRemainingLength(mAsset);
623            return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)len;
624        }
625        public final void close() throws IOException {
626            synchronized (AssetManager.this) {
627                if (mAsset != 0) {
628                    destroyAsset(mAsset);
629                    mAsset = 0;
630                    decRefsLocked(hashCode());
631                }
632            }
633        }
634        public final void mark(int readlimit) {
635            mMarkPos = seekAsset(mAsset, 0, 0);
636        }
637        public final void reset() throws IOException {
638            seekAsset(mAsset, mMarkPos, -1);
639        }
640        public final int read(byte[] b) throws IOException {
641            return readAsset(mAsset, b, 0, b.length);
642        }
643        public final int read(byte[] b, int off, int len) throws IOException {
644            return readAsset(mAsset, b, off, len);
645        }
646        public final long skip(long n) throws IOException {
647            long pos = seekAsset(mAsset, 0, 0);
648            if ((pos+n) > mLength) {
649                n = mLength-pos;
650            }
651            if (n > 0) {
652                seekAsset(mAsset, n, 0);
653            }
654            return n;
655        }
656
657        protected void finalize() throws Throwable
658        {
659            close();
660        }
661
662        private long mAsset;
663        private long mLength;
664        private long mMarkPos;
665    }
666
667    /**
668     * Add an additional set of assets to the asset manager.  This can be
669     * either a directory or ZIP file.  Not for use by applications.  Returns
670     * the cookie of the added asset, or 0 on failure.
671     * {@hide}
672     */
673    public final int addAssetPath(String path) {
674        return  addAssetPathInternal(path, false);
675    }
676
677    /**
678     * Add an application assets to the asset manager and loading it as shared library.
679     * This can be either a directory or ZIP file.  Not for use by applications.  Returns
680     * the cookie of the added asset, or 0 on failure.
681     * {@hide}
682     */
683    public final int addAssetPathAsSharedLibrary(String path) {
684        return addAssetPathInternal(path, true);
685    }
686
687    private final int addAssetPathInternal(String path, boolean appAsLib) {
688        synchronized (this) {
689            int res = addAssetPathNative(path, appAsLib);
690            makeStringBlocks(mStringBlocks);
691            return res;
692        }
693    }
694
695    private native final int addAssetPathNative(String path, boolean appAsLib);
696
697     /**
698     * Add a set of assets to overlay an already added set of assets.
699     *
700     * This is only intended for application resources. System wide resources
701     * are handled before any Java code is executed.
702     *
703     * {@hide}
704     */
705
706    public final int addOverlayPath(String idmapPath) {
707        synchronized (this) {
708            int res = addOverlayPathNative(idmapPath);
709            makeStringBlocks(mStringBlocks);
710            return res;
711        }
712    }
713
714    /**
715     * See addOverlayPath.
716     *
717     * {@hide}
718     */
719    public native final int addOverlayPathNative(String idmapPath);
720
721    /**
722     * Add multiple sets of assets to the asset manager at once.  See
723     * {@link #addAssetPath(String)} for more information.  Returns array of
724     * cookies for each added asset with 0 indicating failure, or null if
725     * the input array of paths is null.
726     * {@hide}
727     */
728    public final int[] addAssetPaths(String[] paths) {
729        if (paths == null) {
730            return null;
731        }
732
733        int[] cookies = new int[paths.length];
734        for (int i = 0; i < paths.length; i++) {
735            cookies[i] = addAssetPath(paths[i]);
736        }
737
738        return cookies;
739    }
740
741    /**
742     * Determine whether the state in this asset manager is up-to-date with
743     * the files on the filesystem.  If false is returned, you need to
744     * instantiate a new AssetManager class to see the new data.
745     * {@hide}
746     */
747    public native final boolean isUpToDate();
748
749    /**
750     * Get the locales that this asset manager contains data for.
751     *
752     * <p>On SDK 21 (Android 5.0: Lollipop) and above, Locale strings are valid
753     * <a href="https://tools.ietf.org/html/bcp47">BCP-47</a> language tags and can be
754     * parsed using {@link java.util.Locale#forLanguageTag(String)}.
755     *
756     * <p>On SDK 20 (Android 4.4W: Kitkat for watches) and below, locale strings
757     * are of the form {@code ll_CC} where {@code ll} is a two letter language code,
758     * and {@code CC} is a two letter country code.
759     */
760    public native final String[] getLocales();
761
762    /**
763     * Same as getLocales(), except that locales that are only provided by the system (i.e. those
764     * present in framework-res.apk or its overlays) will not be listed.
765     *
766     * For example, if the "system" assets support English, French, and German, and the additional
767     * assets support Cherokee and French, getLocales() would return
768     * [Cherokee, English, French, German], while getNonSystemLocales() would return
769     * [Cherokee, French].
770     * {@hide}
771     */
772    public native final String[] getNonSystemLocales();
773
774    /** {@hide} */
775    public native final Configuration[] getSizeConfigurations();
776
777    /**
778     * Change the configuation used when retrieving resources.  Not for use by
779     * applications.
780     * {@hide}
781     */
782    public native final void setConfiguration(int mcc, int mnc, String locale,
783            int orientation, int touchscreen, int density, int keyboard,
784            int keyboardHidden, int navigation, int screenWidth, int screenHeight,
785            int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp,
786            int screenLayout, int uiMode, int colorMode, int majorVersion);
787
788    /**
789     * Retrieve the resource identifier for the given resource name.
790     */
791    /*package*/ native final int getResourceIdentifier(String name,
792                                                       String defType,
793                                                       String defPackage);
794
795    /*package*/ native final String getResourceName(int resid);
796    /*package*/ native final String getResourcePackageName(int resid);
797    /*package*/ native final String getResourceTypeName(int resid);
798    /*package*/ native final String getResourceEntryName(int resid);
799
800    private native final long openAsset(String fileName, int accessMode);
801    private final native ParcelFileDescriptor openAssetFd(String fileName,
802            long[] outOffsets) throws IOException;
803    private native final long openNonAssetNative(int cookie, String fileName,
804            int accessMode);
805    private native ParcelFileDescriptor openNonAssetFdNative(int cookie,
806            String fileName, long[] outOffsets) throws IOException;
807    private native final void destroyAsset(long asset);
808    private native final int readAssetChar(long asset);
809    private native final int readAsset(long asset, byte[] b, int off, int len);
810    private native final long seekAsset(long asset, long offset, int whence);
811    private native final long getAssetLength(long asset);
812    private native final long getAssetRemainingLength(long asset);
813
814    /** Returns true if the resource was found, filling in mRetStringBlock and
815     *  mRetData. */
816    private native final int loadResourceValue(int ident, short density, TypedValue outValue,
817            boolean resolve);
818    /** Returns true if the resource was found, filling in mRetStringBlock and
819     *  mRetData. */
820    private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
821                                               boolean resolve);
822    /*package*/ static final int STYLE_NUM_ENTRIES = 6;
823    /*package*/ static final int STYLE_TYPE = 0;
824    /*package*/ static final int STYLE_DATA = 1;
825    /*package*/ static final int STYLE_ASSET_COOKIE = 2;
826    /*package*/ static final int STYLE_RESOURCE_ID = 3;
827
828    /* Offset within typed data array for native changingConfigurations. */
829    static final int STYLE_CHANGING_CONFIGURATIONS = 4;
830
831    /*package*/ static final int STYLE_DENSITY = 5;
832    /*package*/ native static final void applyStyle(long theme,
833            int defStyleAttr, int defStyleRes, long xmlParser,
834            int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress);
835    /*package*/ native static final boolean resolveAttrs(long theme,
836            int defStyleAttr, int defStyleRes, int[] inValues,
837            int[] inAttrs, int[] outValues, int[] outIndices);
838    /*package*/ native final boolean retrieveAttributes(
839            long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
840    /*package*/ native final int getArraySize(int resource);
841    /*package*/ native final int retrieveArray(int resource, int[] outValues);
842    private native final int getStringBlockCount();
843    private native final long getNativeStringBlock(int block);
844
845    /**
846     * {@hide}
847     */
848    public native final String getCookieName(int cookie);
849
850    /**
851     * {@hide}
852     */
853    public native final SparseArray<String> getAssignedPackageIdentifiers();
854
855    /**
856     * {@hide}
857     */
858    public native static final int getGlobalAssetCount();
859
860    /**
861     * {@hide}
862     */
863    public native static final String getAssetAllocations();
864
865    /**
866     * {@hide}
867     */
868    public native static final int getGlobalAssetManagerCount();
869
870    private native final long newTheme();
871    private native final void deleteTheme(long theme);
872    /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
873    /*package*/ native static final void copyTheme(long dest, long source);
874    /*package*/ native static final void clearTheme(long theme);
875    /*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
876                                                                TypedValue outValue,
877                                                                boolean resolve);
878    /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
879    /*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme);
880
881    private native final long openXmlAssetNative(int cookie, String fileName);
882
883    private native final String[] getArrayStringResource(int arrayRes);
884    private native final int[] getArrayStringInfo(int arrayRes);
885    /*package*/ native final int[] getArrayIntResource(int arrayRes);
886    /*package*/ native final int[] getStyleAttributes(int themeRes);
887
888    private native final void init(boolean isSystem);
889    private native final void destroy();
890
891    private final void incRefsLocked(long id) {
892        if (DEBUG_REFS) {
893            if (mRefStacks == null) {
894                mRefStacks = new HashMap<Long, RuntimeException>();
895            }
896            RuntimeException ex = new RuntimeException();
897            ex.fillInStackTrace();
898            mRefStacks.put(id, ex);
899        }
900        mNumRefs++;
901    }
902
903    private final void decRefsLocked(long id) {
904        if (DEBUG_REFS && mRefStacks != null) {
905            mRefStacks.remove(id);
906        }
907        mNumRefs--;
908        //System.out.println("Dec streams: mNumRefs=" + mNumRefs
909        //                   + " mReleased=" + mReleased);
910        if (mNumRefs == 0) {
911            destroy();
912        }
913    }
914}
915