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.annotation.AnyRes;
     20 import android.annotation.ArrayRes;
     21 import android.annotation.NonNull;
     22 import android.annotation.Nullable;
     23 import android.annotation.StringRes;
     24 import android.content.res.Configuration.NativeConfig;
     25 import android.os.ParcelFileDescriptor;
     26 import android.util.Log;
     27 import android.util.SparseArray;
     28 import android.util.TypedValue;
     29 
     30 import java.io.FileNotFoundException;
     31 import java.io.IOException;
     32 import java.io.InputStream;
     33 import 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  */
     42 public 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