Home | History | Annotate | Download | only in res
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.content.res;
     18 
     19 import android.os.ParcelFileDescriptor;
     20 import android.util.Log;
     21 import android.util.SparseArray;
     22 import android.util.TypedValue;
     23 
     24 import java.io.FileNotFoundException;
     25 import java.io.IOException;
     26 import java.io.InputStream;
     27 import 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  */
     36 public 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