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