blob: 6667a41f49ca1e01e0f55f2e1289511c89fbf29e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
San Mehatb1043402010-02-05 08:26:50 -080019import android.os.storage.IMountService;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070020import android.os.storage.StorageManager;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070021import android.os.storage.StorageVolume;
Jeff Sharkeyb049e212012-09-07 23:16:01 -070022import android.text.TextUtils;
Kenny Rootb2278dc2011-01-18 13:03:28 -080023import android.util.Log;
San Mehat7fd0fee2009-12-17 07:12:23 -080024
Gilles Debunneee1d6302011-05-13 10:09:32 -070025import java.io.File;
26
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080027/**
28 * Provides access to environment variables.
29 */
30public class Environment {
Kenny Rootb2278dc2011-01-18 13:03:28 -080031 private static final String TAG = "Environment";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032
Jeff Sharkeyb049e212012-09-07 23:16:01 -070033 private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
34 private static final String ENV_EMULATED_STORAGE_TARGET = "EMULATED_STORAGE_TARGET";
35
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 private static final File ROOT_DIRECTORY
37 = getDirectory("ANDROID_ROOT", "/system");
38
Oscar Montemayora8529f62009-11-18 10:14:20 -080039 private static final String SYSTEM_PROPERTY_EFS_ENABLED = "persist.security.efs.enabled";
40
Jeff Sharkeyb049e212012-09-07 23:16:01 -070041 private static UserEnvironment sCurrentUser;
Kenny Roote1ff2142010-10-12 11:20:01 -070042
Jeff Sharkeyb049e212012-09-07 23:16:01 -070043 private static final Object sLock = new Object();
44
45 // @GuardedBy("sLock")
46 private static volatile StorageVolume sPrimaryVolume;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070047
48 private static StorageVolume getPrimaryVolume() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -070049 if (sPrimaryVolume == null) {
50 synchronized (sLock) {
51 if (sPrimaryVolume == null) {
Mike Lockwood2f6a3882011-05-09 19:08:06 -070052 try {
53 IMountService mountService = IMountService.Stub.asInterface(ServiceManager
54 .getService("mount"));
Jeff Sharkeyb049e212012-09-07 23:16:01 -070055 final StorageVolume[] volumes = mountService.getVolumeList();
56 sPrimaryVolume = StorageManager.getPrimaryVolume(volumes);
Mike Lockwood2f6a3882011-05-09 19:08:06 -070057 } catch (Exception e) {
58 Log.e(TAG, "couldn't talk to MountService", e);
59 }
60 }
61 }
62 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -070063 return sPrimaryVolume;
64 }
65
66 static {
67 initForCurrentUser();
68 }
69
70 /** {@hide} */
71 public static void initForCurrentUser() {
72 final int userId = UserHandle.myUserId();
73 sCurrentUser = new UserEnvironment(userId);
74
75 synchronized (sLock) {
76 sPrimaryVolume = null;
77 }
78 }
79
80 /** {@hide} */
81 public static class UserEnvironment {
82 // TODO: generalize further to create package-specific environment
83
84 private final File mExternalStorage;
85 private final File mExternalStorageAndroidData;
86 private final File mExternalStorageAndroidMedia;
87 private final File mExternalStorageAndroidObb;
88
89 public UserEnvironment(int userId) {
90 // See storage config details at http://source.android.com/tech/storage/
91 String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);
92 String rawEmulatedStorageTarget = System.getenv(ENV_EMULATED_STORAGE_TARGET);
93
94 if (!TextUtils.isEmpty(rawEmulatedStorageTarget)) {
95 // Device has emulated storage; external storage paths should have
96 // userId burned into them.
97 final File emulatedBase = new File(rawEmulatedStorageTarget);
98
99 // /storage/emulated/0
100 mExternalStorage = buildPath(emulatedBase, Integer.toString(userId));
101 // /storage/emulated/obb
102 mExternalStorageAndroidObb = buildPath(emulatedBase, "obb");
103
104 } else {
105 // Device has physical external storage; use plain paths.
106 if (TextUtils.isEmpty(rawExternalStorage)) {
107 Log.w(TAG, "EXTERNAL_STORAGE undefined; falling back to default");
108 rawExternalStorage = "/storage/sdcard0";
109 }
110
111 // /storage/sdcard0
112 mExternalStorage = new File(rawExternalStorage);
113 // /storage/sdcard0/Android/obb
114 mExternalStorageAndroidObb = buildPath(mExternalStorage, "Android", "obb");
115 }
116
117 mExternalStorageAndroidData = buildPath(mExternalStorage, "Android", "data");
118 mExternalStorageAndroidMedia = buildPath(mExternalStorage, "Android", "media");
119 }
120
121 public File getExternalStorageDirectory() {
122 return mExternalStorage;
123 }
124
125 public File getExternalStoragePublicDirectory(String type) {
126 return new File(mExternalStorage, type);
127 }
128
129 public File getExternalStorageAndroidDataDir() {
130 return mExternalStorageAndroidData;
131 }
132
133 public File getExternalStorageAppDataDirectory(String packageName) {
134 return new File(mExternalStorageAndroidData, packageName);
135 }
136
137 public File getExternalStorageAppMediaDirectory(String packageName) {
138 return new File(mExternalStorageAndroidMedia, packageName);
139 }
140
141 public File getExternalStorageAppObbDirectory(String packageName) {
142 return new File(mExternalStorageAndroidObb, packageName);
143 }
144
145 public File getExternalStorageAppFilesDirectory(String packageName) {
146 return new File(new File(mExternalStorageAndroidData, packageName), "files");
147 }
148
149 public File getExternalStorageAppCacheDirectory(String packageName) {
150 return new File(new File(mExternalStorageAndroidData, packageName), "cache");
151 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700152 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 /**
155 * Gets the Android root directory.
156 */
157 public static File getRootDirectory() {
158 return ROOT_DIRECTORY;
159 }
160
Jason parksa3cdaa52011-01-13 14:15:43 -0600161 /**
162 * Gets the system directory available for secure storage.
163 * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
164 * Otherwise, it returns the unencrypted /data/system directory.
165 * @return File object representing the secure storage system directory.
166 * @hide
167 */
168 public static File getSystemSecureDirectory() {
169 if (isEncryptedFilesystemEnabled()) {
170 return new File(SECURE_DATA_DIRECTORY, "system");
171 } else {
172 return new File(DATA_DIRECTORY, "system");
173 }
174 }
175
176 /**
177 * Gets the data directory for secure storage.
178 * If Encrypted File system is enabled, it returns an encrypted directory (/data/secure).
179 * Otherwise, it returns the unencrypted /data directory.
180 * @return File object representing the data directory for secure storage.
181 * @hide
182 */
183 public static File getSecureDataDirectory() {
184 if (isEncryptedFilesystemEnabled()) {
185 return SECURE_DATA_DIRECTORY;
186 } else {
187 return DATA_DIRECTORY;
188 }
189 }
190
191 /**
Jeff Sharkeyd525baa2012-05-22 18:25:32 -0700192 * Return directory used for internal media storage, which is protected by
193 * {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}.
194 *
195 * @hide
196 */
197 public static File getMediaStorageDirectory() {
198 return MEDIA_STORAGE_DIRECTORY;
199 }
200
201 /**
Amith Yamasani61f57372012-08-31 12:12:28 -0700202 * Return the system directory for a user. This is for use by system services to store
203 * files relating to the user. This directory will be automatically deleted when the user
204 * is removed.
205 *
206 * @hide
207 */
208 public static File getUserSystemDirectory(int userId) {
209 return new File(new File(getSystemSecureDirectory(), "users"), Integer.toString(userId));
210 }
211
212 /**
Jason parksa3cdaa52011-01-13 14:15:43 -0600213 * Returns whether the Encrypted File System feature is enabled on the device or not.
214 * @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code>
215 * if disabled.
216 * @hide
217 */
218 public static boolean isEncryptedFilesystemEnabled() {
219 return SystemProperties.getBoolean(SYSTEM_PROPERTY_EFS_ENABLED, false);
220 }
221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 private static final File DATA_DIRECTORY
223 = getDirectory("ANDROID_DATA", "/data");
224
Oscar Montemayora8529f62009-11-18 10:14:20 -0800225 /**
226 * @hide
227 */
228 private static final File SECURE_DATA_DIRECTORY
229 = getDirectory("ANDROID_SECURE_DATA", "/data/secure");
230
Jeff Sharkeyd525baa2012-05-22 18:25:32 -0700231 /** @hide */
232 private static final File MEDIA_STORAGE_DIRECTORY
233 = getDirectory("MEDIA_STORAGE", "/data/media");
234
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700235 private static final File DOWNLOAD_CACHE_DIRECTORY = getDirectory("DOWNLOAD_CACHE", "/cache");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
237 /**
238 * Gets the Android data directory.
239 */
240 public static File getDataDirectory() {
241 return DATA_DIRECTORY;
242 }
243
244 /**
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800245 * Gets the Android external storage directory. This directory may not
246 * currently be accessible if it has been mounted by the user on their
247 * computer, has been removed from the device, or some other problem has
248 * happened. You can determine its current state with
249 * {@link #getExternalStorageState()}.
250 *
Dianne Hackborn407f6252010-10-04 11:31:17 -0700251 * <p><em>Note: don't be confused by the word "external" here. This
252 * directory can better be thought as media/shared storage. It is a
253 * filesystem that can hold a relatively large amount of data and that
254 * is shared across all applications (does not enforce permissions).
255 * Traditionally this is an SD card, but it may also be implemented as
256 * built-in storage in a device that is distinct from the protected
257 * internal storage and can be mounted as a filesystem on a computer.</em></p>
258 *
259 * <p>In devices with multiple "external" storage directories (such as
260 * both secure app storage and mountable shared storage), this directory
261 * represents the "primary" external storage that the user will interact
262 * with.</p>
263 *
Dianne Hackbornacaf0282010-03-30 14:39:35 -0700264 * <p>Applications should not directly use this top-level directory, in
265 * order to avoid polluting the user's root namespace. Any files that are
266 * private to the application should be placed in a directory returned
267 * by {@link android.content.Context#getExternalFilesDir
268 * Context.getExternalFilesDir}, which the system will take care of deleting
269 * if the application is uninstalled. Other shared files should be placed
270 * in one of the directories returned by
271 * {@link #getExternalStoragePublicDirectory}.
272 *
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800273 * <p>Here is an example of typical code to monitor the state of
274 * external storage:</p>
275 *
276 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
277 * monitor_storage}
Dianne Hackborn407f6252010-10-04 11:31:17 -0700278 *
279 * @see #getExternalStorageState()
280 * @see #isExternalStorageRemovable()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 */
282 public static File getExternalStorageDirectory() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700283 throwIfSystem();
284 return sCurrentUser.getExternalStorageDirectory();
285 }
286
287 /** {@hide} */
288 public static File getLegacyExternalStorageDirectory() {
289 return new File(System.getenv(ENV_EXTERNAL_STORAGE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 }
291
292 /**
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800293 * Standard directory in which to place any audio files that should be
294 * in the regular list of music for the user.
295 * This may be combined with
296 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
297 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
298 * of directories to categories a particular audio file as more than one
299 * type.
300 */
301 public static String DIRECTORY_MUSIC = "Music";
302
303 /**
304 * Standard directory in which to place any audio files that should be
305 * in the list of podcasts that the user can select (not as regular
306 * music).
307 * This may be combined with {@link #DIRECTORY_MUSIC},
308 * {@link #DIRECTORY_NOTIFICATIONS},
309 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
310 * of directories to categories a particular audio file as more than one
311 * type.
312 */
313 public static String DIRECTORY_PODCASTS = "Podcasts";
314
315 /**
316 * Standard directory in which to place any audio files that should be
317 * in the list of ringtones that the user can select (not as regular
318 * music).
319 * This may be combined with {@link #DIRECTORY_MUSIC},
320 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
321 * {@link #DIRECTORY_ALARMS} as a series
322 * of directories to categories a particular audio file as more than one
323 * type.
324 */
325 public static String DIRECTORY_RINGTONES = "Ringtones";
326
327 /**
328 * Standard directory in which to place any audio files that should be
329 * in the list of alarms that the user can select (not as regular
330 * music).
331 * This may be combined with {@link #DIRECTORY_MUSIC},
332 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
333 * and {@link #DIRECTORY_RINGTONES} as a series
334 * of directories to categories a particular audio file as more than one
335 * type.
336 */
337 public static String DIRECTORY_ALARMS = "Alarms";
338
339 /**
340 * Standard directory in which to place any audio files that should be
341 * in the list of notifications that the user can select (not as regular
342 * music).
343 * This may be combined with {@link #DIRECTORY_MUSIC},
344 * {@link #DIRECTORY_PODCASTS},
345 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
346 * of directories to categories a particular audio file as more than one
347 * type.
348 */
349 public static String DIRECTORY_NOTIFICATIONS = "Notifications";
350
351 /**
352 * Standard directory in which to place pictures that are available to
353 * the user. Note that this is primarily a convention for the top-level
354 * public directory, as the media scanner will find and collect pictures
355 * in any directory.
356 */
357 public static String DIRECTORY_PICTURES = "Pictures";
358
359 /**
360 * Standard directory in which to place movies that are available to
361 * the user. Note that this is primarily a convention for the top-level
362 * public directory, as the media scanner will find and collect movies
363 * in any directory.
364 */
365 public static String DIRECTORY_MOVIES = "Movies";
366
367 /**
368 * Standard directory in which to place files that have been downloaded by
369 * the user. Note that this is primarily a convention for the top-level
370 * public directory, you are free to download files anywhere in your own
Dianne Hackbornce59fb82010-04-07 17:19:04 -0700371 * private directories. Also note that though the constant here is
372 * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
373 * backwards compatibility reasons.
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800374 */
Dianne Hackbornce59fb82010-04-07 17:19:04 -0700375 public static String DIRECTORY_DOWNLOADS = "Download";
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800376
377 /**
378 * The traditional location for pictures and videos when mounting the
379 * device as a camera. Note that this is primarily a convention for the
380 * top-level public directory, as this convention makes no sense elsewhere.
381 */
382 public static String DIRECTORY_DCIM = "DCIM";
383
384 /**
385 * Get a top-level public external storage directory for placing files of
386 * a particular type. This is where the user will typically place and
387 * manage their own files, so you should be careful about what you put here
388 * to ensure you don't erase their files or get in the way of their own
389 * organization.
390 *
391 * <p>Here is an example of typical code to manipulate a picture on
392 * the public external storage:</p>
393 *
394 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
395 * public_picture}
396 *
397 * @param type The type of storage directory to return. Should be one of
398 * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
399 * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
400 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
401 * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
402 * {@link #DIRECTORY_DCIM}. May not be null.
403 *
404 * @return Returns the File path for the directory. Note that this
405 * directory may not yet exist, so you must make sure it exists before
406 * using it such as with {@link File#mkdirs File.mkdirs()}.
407 */
408 public static File getExternalStoragePublicDirectory(String type) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700409 throwIfSystem();
410 return sCurrentUser.getExternalStoragePublicDirectory(type);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800411 }
412
413 /**
414 * Returns the path for android-specific data on the SD card.
415 * @hide
416 */
417 public static File getExternalStorageAndroidDataDir() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700418 throwIfSystem();
419 return sCurrentUser.getExternalStorageAndroidDataDir();
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800420 }
421
422 /**
423 * Generates the raw path to an application's data
424 * @hide
425 */
426 public static File getExternalStorageAppDataDirectory(String packageName) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700427 throwIfSystem();
428 return sCurrentUser.getExternalStorageAppDataDirectory(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800429 }
430
431 /**
432 * Generates the raw path to an application's media
433 * @hide
434 */
435 public static File getExternalStorageAppMediaDirectory(String packageName) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700436 throwIfSystem();
437 return sCurrentUser.getExternalStorageAppMediaDirectory(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800438 }
439
440 /**
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800441 * Generates the raw path to an application's OBB files
442 * @hide
443 */
444 public static File getExternalStorageAppObbDirectory(String packageName) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700445 throwIfSystem();
446 return sCurrentUser.getExternalStorageAppObbDirectory(packageName);
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800447 }
448
449 /**
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800450 * Generates the path to an application's files.
451 * @hide
452 */
453 public static File getExternalStorageAppFilesDirectory(String packageName) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700454 throwIfSystem();
455 return sCurrentUser.getExternalStorageAppFilesDirectory(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800456 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700457
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800458 /**
459 * Generates the path to an application's cache.
460 * @hide
461 */
462 public static File getExternalStorageAppCacheDirectory(String packageName) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700463 throwIfSystem();
464 return sCurrentUser.getExternalStorageAppCacheDirectory(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800465 }
466
467 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 * Gets the Android Download/Cache content directory.
469 */
470 public static File getDownloadCacheDirectory() {
471 return DOWNLOAD_CACHE_DIRECTORY;
472 }
473
474 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700475 * {@link #getExternalStorageState()} returns MEDIA_REMOVED if the media is not present.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 */
477 public static final String MEDIA_REMOVED = "removed";
478
479 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700480 * {@link #getExternalStorageState()} returns MEDIA_UNMOUNTED if the media is present
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 * but not mounted.
482 */
483 public static final String MEDIA_UNMOUNTED = "unmounted";
484
485 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700486 * {@link #getExternalStorageState()} returns MEDIA_CHECKING if the media is present
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 * and being disk-checked
488 */
489 public static final String MEDIA_CHECKING = "checking";
490
491 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700492 * {@link #getExternalStorageState()} returns MEDIA_NOFS if the media is present
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 * but is blank or is using an unsupported filesystem
494 */
495 public static final String MEDIA_NOFS = "nofs";
496
497 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700498 * {@link #getExternalStorageState()} returns MEDIA_MOUNTED if the media is present
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 * and mounted at its mount point with read/write access.
500 */
501 public static final String MEDIA_MOUNTED = "mounted";
502
503 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700504 * {@link #getExternalStorageState()} returns MEDIA_MOUNTED_READ_ONLY if the media is present
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 * and mounted at its mount point with read only access.
506 */
507 public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
508
509 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700510 * {@link #getExternalStorageState()} returns MEDIA_SHARED if the media is present
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 * not mounted, and shared via USB mass storage.
512 */
513 public static final String MEDIA_SHARED = "shared";
514
515 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700516 * {@link #getExternalStorageState()} returns MEDIA_BAD_REMOVAL if the media was
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 * removed before it was unmounted.
518 */
519 public static final String MEDIA_BAD_REMOVAL = "bad_removal";
520
521 /**
Gilles Debunneee1d6302011-05-13 10:09:32 -0700522 * {@link #getExternalStorageState()} returns MEDIA_UNMOUNTABLE if the media is present
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 * but cannot be mounted. Typically this happens if the file system on the
524 * media is corrupted.
525 */
526 public static final String MEDIA_UNMOUNTABLE = "unmountable";
527
528 /**
Dianne Hackborn407f6252010-10-04 11:31:17 -0700529 * Gets the current state of the primary "external" storage device.
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800530 *
Dianne Hackborn407f6252010-10-04 11:31:17 -0700531 * <p>See {@link #getExternalStorageDirectory()} for more information.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800532 */
533 public static String getExternalStorageState() {
San Mehat7fd0fee2009-12-17 07:12:23 -0800534 try {
Kenny Rootb2278dc2011-01-18 13:03:28 -0800535 IMountService mountService = IMountService.Stub.asInterface(ServiceManager
536 .getService("mount"));
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700537 final StorageVolume primary = getPrimaryVolume();
538 return mountService.getVolumeState(primary.getPath());
539 } catch (RemoteException rex) {
540 Log.w(TAG, "Failed to read external storage state; assuming REMOVED: " + rex);
San Mehat7fd0fee2009-12-17 07:12:23 -0800541 return Environment.MEDIA_REMOVED;
542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 }
544
Dianne Hackborn407f6252010-10-04 11:31:17 -0700545 /**
546 * Returns whether the primary "external" storage device is removable.
547 * If true is returned, this device is for example an SD card that the
548 * user can remove. If false is returned, the storage is built into
549 * the device and can not be physically removed.
550 *
551 * <p>See {@link #getExternalStorageDirectory()} for more information.
552 */
553 public static boolean isExternalStorageRemovable() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700554 final StorageVolume primary = getPrimaryVolume();
555 return (primary != null && primary.isRemovable());
Dianne Hackborn407f6252010-10-04 11:31:17 -0700556 }
557
Kenny Roote1ff2142010-10-12 11:20:01 -0700558 /**
559 * Returns whether the device has an external storage device which is
Andy Stadler50c294f2011-03-07 19:13:42 -0800560 * emulated. If true, the device does not have real external storage, and the directory
561 * returned by {@link #getExternalStorageDirectory()} will be allocated using a portion of
562 * the internal storage system.
563 *
564 * <p>Certain system services, such as the package manager, use this
Kenny Roote1ff2142010-10-12 11:20:01 -0700565 * to determine where to install an application.
Andy Stadler50c294f2011-03-07 19:13:42 -0800566 *
567 * <p>Emulated external storage may also be encrypted - see
568 * {@link android.app.admin.DevicePolicyManager#setStorageEncryption(
569 * android.content.ComponentName, boolean)} for additional details.
Kenny Roote1ff2142010-10-12 11:20:01 -0700570 */
571 public static boolean isExternalStorageEmulated() {
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700572 final StorageVolume primary = getPrimaryVolume();
573 return (primary != null && primary.isEmulated());
Kenny Roote1ff2142010-10-12 11:20:01 -0700574 }
575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 static File getDirectory(String variableName, String defaultPath) {
577 String path = System.getenv(variableName);
578 return path == null ? new File(defaultPath) : new File(path);
579 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700580
581 private static void throwIfSystem() {
582 if (Process.myUid() == Process.SYSTEM_UID) {
583 Log.wtf(TAG, "Static storage paths aren't available from AID_SYSTEM", new Throwable());
584 }
585 }
586
587 private static File buildPath(File base, String... segments) {
588 File cur = base;
589 for (String segment : segments) {
590 if (cur == null) {
591 cur = new File(segment);
592 } else {
593 cur = new File(cur, segment);
594 }
595 }
596 return cur;
597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598}