Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2007 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.os;
     18 
     19 import android.annotation.TestApi;
     20 import android.app.admin.DevicePolicyManager;
     21 import android.content.Context;
     22 import android.os.storage.StorageManager;
     23 import android.os.storage.StorageVolume;
     24 import android.text.TextUtils;
     25 import android.util.Log;
     26 
     27 import java.io.File;
     28 import java.util.LinkedList;
     29 
     30 /**
     31  * Provides access to environment variables.
     32  */
     33 public class Environment {
     34     private static final String TAG = "Environment";
     35 
     36     private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
     37     private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
     38     private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
     39     private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND";
     40     private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
     41     private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
     42     private static final String ENV_OEM_ROOT = "OEM_ROOT";
     43     private static final String ENV_ODM_ROOT = "ODM_ROOT";
     44     private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
     45     private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
     46 
     47     /** {@hide} */
     48     public static final String DIR_ANDROID = "Android";
     49     private static final String DIR_DATA = "data";
     50     private static final String DIR_MEDIA = "media";
     51     private static final String DIR_OBB = "obb";
     52     private static final String DIR_FILES = "files";
     53     private static final String DIR_CACHE = "cache";
     54 
     55     /** {@hide} */
     56     @Deprecated
     57     public static final String DIRECTORY_ANDROID = DIR_ANDROID;
     58 
     59     private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
     60     private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
     61     private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand");
     62     private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
     63     private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
     64     private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
     65     private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
     66     private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
     67     private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
     68 
     69     private static UserEnvironment sCurrentUser;
     70     private static boolean sUserRequired;
     71 
     72     static {
     73         initForCurrentUser();
     74     }
     75 
     76     /** {@hide} */
     77     public static void initForCurrentUser() {
     78         final int userId = UserHandle.myUserId();
     79         sCurrentUser = new UserEnvironment(userId);
     80     }
     81 
     82     /** {@hide} */
     83     public static class UserEnvironment {
     84         private final int mUserId;
     85 
     86         public UserEnvironment(int userId) {
     87             mUserId = userId;
     88         }
     89 
     90         public File[] getExternalDirs() {
     91             final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,
     92                     StorageManager.FLAG_FOR_WRITE);
     93             final File[] files = new File[volumes.length];
     94             for (int i = 0; i < volumes.length; i++) {
     95                 files[i] = volumes[i].getPathFile();
     96             }
     97             return files;
     98         }
     99 
    100         @Deprecated
    101         public File getExternalStorageDirectory() {
    102             return getExternalDirs()[0];
    103         }
    104 
    105         @Deprecated
    106         public File getExternalStoragePublicDirectory(String type) {
    107             return buildExternalStoragePublicDirs(type)[0];
    108         }
    109 
    110         public File[] buildExternalStoragePublicDirs(String type) {
    111             return buildPaths(getExternalDirs(), type);
    112         }
    113 
    114         public File[] buildExternalStorageAndroidDataDirs() {
    115             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA);
    116         }
    117 
    118         public File[] buildExternalStorageAndroidObbDirs() {
    119             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB);
    120         }
    121 
    122         public File[] buildExternalStorageAppDataDirs(String packageName) {
    123             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName);
    124         }
    125 
    126         public File[] buildExternalStorageAppMediaDirs(String packageName) {
    127             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName);
    128         }
    129 
    130         public File[] buildExternalStorageAppObbDirs(String packageName) {
    131             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName);
    132         }
    133 
    134         public File[] buildExternalStorageAppFilesDirs(String packageName) {
    135             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
    136         }
    137 
    138         public File[] buildExternalStorageAppCacheDirs(String packageName) {
    139             return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
    140         }
    141     }
    142 
    143     /**
    144      * Return root of the "system" partition holding the core Android OS.
    145      * Always present and mounted read-only.
    146      */
    147     public static File getRootDirectory() {
    148         return DIR_ANDROID_ROOT;
    149     }
    150 
    151     /** {@hide} */
    152     public static File getStorageDirectory() {
    153         return DIR_ANDROID_STORAGE;
    154     }
    155 
    156     /**
    157      * Return root directory of the "oem" partition holding OEM customizations,
    158      * if any. If present, the partition is mounted read-only.
    159      *
    160      * @hide
    161      */
    162     public static File getOemDirectory() {
    163         return DIR_OEM_ROOT;
    164     }
    165 
    166     /**
    167      * Return root directory of the "odm" partition holding ODM customizations,
    168      * if any. If present, the partition is mounted read-only.
    169      *
    170      * @hide
    171      */
    172     public static File getOdmDirectory() {
    173         return DIR_ODM_ROOT;
    174     }
    175 
    176     /**
    177      * Return root directory of the "vendor" partition that holds vendor-provided
    178      * software that should persist across simple reflashing of the "system" partition.
    179      * @hide
    180      */
    181     public static File getVendorDirectory() {
    182         return DIR_VENDOR_ROOT;
    183     }
    184 
    185     /**
    186      * Return root directory of the "product" partition holding product-specific
    187      * customizations if any. If present, the partition is mounted read-only.
    188      *
    189      * @hide
    190      */
    191     public static File getProductDirectory() {
    192         return DIR_PRODUCT_ROOT;
    193     }
    194 
    195     /**
    196      * Return the system directory for a user. This is for use by system
    197      * services to store files relating to the user. This directory will be
    198      * automatically deleted when the user is removed.
    199      *
    200      * @deprecated This directory is valid and still exists, but callers should
    201      *             <em>strongly</em> consider switching to
    202      *             {@link #getDataSystemCeDirectory(int)} which is protected
    203      *             with user credentials or
    204      *             {@link #getDataSystemDeDirectory(int)} which supports fast
    205      *             user wipe.
    206      * @hide
    207      */
    208     @Deprecated
    209     public static File getUserSystemDirectory(int userId) {
    210         return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
    211     }
    212 
    213     /**
    214      * Returns the config directory for a user. This is for use by system
    215      * services to store files relating to the user which should be readable by
    216      * any app running as that user.
    217      *
    218      * @deprecated This directory is valid and still exists, but callers should
    219      *             <em>strongly</em> consider switching to
    220      *             {@link #getDataMiscCeDirectory(int)} which is protected with
    221      *             user credentials or {@link #getDataMiscDeDirectory(int)}
    222      *             which supports fast user wipe.
    223      * @hide
    224      */
    225     @Deprecated
    226     public static File getUserConfigDirectory(int userId) {
    227         return new File(new File(new File(
    228                 getDataDirectory(), "misc"), "user"), Integer.toString(userId));
    229     }
    230 
    231     /**
    232      * Return the user data directory.
    233      */
    234     public static File getDataDirectory() {
    235         return DIR_ANDROID_DATA;
    236     }
    237 
    238     /** {@hide} */
    239     public static File getDataDirectory(String volumeUuid) {
    240         if (TextUtils.isEmpty(volumeUuid)) {
    241             return DIR_ANDROID_DATA;
    242         } else {
    243             return new File("/mnt/expand/" + volumeUuid);
    244         }
    245     }
    246 
    247     /** {@hide} */
    248     public static File getExpandDirectory() {
    249         return DIR_ANDROID_EXPAND;
    250     }
    251 
    252     /** {@hide} */
    253     public static File getDataSystemDirectory() {
    254         return new File(getDataDirectory(), "system");
    255     }
    256 
    257     /**
    258      * Returns the base directory for per-user system directory, device encrypted.
    259      * {@hide}
    260      */
    261     public static File getDataSystemDeDirectory() {
    262         return buildPath(getDataDirectory(), "system_de");
    263     }
    264 
    265     /**
    266      * Returns the base directory for per-user system directory, credential encrypted.
    267      * {@hide}
    268      */
    269     public static File getDataSystemCeDirectory() {
    270         return buildPath(getDataDirectory(), "system_ce");
    271     }
    272 
    273     /** {@hide} */
    274     public static File getDataSystemCeDirectory(int userId) {
    275         return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
    276     }
    277 
    278     /** {@hide} */
    279     public static File getDataSystemDeDirectory(int userId) {
    280         return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
    281     }
    282 
    283     /** {@hide} */
    284     public static File getDataMiscDirectory() {
    285         return new File(getDataDirectory(), "misc");
    286     }
    287 
    288     /** {@hide} */
    289     public static File getDataMiscCeDirectory() {
    290         return buildPath(getDataDirectory(), "misc_ce");
    291     }
    292 
    293     /** {@hide} */
    294     public static File getDataMiscCeDirectory(int userId) {
    295         return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
    296     }
    297 
    298     /** {@hide} */
    299     public static File getDataMiscDeDirectory(int userId) {
    300         return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
    301     }
    302 
    303     private static File getDataProfilesDeDirectory(int userId) {
    304         return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
    305     }
    306 
    307     /** {@hide} */
    308     public static File getDataVendorCeDirectory(int userId) {
    309         return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId));
    310     }
    311 
    312     /** {@hide} */
    313     public static File getDataVendorDeDirectory(int userId) {
    314         return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId));
    315     }
    316 
    317     /** {@hide} */
    318     public static File getDataRefProfilesDePackageDirectory(String packageName) {
    319         return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
    320     }
    321 
    322     /** {@hide} */
    323     public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
    324         return buildPath(getDataProfilesDeDirectory(userId), packageName);
    325     }
    326 
    327     /** {@hide} */
    328     public static File getDataAppDirectory(String volumeUuid) {
    329         return new File(getDataDirectory(volumeUuid), "app");
    330     }
    331 
    332     /** {@hide} */
    333     public static File getDataUserCeDirectory(String volumeUuid) {
    334         return new File(getDataDirectory(volumeUuid), "user");
    335     }
    336 
    337     /** {@hide} */
    338     public static File getDataUserCeDirectory(String volumeUuid, int userId) {
    339         return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
    340     }
    341 
    342     /** {@hide} */
    343     public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
    344             String packageName) {
    345         // TODO: keep consistent with installd
    346         return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
    347     }
    348 
    349     /** {@hide} */
    350     public static File getDataUserDeDirectory(String volumeUuid) {
    351         return new File(getDataDirectory(volumeUuid), "user_de");
    352     }
    353 
    354     /** {@hide} */
    355     public static File getDataUserDeDirectory(String volumeUuid, int userId) {
    356         return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
    357     }
    358 
    359     /** {@hide} */
    360     public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
    361             String packageName) {
    362         // TODO: keep consistent with installd
    363         return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
    364     }
    365 
    366     /**
    367      * Return preloads directory.
    368      * <p>This directory may contain pre-loaded content such as
    369      * {@link #getDataPreloadsDemoDirectory() demo videos} and
    370      * {@link #getDataPreloadsAppsDirectory() APK files} .
    371      * {@hide}
    372      */
    373     public static File getDataPreloadsDirectory() {
    374         return new File(getDataDirectory(), "preloads");
    375     }
    376 
    377     /**
    378      * @see #getDataPreloadsDirectory()
    379      * {@hide}
    380      */
    381     public static File getDataPreloadsDemoDirectory() {
    382         return new File(getDataPreloadsDirectory(), "demo");
    383     }
    384 
    385     /**
    386      * @see #getDataPreloadsDirectory()
    387      * {@hide}
    388      */
    389     public static File getDataPreloadsAppsDirectory() {
    390         return new File(getDataPreloadsDirectory(), "apps");
    391     }
    392 
    393     /**
    394      * @see #getDataPreloadsDirectory()
    395      * {@hide}
    396      */
    397     public static File getDataPreloadsMediaDirectory() {
    398         return new File(getDataPreloadsDirectory(), "media");
    399     }
    400 
    401     /**
    402      * Returns location of preloaded cache directory for package name
    403      * @see #getDataPreloadsDirectory()
    404      * {@hide}
    405      */
    406     public static File getDataPreloadsFileCacheDirectory(String packageName) {
    407         return new File(getDataPreloadsFileCacheDirectory(), packageName);
    408     }
    409 
    410     /**
    411      * Returns location of preloaded cache directory.
    412      * @see #getDataPreloadsDirectory()
    413      * {@hide}
    414      */
    415     public static File getDataPreloadsFileCacheDirectory() {
    416         return new File(getDataPreloadsDirectory(), "file_cache");
    417     }
    418 
    419     /**
    420      * Return the primary shared/external storage directory. This directory may
    421      * not currently be accessible if it has been mounted by the user on their
    422      * computer, has been removed from the device, or some other problem has
    423      * happened. You can determine its current state with
    424      * {@link #getExternalStorageState()}.
    425      * <p>
    426      * <em>Note: don't be confused by the word "external" here. This directory
    427      * can better be thought as media/shared storage. It is a filesystem that
    428      * can hold a relatively large amount of data and that is shared across all
    429      * applications (does not enforce permissions). Traditionally this is an SD
    430      * card, but it may also be implemented as built-in storage in a device that
    431      * is distinct from the protected internal storage and can be mounted as a
    432      * filesystem on a computer.</em>
    433      * <p>
    434      * On devices with multiple users (as described by {@link UserManager}),
    435      * each user has their own isolated shared storage. Applications only have
    436      * access to the shared storage for the user they're running as.
    437      * <p>
    438      * In devices with multiple shared/external storage directories, this
    439      * directory represents the primary storage that the user will interact
    440      * with. Access to secondary storage is available through
    441      * {@link Context#getExternalFilesDirs(String)},
    442      * {@link Context#getExternalCacheDirs()}, and
    443      * {@link Context#getExternalMediaDirs()}.
    444      * <p>
    445      * Applications should not directly use this top-level directory, in order
    446      * to avoid polluting the user's root namespace. Any files that are private
    447      * to the application should be placed in a directory returned by
    448      * {@link android.content.Context#getExternalFilesDir
    449      * Context.getExternalFilesDir}, which the system will take care of deleting
    450      * if the application is uninstalled. Other shared files should be placed in
    451      * one of the directories returned by
    452      * {@link #getExternalStoragePublicDirectory}.
    453      * <p>
    454      * Writing to this path requires the
    455      * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
    456      * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read access requires the
    457      * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
    458      * which is automatically granted if you hold the write permission.
    459      * <p>
    460      * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
    461      * application only needs to store internal data, consider using
    462      * {@link Context#getExternalFilesDir(String)},
    463      * {@link Context#getExternalCacheDir()}, or
    464      * {@link Context#getExternalMediaDirs()}, which require no permissions to
    465      * read or write.
    466      * <p>
    467      * This path may change between platform versions, so applications should
    468      * only persist relative paths.
    469      * <p>
    470      * Here is an example of typical code to monitor the state of external
    471      * storage:
    472      * <p>
    473      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
    474      * monitor_storage}
    475      *
    476      * @see #getExternalStorageState()
    477      * @see #isExternalStorageRemovable()
    478      */
    479     public static File getExternalStorageDirectory() {
    480         throwIfUserRequired();
    481         return sCurrentUser.getExternalDirs()[0];
    482     }
    483 
    484     /** {@hide} */
    485     public static File getLegacyExternalStorageDirectory() {
    486         return new File(System.getenv(ENV_EXTERNAL_STORAGE));
    487     }
    488 
    489     /** {@hide} */
    490     public static File getLegacyExternalStorageObbDirectory() {
    491         return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
    492     }
    493 
    494     /**
    495      * Standard directory in which to place any audio files that should be
    496      * in the regular list of music for the user.
    497      * This may be combined with
    498      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
    499      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    500      * of directories to categories a particular audio file as more than one
    501      * type.
    502      */
    503     public static String DIRECTORY_MUSIC = "Music";
    504 
    505     /**
    506      * Standard directory in which to place any audio files that should be
    507      * in the list of podcasts that the user can select (not as regular
    508      * music).
    509      * This may be combined with {@link #DIRECTORY_MUSIC},
    510      * {@link #DIRECTORY_NOTIFICATIONS},
    511      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    512      * of directories to categories a particular audio file as more than one
    513      * type.
    514      */
    515     public static String DIRECTORY_PODCASTS = "Podcasts";
    516 
    517     /**
    518      * Standard directory in which to place any audio files that should be
    519      * in the list of ringtones that the user can select (not as regular
    520      * music).
    521      * This may be combined with {@link #DIRECTORY_MUSIC},
    522      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
    523      * {@link #DIRECTORY_ALARMS} as a series
    524      * of directories to categories a particular audio file as more than one
    525      * type.
    526      */
    527     public static String DIRECTORY_RINGTONES = "Ringtones";
    528 
    529     /**
    530      * Standard directory in which to place any audio files that should be
    531      * in the list of alarms that the user can select (not as regular
    532      * music).
    533      * This may be combined with {@link #DIRECTORY_MUSIC},
    534      * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
    535      * and {@link #DIRECTORY_RINGTONES} as a series
    536      * of directories to categories a particular audio file as more than one
    537      * type.
    538      */
    539     public static String DIRECTORY_ALARMS = "Alarms";
    540 
    541     /**
    542      * Standard directory in which to place any audio files that should be
    543      * in the list of notifications that the user can select (not as regular
    544      * music).
    545      * This may be combined with {@link #DIRECTORY_MUSIC},
    546      * {@link #DIRECTORY_PODCASTS},
    547      * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
    548      * of directories to categories a particular audio file as more than one
    549      * type.
    550      */
    551     public static String DIRECTORY_NOTIFICATIONS = "Notifications";
    552 
    553     /**
    554      * Standard directory in which to place pictures that are available to
    555      * the user.  Note that this is primarily a convention for the top-level
    556      * public directory, as the media scanner will find and collect pictures
    557      * in any directory.
    558      */
    559     public static String DIRECTORY_PICTURES = "Pictures";
    560 
    561     /**
    562      * Standard directory in which to place movies that are available to
    563      * the user.  Note that this is primarily a convention for the top-level
    564      * public directory, as the media scanner will find and collect movies
    565      * in any directory.
    566      */
    567     public static String DIRECTORY_MOVIES = "Movies";
    568 
    569     /**
    570      * Standard directory in which to place files that have been downloaded by
    571      * the user.  Note that this is primarily a convention for the top-level
    572      * public directory, you are free to download files anywhere in your own
    573      * private directories.  Also note that though the constant here is
    574      * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
    575      * backwards compatibility reasons.
    576      */
    577     public static String DIRECTORY_DOWNLOADS = "Download";
    578 
    579     /**
    580      * The traditional location for pictures and videos when mounting the
    581      * device as a camera.  Note that this is primarily a convention for the
    582      * top-level public directory, as this convention makes no sense elsewhere.
    583      */
    584     public static String DIRECTORY_DCIM = "DCIM";
    585 
    586     /**
    587      * Standard directory in which to place documents that have been created by
    588      * the user.
    589      */
    590     public static String DIRECTORY_DOCUMENTS = "Documents";
    591 
    592     /**
    593      * List of standard storage directories.
    594      * <p>
    595      * Each of its values have its own constant:
    596      * <ul>
    597      *   <li>{@link #DIRECTORY_MUSIC}
    598      *   <li>{@link #DIRECTORY_PODCASTS}
    599      *   <li>{@link #DIRECTORY_ALARMS}
    600      *   <li>{@link #DIRECTORY_RINGTONES}
    601      *   <li>{@link #DIRECTORY_NOTIFICATIONS}
    602      *   <li>{@link #DIRECTORY_PICTURES}
    603      *   <li>{@link #DIRECTORY_MOVIES}
    604      *   <li>{@link #DIRECTORY_DOWNLOADS}
    605      *   <li>{@link #DIRECTORY_DCIM}
    606      *   <li>{@link #DIRECTORY_DOCUMENTS}
    607      * </ul>
    608      * @hide
    609      */
    610     public static final String[] STANDARD_DIRECTORIES = {
    611             DIRECTORY_MUSIC,
    612             DIRECTORY_PODCASTS,
    613             DIRECTORY_RINGTONES,
    614             DIRECTORY_ALARMS,
    615             DIRECTORY_NOTIFICATIONS,
    616             DIRECTORY_PICTURES,
    617             DIRECTORY_MOVIES,
    618             DIRECTORY_DOWNLOADS,
    619             DIRECTORY_DCIM,
    620             DIRECTORY_DOCUMENTS
    621     };
    622 
    623     /**
    624      * @hide
    625      */
    626     public static boolean isStandardDirectory(String dir) {
    627         for (String valid : STANDARD_DIRECTORIES) {
    628             if (valid.equals(dir)) {
    629                 return true;
    630             }
    631         }
    632         return false;
    633     }
    634 
    635     /** {@hide} */ public static final int HAS_MUSIC = 1 << 0;
    636     /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1;
    637     /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2;
    638     /** {@hide} */ public static final int HAS_ALARMS = 1 << 3;
    639     /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4;
    640     /** {@hide} */ public static final int HAS_PICTURES = 1 << 5;
    641     /** {@hide} */ public static final int HAS_MOVIES = 1 << 6;
    642     /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7;
    643     /** {@hide} */ public static final int HAS_DCIM = 1 << 8;
    644     /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9;
    645 
    646     /** {@hide} */ public static final int HAS_ANDROID = 1 << 16;
    647     /** {@hide} */ public static final int HAS_OTHER = 1 << 17;
    648 
    649     /**
    650      * Classify the content types present on the given external storage device.
    651      * <p>
    652      * This is typically useful for deciding if an inserted SD card is empty, or
    653      * if it contains content like photos that should be preserved.
    654      *
    655      * @hide
    656      */
    657     public static int classifyExternalStorageDirectory(File dir) {
    658         int res = 0;
    659         for (File f : FileUtils.listFilesOrEmpty(dir)) {
    660             if (f.isFile() && isInterestingFile(f)) {
    661                 res |= HAS_OTHER;
    662             } else if (f.isDirectory() && hasInterestingFiles(f)) {
    663                 final String name = f.getName();
    664                 if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC;
    665                 else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS;
    666                 else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES;
    667                 else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS;
    668                 else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS;
    669                 else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES;
    670                 else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES;
    671                 else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS;
    672                 else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM;
    673                 else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS;
    674                 else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID;
    675                 else res |= HAS_OTHER;
    676             }
    677         }
    678         return res;
    679     }
    680 
    681     private static boolean hasInterestingFiles(File dir) {
    682         final LinkedList<File> explore = new LinkedList<>();
    683         explore.add(dir);
    684         while (!explore.isEmpty()) {
    685             dir = explore.pop();
    686             for (File f : FileUtils.listFilesOrEmpty(dir)) {
    687                 if (isInterestingFile(f)) return true;
    688                 if (f.isDirectory()) explore.add(f);
    689             }
    690         }
    691         return false;
    692     }
    693 
    694     private static boolean isInterestingFile(File file) {
    695         if (file.isFile()) {
    696             final String name = file.getName().toLowerCase();
    697             if (name.endsWith(".exe") || name.equals("autorun.inf")
    698                     || name.equals("launchpad.zip") || name.equals(".nomedia")) {
    699                 return false;
    700             } else {
    701                 return true;
    702             }
    703         } else {
    704             return false;
    705         }
    706     }
    707 
    708     /**
    709      * Get a top-level shared/external storage directory for placing files of a
    710      * particular type. This is where the user will typically place and manage
    711      * their own files, so you should be careful about what you put here to
    712      * ensure you don't erase their files or get in the way of their own
    713      * organization.
    714      * <p>
    715      * On devices with multiple users (as described by {@link UserManager}),
    716      * each user has their own isolated shared storage. Applications only have
    717      * access to the shared storage for the user they're running as.
    718      * </p>
    719      * <p>
    720      * Here is an example of typical code to manipulate a picture on the public
    721      * shared storage:
    722      * </p>
    723      * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
    724      * public_picture}
    725      *
    726      * @param type The type of storage directory to return. Should be one of
    727      *            {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
    728      *            {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
    729      *            {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
    730      *            {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS},
    731      *            {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null.
    732      * @return Returns the File path for the directory. Note that this directory
    733      *         may not yet exist, so you must make sure it exists before using
    734      *         it such as with {@link File#mkdirs File.mkdirs()}.
    735      */
    736     public static File getExternalStoragePublicDirectory(String type) {
    737         throwIfUserRequired();
    738         return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
    739     }
    740 
    741     /**
    742      * Returns the path for android-specific data on the SD card.
    743      * @hide
    744      */
    745     public static File[] buildExternalStorageAndroidDataDirs() {
    746         throwIfUserRequired();
    747         return sCurrentUser.buildExternalStorageAndroidDataDirs();
    748     }
    749 
    750     /**
    751      * Generates the raw path to an application's data
    752      * @hide
    753      */
    754     public static File[] buildExternalStorageAppDataDirs(String packageName) {
    755         throwIfUserRequired();
    756         return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
    757     }
    758 
    759     /**
    760      * Generates the raw path to an application's media
    761      * @hide
    762      */
    763     public static File[] buildExternalStorageAppMediaDirs(String packageName) {
    764         throwIfUserRequired();
    765         return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
    766     }
    767 
    768     /**
    769      * Generates the raw path to an application's OBB files
    770      * @hide
    771      */
    772     public static File[] buildExternalStorageAppObbDirs(String packageName) {
    773         throwIfUserRequired();
    774         return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
    775     }
    776 
    777     /**
    778      * Generates the path to an application's files.
    779      * @hide
    780      */
    781     public static File[] buildExternalStorageAppFilesDirs(String packageName) {
    782         throwIfUserRequired();
    783         return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
    784     }
    785 
    786     /**
    787      * Generates the path to an application's cache.
    788      * @hide
    789      */
    790     public static File[] buildExternalStorageAppCacheDirs(String packageName) {
    791         throwIfUserRequired();
    792         return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
    793     }
    794 
    795     /**
    796      * Return the download/cache content directory.
    797      */
    798     public static File getDownloadCacheDirectory() {
    799         return DIR_DOWNLOAD_CACHE;
    800     }
    801 
    802     /**
    803      * Unknown storage state, such as when a path isn't backed by known storage
    804      * media.
    805      *
    806      * @see #getExternalStorageState(File)
    807      */
    808     public static final String MEDIA_UNKNOWN = "unknown";
    809 
    810     /**
    811      * Storage state if the media is not present.
    812      *
    813      * @see #getExternalStorageState(File)
    814      */
    815     public static final String MEDIA_REMOVED = "removed";
    816 
    817     /**
    818      * Storage state if the media is present but not mounted.
    819      *
    820      * @see #getExternalStorageState(File)
    821      */
    822     public static final String MEDIA_UNMOUNTED = "unmounted";
    823 
    824     /**
    825      * Storage state if the media is present and being disk-checked.
    826      *
    827      * @see #getExternalStorageState(File)
    828      */
    829     public static final String MEDIA_CHECKING = "checking";
    830 
    831     /**
    832      * Storage state if the media is present but is blank or is using an
    833      * unsupported filesystem.
    834      *
    835      * @see #getExternalStorageState(File)
    836      */
    837     public static final String MEDIA_NOFS = "nofs";
    838 
    839     /**
    840      * Storage state if the media is present and mounted at its mount point with
    841      * read/write access.
    842      *
    843      * @see #getExternalStorageState(File)
    844      */
    845     public static final String MEDIA_MOUNTED = "mounted";
    846 
    847     /**
    848      * Storage state if the media is present and mounted at its mount point with
    849      * read-only access.
    850      *
    851      * @see #getExternalStorageState(File)
    852      */
    853     public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
    854 
    855     /**
    856      * Storage state if the media is present not mounted, and shared via USB
    857      * mass storage.
    858      *
    859      * @see #getExternalStorageState(File)
    860      */
    861     public static final String MEDIA_SHARED = "shared";
    862 
    863     /**
    864      * Storage state if the media was removed before it was unmounted.
    865      *
    866      * @see #getExternalStorageState(File)
    867      */
    868     public static final String MEDIA_BAD_REMOVAL = "bad_removal";
    869 
    870     /**
    871      * Storage state if the media is present but cannot be mounted. Typically
    872      * this happens if the file system on the media is corrupted.
    873      *
    874      * @see #getExternalStorageState(File)
    875      */
    876     public static final String MEDIA_UNMOUNTABLE = "unmountable";
    877 
    878     /**
    879      * Storage state if the media is in the process of being ejected.
    880      *
    881      * @see #getExternalStorageState(File)
    882      */
    883     public static final String MEDIA_EJECTING = "ejecting";
    884 
    885     /**
    886      * Returns the current state of the primary shared/external storage media.
    887      *
    888      * @see #getExternalStorageDirectory()
    889      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
    890      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
    891      *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
    892      *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
    893      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
    894      */
    895     public static String getExternalStorageState() {
    896         final File externalDir = sCurrentUser.getExternalDirs()[0];
    897         return getExternalStorageState(externalDir);
    898     }
    899 
    900     /**
    901      * @deprecated use {@link #getExternalStorageState(File)}
    902      */
    903     @Deprecated
    904     public static String getStorageState(File path) {
    905         return getExternalStorageState(path);
    906     }
    907 
    908     /**
    909      * Returns the current state of the shared/external storage media at the
    910      * given path.
    911      *
    912      * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
    913      *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
    914      *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
    915      *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
    916      *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
    917      */
    918     public static String getExternalStorageState(File path) {
    919         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
    920         if (volume != null) {
    921             return volume.getState();
    922         } else {
    923             return MEDIA_UNKNOWN;
    924         }
    925     }
    926 
    927     /**
    928      * Returns whether the primary shared/external storage media is physically
    929      * removable.
    930      *
    931      * @return true if the storage device can be removed (such as an SD card),
    932      *         or false if the storage device is built in and cannot be
    933      *         physically removed.
    934      */
    935     public static boolean isExternalStorageRemovable() {
    936         final File externalDir = sCurrentUser.getExternalDirs()[0];
    937         return isExternalStorageRemovable(externalDir);
    938     }
    939 
    940     /**
    941      * Returns whether the shared/external storage media at the given path is
    942      * physically removable.
    943      *
    944      * @return true if the storage device can be removed (such as an SD card),
    945      *         or false if the storage device is built in and cannot be
    946      *         physically removed.
    947      * @throws IllegalArgumentException if the path is not a valid storage
    948      *             device.
    949      */
    950     public static boolean isExternalStorageRemovable(File path) {
    951         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
    952         if (volume != null) {
    953             return volume.isRemovable();
    954         } else {
    955             throw new IllegalArgumentException("Failed to find storage device at " + path);
    956         }
    957     }
    958 
    959     /**
    960      * Returns whether the primary shared/external storage media is emulated.
    961      * <p>
    962      * The contents of emulated storage devices are backed by a private user
    963      * data partition, which means there is little benefit to apps storing data
    964      * here instead of the private directories returned by
    965      * {@link Context#getFilesDir()}, etc.
    966      * <p>
    967      * This returns true when emulated storage is backed by either internal
    968      * storage or an adopted storage device.
    969      *
    970      * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
    971      *      boolean)
    972      */
    973     public static boolean isExternalStorageEmulated() {
    974         final File externalDir = sCurrentUser.getExternalDirs()[0];
    975         return isExternalStorageEmulated(externalDir);
    976     }
    977 
    978     /**
    979      * Returns whether the shared/external storage media at the given path is
    980      * emulated.
    981      * <p>
    982      * The contents of emulated storage devices are backed by a private user
    983      * data partition, which means there is little benefit to apps storing data
    984      * here instead of the private directories returned by
    985      * {@link Context#getFilesDir()}, etc.
    986      * <p>
    987      * This returns true when emulated storage is backed by either internal
    988      * storage or an adopted storage device.
    989      *
    990      * @throws IllegalArgumentException if the path is not a valid storage
    991      *             device.
    992      */
    993     public static boolean isExternalStorageEmulated(File path) {
    994         final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
    995         if (volume != null) {
    996             return volume.isEmulated();
    997         } else {
    998             throw new IllegalArgumentException("Failed to find storage device at " + path);
    999         }
   1000     }
   1001 
   1002     static File getDirectory(String variableName, String defaultPath) {
   1003         String path = System.getenv(variableName);
   1004         return path == null ? new File(defaultPath) : new File(path);
   1005     }
   1006 
   1007     /** {@hide} */
   1008     public static void setUserRequired(boolean userRequired) {
   1009         sUserRequired = userRequired;
   1010     }
   1011 
   1012     private static void throwIfUserRequired() {
   1013         if (sUserRequired) {
   1014             Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
   1015                     new Throwable());
   1016         }
   1017     }
   1018 
   1019     /**
   1020      * Append path segments to each given base path, returning result.
   1021      *
   1022      * @hide
   1023      */
   1024     public static File[] buildPaths(File[] base, String... segments) {
   1025         File[] result = new File[base.length];
   1026         for (int i = 0; i < base.length; i++) {
   1027             result[i] = buildPath(base[i], segments);
   1028         }
   1029         return result;
   1030     }
   1031 
   1032     /**
   1033      * Append path segments to given base path, returning result.
   1034      *
   1035      * @hide
   1036      */
   1037     @TestApi
   1038     public static File buildPath(File base, String... segments) {
   1039         File cur = base;
   1040         for (String segment : segments) {
   1041             if (cur == null) {
   1042                 cur = new File(segment);
   1043             } else {
   1044                 cur = new File(cur, segment);
   1045             }
   1046         }
   1047         return cur;
   1048     }
   1049 
   1050 
   1051     /**
   1052      * If the given path exists on emulated external storage, return the
   1053      * translated backing path hosted on internal storage. This bypasses any
   1054      * emulation later, improving performance. This is <em>only</em> suitable
   1055      * for read-only access.
   1056      * <p>
   1057      * Returns original path if given path doesn't meet these criteria. Callers
   1058      * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
   1059      * permission.
   1060      *
   1061      * @hide
   1062      */
   1063     public static File maybeTranslateEmulatedPathToInternal(File path) {
   1064         return StorageManager.maybeTranslateEmulatedPathToInternal(path);
   1065     }
   1066 }
   1067