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.pm.ActivityInfo;
     25 import android.content.res.Configuration.NativeConfig;
     26 import android.os.ParcelFileDescriptor;
     27 import android.util.Log;
     28 import android.util.SparseArray;
     29 import android.util.TypedValue;
     30 
     31 import dalvik.annotation.optimization.FastNative;
     32 
     33 import java.io.FileNotFoundException;
     34 import java.io.IOException;
     35 import java.io.InputStream;
     36 import 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  */
     45 public 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