Environment.java revision 4887789e44cdb16b042a35e8ec03983213e88ac6
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
17package android.os;
18
19import android.app.admin.DevicePolicyManager;
20import android.content.Context;
21import android.os.storage.StorageManager;
22import android.os.storage.StorageVolume;
23import android.util.Log;
24
25import java.io.File;
26
27/**
28 * Provides access to environment variables.
29 */
30public class Environment {
31    private static final String TAG = "Environment";
32
33    private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
34    private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
35    private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
36    private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
37    private static final String ENV_OEM_ROOT = "OEM_ROOT";
38    private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
39
40    /** {@hide} */
41    public static final String DIR_ANDROID = "Android";
42    private static final String DIR_DATA = "data";
43    private static final String DIR_MEDIA = "media";
44    private static final String DIR_OBB = "obb";
45    private static final String DIR_FILES = "files";
46    private static final String DIR_CACHE = "cache";
47
48    /** {@hide} */
49    @Deprecated
50    public static final String DIRECTORY_ANDROID = DIR_ANDROID;
51
52    private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
53    private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
54    private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
55    private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
56    private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
57
58    private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
59
60    private static UserEnvironment sCurrentUser;
61    private static boolean sUserRequired;
62
63    static {
64        initForCurrentUser();
65    }
66
67    /** {@hide} */
68    public static void initForCurrentUser() {
69        final int userId = UserHandle.myUserId();
70        sCurrentUser = new UserEnvironment(userId);
71    }
72
73    /** {@hide} */
74    public static class UserEnvironment {
75        private final int mUserId;
76
77        public UserEnvironment(int userId) {
78            mUserId = userId;
79        }
80
81        public File[] getExternalDirs() {
82            final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId);
83            final File[] dirs = new File[volumes.length];
84            for (int i = 0; i < volumes.length; i++) {
85                dirs[i] = volumes[i].getPathFile();
86            }
87            return dirs;
88        }
89
90        @Deprecated
91        public File getExternalStorageDirectory() {
92            return getExternalDirs()[0];
93        }
94
95        @Deprecated
96        public File getExternalStoragePublicDirectory(String type) {
97            return buildExternalStoragePublicDirs(type)[0];
98        }
99
100        public File[] buildExternalStoragePublicDirs(String type) {
101            return buildPaths(getExternalDirs(), type);
102        }
103
104        public File[] buildExternalStorageAndroidDataDirs() {
105            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA);
106        }
107
108        public File[] buildExternalStorageAndroidObbDirs() {
109            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB);
110        }
111
112        public File[] buildExternalStorageAppDataDirs(String packageName) {
113            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName);
114        }
115
116        public File[] buildExternalStorageAppMediaDirs(String packageName) {
117            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName);
118        }
119
120        public File[] buildExternalStorageAppObbDirs(String packageName) {
121            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName);
122        }
123
124        public File[] buildExternalStorageAppFilesDirs(String packageName) {
125            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
126        }
127
128        public File[] buildExternalStorageAppCacheDirs(String packageName) {
129            return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
130        }
131    }
132
133    /**
134     * Return root of the "system" partition holding the core Android OS.
135     * Always present and mounted read-only.
136     */
137    public static File getRootDirectory() {
138        return DIR_ANDROID_ROOT;
139    }
140
141    /** {@hide} */
142    public static File getStorageDirectory() {
143        return DIR_ANDROID_STORAGE;
144    }
145
146    /**
147     * Return root directory of the "oem" partition holding OEM customizations,
148     * if any. If present, the partition is mounted read-only.
149     *
150     * @hide
151     */
152    public static File getOemDirectory() {
153        return DIR_OEM_ROOT;
154    }
155
156    /**
157     * Return root directory of the "vendor" partition that holds vendor-provided
158     * software that should persist across simple reflashing of the "system" partition.
159     * @hide
160     */
161    public static File getVendorDirectory() {
162        return DIR_VENDOR_ROOT;
163    }
164
165    /**
166     * Gets the system directory available for secure storage.
167     * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
168     * Otherwise, it returns the unencrypted /data/system directory.
169     * @return File object representing the secure storage system directory.
170     * @hide
171     */
172    public static File getSystemSecureDirectory() {
173        if (isEncryptedFilesystemEnabled()) {
174            return new File(SECURE_DATA_DIRECTORY, "system");
175        } else {
176            return new File(DATA_DIRECTORY, "system");
177        }
178    }
179
180    /**
181     * Gets the data directory for secure storage.
182     * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure).
183     * Otherwise, it returns the unencrypted /data directory.
184     * @return File object representing the data directory for secure storage.
185     * @hide
186     */
187    public static File getSecureDataDirectory() {
188        if (isEncryptedFilesystemEnabled()) {
189            return SECURE_DATA_DIRECTORY;
190        } else {
191            return DATA_DIRECTORY;
192        }
193    }
194
195    /**
196     * Return the system directory for a user. This is for use by system services to store
197     * files relating to the user. This directory will be automatically deleted when the user
198     * is removed.
199     *
200     * @hide
201     */
202    public static File getUserSystemDirectory(int userId) {
203        return new File(new File(getSystemSecureDirectory(), "users"), Integer.toString(userId));
204    }
205
206    /**
207     * Returns the config directory for a user. This is for use by system services to store files
208     * relating to the user which should be readable by any app running as that user.
209     *
210     * @hide
211     */
212    public static File getUserConfigDirectory(int userId) {
213        return new File(new File(new File(
214                getDataDirectory(), "misc"), "user"), Integer.toString(userId));
215    }
216
217    /**
218     * Returns whether the Encrypted File System feature is enabled on the device or not.
219     * @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code>
220     * if disabled.
221     * @hide
222     */
223    public static boolean isEncryptedFilesystemEnabled() {
224        return SystemProperties.getBoolean(SYSTEM_PROPERTY_EFS_ENABLED, false);
225    }
226
227    private static final File DATA_DIRECTORY
228            = getDirectory("ANDROID_DATA", "/data");
229
230    /**
231     * @hide
232     */
233    private static final File SECURE_DATA_DIRECTORY
234            = getDirectory("ANDROID_SECURE_DATA", "/data/secure");
235
236    private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
237
238    /**
239     * Return the user data directory.
240     */
241    public static File getDataDirectory() {
242        return DATA_DIRECTORY;
243    }
244
245    /**
246     * Return the primary external storage directory. This directory may not
247     * currently be accessible if it has been mounted by the user on their
248     * computer, has been removed from the device, or some other problem has
249     * happened. You can determine its current state with
250     * {@link #getExternalStorageState()}.
251     * <p>
252     * <em>Note: don't be confused by the word "external" here. This directory
253     * can better be thought as media/shared storage. It is a filesystem that
254     * can hold a relatively large amount of data and that is shared across all
255     * applications (does not enforce permissions). Traditionally this is an SD
256     * card, but it may also be implemented as built-in storage in a device that
257     * is distinct from the protected internal storage and can be mounted as a
258     * filesystem on a computer.</em>
259     * <p>
260     * On devices with multiple users (as described by {@link UserManager}),
261     * each user has their own isolated external storage. Applications only have
262     * access to the external storage for the user they're running as.
263     * <p>
264     * In devices with multiple "external" storage directories, this directory
265     * represents the "primary" external storage that the user will interact
266     * with. Access to secondary storage is available through
267     * <p>
268     * Applications should not directly use this top-level directory, in order
269     * to avoid polluting the user's root namespace. Any files that are private
270     * to the application should be placed in a directory returned by
271     * {@link android.content.Context#getExternalFilesDir
272     * Context.getExternalFilesDir}, which the system will take care of deleting
273     * if the application is uninstalled. Other shared files should be placed in
274     * one of the directories returned by
275     * {@link #getExternalStoragePublicDirectory}.
276     * <p>
277     * Writing to this path requires the
278     * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
279     * and starting in read access requires the
280     * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
281     * which is automatically granted if you hold the write permission.
282     * <p>
283     * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
284     * application only needs to store internal data, consider using
285     * {@link Context#getExternalFilesDir(String)} or
286     * {@link Context#getExternalCacheDir()}, which require no permissions to
287     * read or write.
288     * <p>
289     * This path may change between platform versions, so applications should
290     * only persist relative paths.
291     * <p>
292     * Here is an example of typical code to monitor the state of external
293     * storage:
294     * <p>
295     * {@sample
296     * development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
297     * monitor_storage}
298     *
299     * @see #getExternalStorageState()
300     * @see #isExternalStorageRemovable()
301     */
302    public static File getExternalStorageDirectory() {
303        throwIfUserRequired();
304        return sCurrentUser.getExternalDirs()[0];
305    }
306
307    /** {@hide} */
308    public static File getLegacyExternalStorageDirectory() {
309        return new File(System.getenv(ENV_EXTERNAL_STORAGE));
310    }
311
312    /** {@hide} */
313    public static File getLegacyExternalStorageObbDirectory() {
314        return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
315    }
316
317    /**
318     * Standard directory in which to place any audio files that should be
319     * in the regular list of music for the user.
320     * This may be combined with
321     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
322     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
323     * of directories to categories a particular audio file as more than one
324     * type.
325     */
326    public static String DIRECTORY_MUSIC = "Music";
327
328    /**
329     * Standard directory in which to place any audio files that should be
330     * in the list of podcasts that the user can select (not as regular
331     * music).
332     * This may be combined with {@link #DIRECTORY_MUSIC},
333     * {@link #DIRECTORY_NOTIFICATIONS},
334     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
335     * of directories to categories a particular audio file as more than one
336     * type.
337     */
338    public static String DIRECTORY_PODCASTS = "Podcasts";
339
340    /**
341     * Standard directory in which to place any audio files that should be
342     * in the list of ringtones that the user can select (not as regular
343     * music).
344     * This may be combined with {@link #DIRECTORY_MUSIC},
345     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
346     * {@link #DIRECTORY_ALARMS} as a series
347     * of directories to categories a particular audio file as more than one
348     * type.
349     */
350    public static String DIRECTORY_RINGTONES = "Ringtones";
351
352    /**
353     * Standard directory in which to place any audio files that should be
354     * in the list of alarms that the user can select (not as regular
355     * music).
356     * This may be combined with {@link #DIRECTORY_MUSIC},
357     * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
358     * and {@link #DIRECTORY_RINGTONES} as a series
359     * of directories to categories a particular audio file as more than one
360     * type.
361     */
362    public static String DIRECTORY_ALARMS = "Alarms";
363
364    /**
365     * Standard directory in which to place any audio files that should be
366     * in the list of notifications that the user can select (not as regular
367     * music).
368     * This may be combined with {@link #DIRECTORY_MUSIC},
369     * {@link #DIRECTORY_PODCASTS},
370     * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
371     * of directories to categories a particular audio file as more than one
372     * type.
373     */
374    public static String DIRECTORY_NOTIFICATIONS = "Notifications";
375
376    /**
377     * Standard directory in which to place pictures that are available to
378     * the user.  Note that this is primarily a convention for the top-level
379     * public directory, as the media scanner will find and collect pictures
380     * in any directory.
381     */
382    public static String DIRECTORY_PICTURES = "Pictures";
383
384    /**
385     * Standard directory in which to place movies that are available to
386     * the user.  Note that this is primarily a convention for the top-level
387     * public directory, as the media scanner will find and collect movies
388     * in any directory.
389     */
390    public static String DIRECTORY_MOVIES = "Movies";
391
392    /**
393     * Standard directory in which to place files that have been downloaded by
394     * the user.  Note that this is primarily a convention for the top-level
395     * public directory, you are free to download files anywhere in your own
396     * private directories.  Also note that though the constant here is
397     * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
398     * backwards compatibility reasons.
399     */
400    public static String DIRECTORY_DOWNLOADS = "Download";
401
402    /**
403     * The traditional location for pictures and videos when mounting the
404     * device as a camera.  Note that this is primarily a convention for the
405     * top-level public directory, as this convention makes no sense elsewhere.
406     */
407    public static String DIRECTORY_DCIM = "DCIM";
408
409    /**
410     * Standard directory in which to place documents that have been created by
411     * the user.
412     */
413    public static String DIRECTORY_DOCUMENTS = "Documents";
414
415    /**
416     * Get a top-level public external storage directory for placing files of
417     * a particular type.  This is where the user will typically place and
418     * manage their own files, so you should be careful about what you put here
419     * to ensure you don't erase their files or get in the way of their own
420     * organization.
421     *
422     * <p>On devices with multiple users (as described by {@link UserManager}),
423     * each user has their own isolated external storage. Applications only
424     * have access to the external storage for the user they're running as.</p>
425     *
426     * <p>Here is an example of typical code to manipulate a picture on
427     * the public external storage:</p>
428     *
429     * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
430     * public_picture}
431     *
432     * @param type The type of storage directory to return.  Should be one of
433     * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
434     * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
435     * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
436     * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
437     * {@link #DIRECTORY_DCIM}.  May not be null.
438     *
439     * @return Returns the File path for the directory.  Note that this
440     * directory may not yet exist, so you must make sure it exists before
441     * using it such as with {@link File#mkdirs File.mkdirs()}.
442     */
443    public static File getExternalStoragePublicDirectory(String type) {
444        throwIfUserRequired();
445        return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
446    }
447
448    /**
449     * Returns the path for android-specific data on the SD card.
450     * @hide
451     */
452    public static File[] buildExternalStorageAndroidDataDirs() {
453        throwIfUserRequired();
454        return sCurrentUser.buildExternalStorageAndroidDataDirs();
455    }
456
457    /**
458     * Generates the raw path to an application's data
459     * @hide
460     */
461    public static File[] buildExternalStorageAppDataDirs(String packageName) {
462        throwIfUserRequired();
463        return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
464    }
465
466    /**
467     * Generates the raw path to an application's media
468     * @hide
469     */
470    public static File[] buildExternalStorageAppMediaDirs(String packageName) {
471        throwIfUserRequired();
472        return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
473    }
474
475    /**
476     * Generates the raw path to an application's OBB files
477     * @hide
478     */
479    public static File[] buildExternalStorageAppObbDirs(String packageName) {
480        throwIfUserRequired();
481        return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
482    }
483
484    /**
485     * Generates the path to an application's files.
486     * @hide
487     */
488    public static File[] buildExternalStorageAppFilesDirs(String packageName) {
489        throwIfUserRequired();
490        return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
491    }
492
493    /**
494     * Generates the path to an application's cache.
495     * @hide
496     */
497    public static File[] buildExternalStorageAppCacheDirs(String packageName) {
498        throwIfUserRequired();
499        return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
500    }
501
502    /**
503     * Return the download/cache content directory.
504     */
505    public static File getDownloadCacheDirectory() {
506        return DOWNLOAD_CACHE_DIRECTORY;
507    }
508
509    /**
510     * Unknown storage state, such as when a path isn't backed by known storage
511     * media.
512     *
513     * @see #getExternalStorageState(File)
514     */
515    public static final String MEDIA_UNKNOWN = "unknown";
516
517    /**
518     * Storage state if the media is not present.
519     *
520     * @see #getExternalStorageState(File)
521     */
522    public static final String MEDIA_REMOVED = "removed";
523
524    /**
525     * Storage state if the media is present but not mounted.
526     *
527     * @see #getExternalStorageState(File)
528     */
529    public static final String MEDIA_UNMOUNTED = "unmounted";
530
531    /**
532     * Storage state if the media is present and being disk-checked.
533     *
534     * @see #getExternalStorageState(File)
535     */
536    public static final String MEDIA_CHECKING = "checking";
537
538    /**
539     * Storage state if the media is present but is blank or is using an
540     * unsupported filesystem.
541     *
542     * @see #getExternalStorageState(File)
543     */
544    public static final String MEDIA_NOFS = "nofs";
545
546    /**
547     * Storage state if the media is present and mounted at its mount point with
548     * read/write access.
549     *
550     * @see #getExternalStorageState(File)
551     */
552    public static final String MEDIA_MOUNTED = "mounted";
553
554    /**
555     * Storage state if the media is present and mounted at its mount point with
556     * read-only access.
557     *
558     * @see #getExternalStorageState(File)
559     */
560    public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
561
562    /**
563     * Storage state if the media is present not mounted, and shared via USB
564     * mass storage.
565     *
566     * @see #getExternalStorageState(File)
567     */
568    public static final String MEDIA_SHARED = "shared";
569
570    /**
571     * Storage state if the media was removed before it was unmounted.
572     *
573     * @see #getExternalStorageState(File)
574     */
575    public static final String MEDIA_BAD_REMOVAL = "bad_removal";
576
577    /**
578     * Storage state if the media is present but cannot be mounted. Typically
579     * this happens if the file system on the media is corrupted.
580     *
581     * @see #getExternalStorageState(File)
582     */
583    public static final String MEDIA_UNMOUNTABLE = "unmountable";
584
585    /**
586     * Storage state if the media is in the process of being ejected.
587     *
588     * @see #getExternalStorageState(File)
589     */
590    public static final String MEDIA_EJECTING = "ejecting";
591
592    /**
593     * Returns the current state of the primary "external" storage device.
594     *
595     * @see #getExternalStorageDirectory()
596     * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
597     *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
598     *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
599     *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
600     *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
601     */
602    public static String getExternalStorageState() {
603        final File externalDir = sCurrentUser.getExternalDirs()[0];
604        return getExternalStorageState(externalDir);
605    }
606
607    /**
608     * @deprecated use {@link #getExternalStorageState(File)}
609     */
610    @Deprecated
611    public static String getStorageState(File path) {
612        return getExternalStorageState(path);
613    }
614
615    /**
616     * Returns the current state of the storage device that provides the given
617     * path.
618     *
619     * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
620     *         {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
621     *         {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
622     *         {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
623     *         {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
624     */
625    public static String getExternalStorageState(File path) {
626        final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
627        if (volume != null) {
628            return volume.getState();
629        } else {
630            return MEDIA_UNKNOWN;
631        }
632    }
633
634    /**
635     * Returns whether the primary "external" storage device is removable.
636     *
637     * @return true if the storage device can be removed (such as an SD card),
638     *         or false if the storage device is built in and cannot be
639     *         physically removed.
640     */
641    public static boolean isExternalStorageRemovable() {
642        if (isStorageDisabled()) return false;
643        final File externalDir = sCurrentUser.getExternalDirs()[0];
644        return isExternalStorageRemovable(externalDir);
645    }
646
647    /**
648     * Returns whether the storage device that provides the given path is
649     * removable.
650     *
651     * @return true if the storage device can be removed (such as an SD card),
652     *         or false if the storage device is built in and cannot be
653     *         physically removed.
654     * @throws IllegalArgumentException if the path is not a valid storage
655     *             device.
656     */
657    public static boolean isExternalStorageRemovable(File path) {
658        final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
659        if (volume != null) {
660            return volume.isRemovable();
661        } else {
662            throw new IllegalArgumentException("Failed to find storage device at " + path);
663        }
664    }
665
666    /**
667     * Returns whether the primary "external" storage device is emulated. If
668     * true, data stored on this device will be stored on a portion of the
669     * internal storage system.
670     *
671     * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
672     *      boolean)
673     */
674    public static boolean isExternalStorageEmulated() {
675        if (isStorageDisabled()) return false;
676        final File externalDir = sCurrentUser.getExternalDirs()[0];
677        return isExternalStorageEmulated(externalDir);
678    }
679
680    /**
681     * Returns whether the storage device that provides the given path is
682     * emulated. If true, data stored on this device will be stored on a portion
683     * of the internal storage system.
684     *
685     * @throws IllegalArgumentException if the path is not a valid storage
686     *             device.
687     */
688    public static boolean isExternalStorageEmulated(File path) {
689        final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
690        if (volume != null) {
691            return volume.isEmulated();
692        } else {
693            throw new IllegalArgumentException("Failed to find storage device at " + path);
694        }
695    }
696
697    static File getDirectory(String variableName, String defaultPath) {
698        String path = System.getenv(variableName);
699        return path == null ? new File(defaultPath) : new File(path);
700    }
701
702    /** {@hide} */
703    public static void setUserRequired(boolean userRequired) {
704        sUserRequired = userRequired;
705    }
706
707    private static void throwIfUserRequired() {
708        if (sUserRequired) {
709            Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
710                    new Throwable());
711        }
712    }
713
714    /**
715     * Append path segments to each given base path, returning result.
716     *
717     * @hide
718     */
719    public static File[] buildPaths(File[] base, String... segments) {
720        File[] result = new File[base.length];
721        for (int i = 0; i < base.length; i++) {
722            result[i] = buildPath(base[i], segments);
723        }
724        return result;
725    }
726
727    /**
728     * Append path segments to given base path, returning result.
729     *
730     * @hide
731     */
732    public static File buildPath(File base, String... segments) {
733        File cur = base;
734        for (String segment : segments) {
735            if (cur == null) {
736                cur = new File(segment);
737            } else {
738                cur = new File(cur, segment);
739            }
740        }
741        return cur;
742    }
743
744    private static boolean isStorageDisabled() {
745        return SystemProperties.getBoolean("config.disable_storage", false);
746    }
747
748    /**
749     * If the given path exists on emulated external storage, return the
750     * translated backing path hosted on internal storage. This bypasses any
751     * emulation later, improving performance. This is <em>only</em> suitable
752     * for read-only access.
753     * <p>
754     * Returns original path if given path doesn't meet these criteria. Callers
755     * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
756     * permission.
757     *
758     * @hide
759     */
760    public static File maybeTranslateEmulatedPathToInternal(File path) {
761        // TODO: bring back this optimization
762        return path;
763    }
764}
765