blob: ae65f1d0bd0558843af49fc38ced1cac9782186f [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
Sudheer Shanka572fdfd2019-06-04 16:46:57 -070019import android.Manifest;
Jeff Sharkeya30e5c32019-02-28 12:02:10 -070020import android.annotation.NonNull;
Jeff Sharkey70eb34a2018-09-13 11:57:03 -060021import android.annotation.SystemApi;
Philip P. Moltmannf80809f2018-04-04 11:20:44 -070022import android.annotation.TestApi;
Jeff Sharkeybcff13c2019-03-28 14:29:35 -060023import android.app.AppGlobals;
24import android.app.AppOpsManager;
Jeff Sharkey4ca728c2014-01-10 16:27:19 -080025import android.app.admin.DevicePolicyManager;
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +000026import android.compat.Compatibility;
Abhijeet Kaur14c5d832020-03-04 17:34:10 +000027import android.compat.annotation.ChangeId;
28import android.compat.annotation.Disabled;
Artur Satayevafdb23a2019-12-10 17:47:53 +000029import android.compat.annotation.UnsupportedAppUsage;
Jeff Sharkey1abdb712013-08-11 16:28:14 -070030import android.content.Context;
Jeff Sharkey488162b2019-04-27 17:03:54 -060031import android.content.Intent;
Sudheer Shanka572fdfd2019-06-04 16:46:57 -070032import android.content.pm.PackageManager;
Jeff Sharkey48877892015-03-18 11:27:19 -070033import android.os.storage.StorageManager;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070034import android.os.storage.StorageVolume;
Jeff Sharkey488162b2019-04-27 17:03:54 -060035import android.provider.MediaStore;
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -070036import android.text.TextUtils;
Kenny Rootb2278dc2011-01-18 13:03:28 -080037import android.util.Log;
San Mehat7fd0fee2009-12-17 07:12:23 -080038
Gilles Debunneee1d6302011-05-13 10:09:32 -070039import java.io.File;
Hung-ying Tyan774d89e2020-02-05 16:55:01 +080040import java.io.IOException;
Jeff Sharkey04b4ba12019-12-15 22:42:42 -070041import java.util.ArrayList;
42import java.util.Collection;
Jeff Sharkey20356142017-12-06 15:22:05 -070043import java.util.LinkedList;
Hung-ying Tyan774d89e2020-02-05 16:55:01 +080044import java.util.List;
shafik81870652020-03-05 12:59:15 +000045import java.util.Objects;
Gilles Debunneee1d6302011-05-13 10:09:32 -070046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047/**
48 * Provides access to environment variables.
49 */
50public class Environment {
Kenny Rootb2278dc2011-01-18 13:03:28 -080051 private static final String TAG = "Environment";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
Jeff Sharkeydd02e332018-06-27 14:41:57 -060053 // NOTE: keep credential-protected paths in sync with StrictMode.java
54
Jeff Sharkeyb049e212012-09-07 23:16:01 -070055 private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
Jeff Sharkey63d0a062013-03-01 16:12:55 -080056 private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
Jeff Sharkey48877892015-03-18 11:27:19 -070057 private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -060058 private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND";
Jeff Sharkey48877892015-03-18 11:27:19 -070059 private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
Jeff Sharkey15447792015-11-05 16:18:51 -080060 private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
Jeff Sharkey1be762c2014-03-06 09:56:23 -080061 private static final String ENV_OEM_ROOT = "OEM_ROOT";
Hung-ying Tyanbdc9d582015-11-20 11:53:39 +080062 private static final String ENV_ODM_ROOT = "ODM_ROOT";
Christopher Tate740888f2014-04-18 12:24:57 -070063 private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
Jaekyun Seok1713d9e2018-01-12 21:47:26 +090064 private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
Jeongik Cha9ec059a2019-07-04 21:12:06 +090065 private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT";
Dario Frenic3e1bb722019-10-09 15:43:38 +010066 private static final String ENV_APEX_ROOT = "APEX_ROOT";
Jeff Sharkeyb049e212012-09-07 23:16:01 -070067
Jeff Sharkeydfa45302012-09-12 16:25:22 -070068 /** {@hide} */
Jeff Sharkey1abdb712013-08-11 16:28:14 -070069 public static final String DIR_ANDROID = "Android";
70 private static final String DIR_DATA = "data";
71 private static final String DIR_MEDIA = "media";
72 private static final String DIR_OBB = "obb";
73 private static final String DIR_FILES = "files";
74 private static final String DIR_CACHE = "cache";
75
76 /** {@hide} */
77 @Deprecated
78 public static final String DIRECTORY_ANDROID = DIR_ANDROID;
Jeff Sharkeydfa45302012-09-12 16:25:22 -070079
Jeff Sharkey63d0a062013-03-01 16:12:55 -080080 private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
Jeff Sharkey48877892015-03-18 11:27:19 -070081 private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -060082 private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand");
Jeff Sharkey48877892015-03-18 11:27:19 -070083 private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
Jeff Sharkey15447792015-11-05 16:18:51 -080084 private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
Jeff Sharkey1be762c2014-03-06 09:56:23 -080085 private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
Hung-ying Tyanbdc9d582015-11-20 11:53:39 +080086 private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
Christopher Tate740888f2014-04-18 12:24:57 -070087 private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
Jaekyun Seok1713d9e2018-01-12 21:47:26 +090088 private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
Jeongik Cha9ec059a2019-07-04 21:12:06 +090089 private static final File DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT,
Dario Frenic3e1bb722019-10-09 15:43:38 +010090 "/system_ext");
91 private static final File DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT,
92 "/apex");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +000094 /**
Abhijeet Kaur14c5d832020-03-04 17:34:10 +000095 * Scoped Storage is on by default. However, it is not strictly enforced and there are multiple
96 * ways to opt out of scoped storage:
97 * <ul>
98 * <li>Target Sdk < Q</li>
99 * <li>Target Sdk = Q and has `requestLegacyExternalStorage` set in AndroidManifest.xml</li>
100 * <li>Target Sdk > Q: Upgrading from an app that was opted out of scoped storage and has
101 * `preserveLegacyExternalStorage` set in AndroidManifest.xml</li>
102 * </ul>
103 * This flag is enabled for all apps by default as Scoped Storage is enabled by default.
104 * Developers can disable this flag to opt out of Scoped Storage and have legacy storage
105 * workflow.
106 *
107 * Note: {@code FORCE_ENABLE_SCOPED_STORAGE} should also be disabled for apps to opt out of
108 * scoped storage.
109 * Note: This flag is also used in {@code com.android.providers.media.LocalCallingIdentity}.
110 * Any modifications to this flag should be reflected there as well.
111 * See https://developer.android.com/training/data-storage#scoped-storage for more information.
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +0000112 */
Abhijeet Kaur14c5d832020-03-04 17:34:10 +0000113 @ChangeId
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +0000114 private static final long DEFAULT_SCOPED_STORAGE = 149924527L;
115
116 /**
Abhijeet Kaur14c5d832020-03-04 17:34:10 +0000117 * Setting this flag strictly enforces Scoped Storage regardless of:
118 * <ul>
119 * <li>The value of Target Sdk</li>
120 * <li>The value of `requestLegacyExternalStorage` in AndroidManifest.xml</li>
121 * <li>The value of `preserveLegacyExternalStorage` in AndroidManifest.xml</li>
122 * </ul>
123 *
124 * Note: {@code DEFAULT_SCOPED_STORAGE} should also be enabled for apps to be enforced into
125 * scoped storage.
126 * Note: This flag is also used in {@code com.android.providers.media.LocalCallingIdentity}.
127 * Any modifications to this flag should be reflected there as well.
128 * See https://developer.android.com/training/data-storage#scoped-storage for more information.
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +0000129 */
Abhijeet Kaur14c5d832020-03-04 17:34:10 +0000130 @ChangeId
131 @Disabled
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +0000132 private static final long FORCE_ENABLE_SCOPED_STORAGE = 132649864L;
133
Andrei Onea24ec3212019-03-15 17:35:05 +0000134 @UnsupportedAppUsage
Andreas Gamped281b422016-07-08 03:50:27 +0000135 private static UserEnvironment sCurrentUser;
136 private static boolean sUserRequired;
Kenny Roote1ff2142010-10-12 11:20:01 -0700137
Andreas Gamped281b422016-07-08 03:50:27 +0000138 static {
139 initForCurrentUser();
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700140 }
141
142 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000143 @UnsupportedAppUsage
Andreas Gamped281b422016-07-08 03:50:27 +0000144 public static void initForCurrentUser() {
145 final int userId = UserHandle.myUserId();
146 sCurrentUser = new UserEnvironment(userId);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700147 }
148
149 /** {@hide} */
150 public static class UserEnvironment {
Jeff Sharkey48877892015-03-18 11:27:19 -0700151 private final int mUserId;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700152
Andrei Onea24ec3212019-03-15 17:35:05 +0000153 @UnsupportedAppUsage
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700154 public UserEnvironment(int userId) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700155 mUserId = userId;
156 }
Jeff Sharkey44cbdec2013-10-07 16:49:47 -0700157
Andrei Onea24ec3212019-03-15 17:35:05 +0000158 @UnsupportedAppUsage
Jeff Sharkey48877892015-03-18 11:27:19 -0700159 public File[] getExternalDirs() {
Jeff Sharkey46349872015-07-28 10:49:47 -0700160 final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,
161 StorageManager.FLAG_FOR_WRITE);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700162 final File[] files = new File[volumes.length];
Jeff Sharkey48877892015-03-18 11:27:19 -0700163 for (int i = 0; i < volumes.length; i++) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700164 files[i] = volumes[i].getPathFile();
Jeff Sharkey3fe5bf62012-09-18 15:54:52 -0700165 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700166 return files;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700167 }
168
Andrei Onea24ec3212019-03-15 17:35:05 +0000169 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700170 @Deprecated
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700171 public File getExternalStorageDirectory() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700172 return getExternalDirs()[0];
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700173 }
174
Andrei Onea24ec3212019-03-15 17:35:05 +0000175 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700176 @Deprecated
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700177 public File getExternalStoragePublicDirectory(String type) {
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700178 return buildExternalStoragePublicDirs(type)[0];
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700179 }
180
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700181 public File[] buildExternalStoragePublicDirs(String type) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700182 return buildPaths(getExternalDirs(), type);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700183 }
184
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700185 public File[] buildExternalStorageAndroidDataDirs() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700186 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700187 }
188
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700189 public File[] buildExternalStorageAndroidObbDirs() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700190 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700191 }
192
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700193 public File[] buildExternalStorageAppDataDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700194 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700195 }
Jeff Sharkey3fe5bf62012-09-18 15:54:52 -0700196
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700197 public File[] buildExternalStorageAppMediaDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700198 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName);
Jeff Sharkey2ee3c1e2014-05-30 15:38:35 -0700199 }
200
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700201 public File[] buildExternalStorageAppObbDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700202 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName);
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700203 }
204
205 public File[] buildExternalStorageAppFilesDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700206 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700207 }
208
209 public File[] buildExternalStorageAppCacheDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700210 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
Jeff Sharkey3fe5bf62012-09-18 15:54:52 -0700211 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700212 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 /**
Jeff Sharkey1be762c2014-03-06 09:56:23 -0800215 * Return root of the "system" partition holding the core Android OS.
216 * Always present and mounted read-only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 */
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700218 public static @NonNull File getRootDirectory() {
Jeff Sharkey63d0a062013-03-01 16:12:55 -0800219 return DIR_ANDROID_ROOT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 }
221
Jeff Sharkeyec19e9b2019-08-22 11:12:11 -0600222 /**
223 * Return root directory where all external storage devices will be mounted.
224 * For example, {@link #getExternalStorageDirectory()} will appear under
225 * this location.
226 */
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700227 public static @NonNull File getStorageDirectory() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700228 return DIR_ANDROID_STORAGE;
229 }
230
Jason parksa3cdaa52011-01-13 14:15:43 -0600231 /**
Jeff Sharkey1be762c2014-03-06 09:56:23 -0800232 * Return root directory of the "oem" partition holding OEM customizations,
233 * if any. If present, the partition is mounted read-only.
234 *
235 * @hide
236 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600237 @SystemApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700238 public static @NonNull File getOemDirectory() {
Jeff Sharkey1be762c2014-03-06 09:56:23 -0800239 return DIR_OEM_ROOT;
240 }
241
242 /**
Hung-ying Tyanbdc9d582015-11-20 11:53:39 +0800243 * Return root directory of the "odm" partition holding ODM customizations,
244 * if any. If present, the partition is mounted read-only.
245 *
246 * @hide
247 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600248 @SystemApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700249 public static @NonNull File getOdmDirectory() {
Hung-ying Tyanbdc9d582015-11-20 11:53:39 +0800250 return DIR_ODM_ROOT;
251 }
252
253 /**
Christopher Tate740888f2014-04-18 12:24:57 -0700254 * Return root directory of the "vendor" partition that holds vendor-provided
255 * software that should persist across simple reflashing of the "system" partition.
256 * @hide
257 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600258 @SystemApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700259 public static @NonNull File getVendorDirectory() {
Christopher Tate740888f2014-04-18 12:24:57 -0700260 return DIR_VENDOR_ROOT;
261 }
262
Jason parksa3cdaa52011-01-13 14:15:43 -0600263 /**
Jaekyun Seok1713d9e2018-01-12 21:47:26 +0900264 * Return root directory of the "product" partition holding product-specific
265 * customizations if any. If present, the partition is mounted read-only.
266 *
267 * @hide
268 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600269 @SystemApi
Anton Hansson09e47be2018-11-08 12:56:18 +0000270 @TestApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700271 public static @NonNull File getProductDirectory() {
Jaekyun Seok1713d9e2018-01-12 21:47:26 +0900272 return DIR_PRODUCT_ROOT;
273 }
274
275 /**
Dario Freni2bef1762018-06-01 14:02:08 +0100276 * Return root directory of the "product_services" partition holding middleware
277 * services if any. If present, the partition is mounted read-only.
278 *
Jeongik Cha9ec059a2019-07-04 21:12:06 +0900279 * @deprecated This directory is not guaranteed to exist.
280 * Its name is changed to "system_ext" because the partition's purpose is changed.
281 * {@link #getSystemExtDirectory()}
Dario Freni2bef1762018-06-01 14:02:08 +0100282 * @hide
283 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600284 @SystemApi
Jeongik Cha9ec059a2019-07-04 21:12:06 +0900285 @Deprecated
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700286 public static @NonNull File getProductServicesDirectory() {
Jeongik Cha9ec059a2019-07-04 21:12:06 +0900287 return getDirectory("PRODUCT_SERVICES_ROOT", "/product_services");
288 }
289
290 /**
291 * Return root directory of the "system_ext" partition holding system partition's extension
292 * If present, the partition is mounted read-only.
293 *
294 * @hide
295 */
296 @SystemApi
297 public static @NonNull File getSystemExtDirectory() {
298 return DIR_SYSTEM_EXT_ROOT;
Dario Freni2bef1762018-06-01 14:02:08 +0100299 }
300
301 /**
Dario Frenic3e1bb722019-10-09 15:43:38 +0100302 * Return root directory of the apex mount point, where all the apex modules are made available
303 * to the rest of the system.
304 *
305 * @hide
306 */
307 public static @NonNull File getApexDirectory() {
308 return DIR_APEX_ROOT;
309 }
310
311 /**
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700312 * Return the system directory for a user. This is for use by system
313 * services to store files relating to the user. This directory will be
314 * automatically deleted when the user is removed.
Amith Yamasani61f57372012-08-31 12:12:28 -0700315 *
Jeff Sharkey3a6a61e2018-10-03 10:45:51 -0600316 * @deprecated This directory is valid and still exists, but but callers
317 * should <em>strongly</em> consider switching to using either
318 * {@link #getDataSystemCeDirectory(int)} or
319 * {@link #getDataSystemDeDirectory(int)}, both of which support
320 * fast user wipe.
Amith Yamasani61f57372012-08-31 12:12:28 -0700321 * @hide
322 */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700323 @Deprecated
Amith Yamasani61f57372012-08-31 12:12:28 -0700324 public static File getUserSystemDirectory(int userId) {
Jeff Sharkey15447792015-11-05 16:18:51 -0800325 return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
Amith Yamasani61f57372012-08-31 12:12:28 -0700326 }
327
328 /**
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700329 * Returns the config directory for a user. This is for use by system
330 * services to store files relating to the user which should be readable by
331 * any app running as that user.
Robin Lee69591332014-04-28 16:03:22 +0100332 *
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700333 * @deprecated This directory is valid and still exists, but callers should
334 * <em>strongly</em> consider switching to
335 * {@link #getDataMiscCeDirectory(int)} which is protected with
336 * user credentials or {@link #getDataMiscDeDirectory(int)}
337 * which supports fast user wipe.
Robin Lee69591332014-04-28 16:03:22 +0100338 * @hide
339 */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700340 @Deprecated
Robin Lee69591332014-04-28 16:03:22 +0100341 public static File getUserConfigDirectory(int userId) {
342 return new File(new File(new File(
343 getDataDirectory(), "misc"), "user"), Integer.toString(userId));
344 }
345
346 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700347 * Return the user data directory.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 */
349 public static File getDataDirectory() {
Jeff Sharkey15447792015-11-05 16:18:51 -0800350 return DIR_ANDROID_DATA;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 }
352
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -0700353 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700354 public static File getDataDirectory(String volumeUuid) {
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -0700355 if (TextUtils.isEmpty(volumeUuid)) {
Jeff Sharkey15447792015-11-05 16:18:51 -0800356 return DIR_ANDROID_DATA;
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -0700357 } else {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700358 return new File("/mnt/expand/" + volumeUuid);
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -0700359 }
360 }
361
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700362 /** {@hide} */
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -0600363 public static File getExpandDirectory() {
364 return DIR_ANDROID_EXPAND;
365 }
366
367 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000368 @UnsupportedAppUsage
Jeff Sharkey15447792015-11-05 16:18:51 -0800369 public static File getDataSystemDirectory() {
370 return new File(getDataDirectory(), "system");
371 }
372
Amith Yamasanid04aaa32016-06-13 12:09:36 -0700373 /**
374 * Returns the base directory for per-user system directory, device encrypted.
375 * {@hide}
376 */
377 public static File getDataSystemDeDirectory() {
378 return buildPath(getDataDirectory(), "system_de");
379 }
380
381 /**
382 * Returns the base directory for per-user system directory, credential encrypted.
383 * {@hide}
384 */
385 public static File getDataSystemCeDirectory() {
386 return buildPath(getDataDirectory(), "system_ce");
387 }
388
Jeff Sharkey3a6a61e2018-10-03 10:45:51 -0600389 /**
390 * Return the "credential encrypted" system directory for a user. This is
391 * for use by system services to store files relating to the user. This
392 * directory supports fast user wipe, and will be automatically deleted when
393 * the user is removed.
394 * <p>
395 * Data stored under this path is "credential encrypted", which uses an
396 * encryption key that is entangled with user credentials, such as a PIN or
397 * password. The contents will only be available once the user has been
398 * unlocked, as reported by {@code SystemService.onUnlockUser()}.
399 * <p>
400 * New code should <em>strongly</em> prefer storing sensitive data in these
401 * credential encrypted areas.
402 *
403 * @hide
404 */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700405 public static File getDataSystemCeDirectory(int userId) {
406 return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
Jeff Sharkey15447792015-11-05 16:18:51 -0800407 }
408
Jeff Sharkey3a6a61e2018-10-03 10:45:51 -0600409 /**
410 * Return the "device encrypted" system directory for a user. This is for
411 * use by system services to store files relating to the user. This
412 * directory supports fast user wipe, and will be automatically deleted when
413 * the user is removed.
414 * <p>
415 * Data stored under this path is "device encrypted", which uses an
416 * encryption key that is tied to the physical device. The contents will
417 * only be available once the device has finished a {@code dm-verity}
418 * protected boot.
419 * <p>
420 * New code should <em>strongly</em> avoid storing sensitive data in these
421 * device encrypted areas.
422 *
423 * @hide
424 */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700425 public static File getDataSystemDeDirectory(int userId) {
426 return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
427 }
428
429 /** {@hide} */
430 public static File getDataMiscDirectory() {
431 return new File(getDataDirectory(), "misc");
432 }
433
434 /** {@hide} */
Amith Yamasania2807132017-01-26 12:35:14 -0800435 public static File getDataMiscCeDirectory() {
436 return buildPath(getDataDirectory(), "misc_ce");
437 }
438
439 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700440 public static File getDataMiscCeDirectory(int userId) {
441 return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
442 }
443
444 /** {@hide} */
445 public static File getDataMiscDeDirectory(int userId) {
446 return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
Jeff Sharkey15447792015-11-05 16:18:51 -0800447 }
448
Calin Juravled479b522016-02-24 16:22:03 +0000449 private static File getDataProfilesDeDirectory(int userId) {
450 return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
451 }
452
453 /** {@hide} */
Andreas Huber7fe20532018-01-22 11:26:44 -0800454 public static File getDataVendorCeDirectory(int userId) {
455 return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId));
456 }
457
458 /** {@hide} */
459 public static File getDataVendorDeDirectory(int userId) {
460 return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId));
461 }
462
463 /** {@hide} */
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800464 public static File getDataRefProfilesDePackageDirectory(String packageName) {
465 return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
Calin Juravle0bd77622016-07-12 15:56:41 +0100466 }
467
468 /** {@hide} */
Calin Juravled479b522016-02-24 16:22:03 +0000469 public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
470 return buildPath(getDataProfilesDeDirectory(userId), packageName);
471 }
472
473 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700474 public static File getDataAppDirectory(String volumeUuid) {
475 return new File(getDataDirectory(volumeUuid), "app");
476 }
477
478 /** {@hide} */
Dario Frenia8f4b132018-12-30 00:36:49 +0000479 public static File getDataStagingDirectory(String volumeUuid) {
Gavin Corkery296c8b92019-02-27 12:06:24 +0000480 return new File(getDataDirectory(volumeUuid), "app-staging");
Dario Frenia8f4b132018-12-30 00:36:49 +0000481 }
482
483 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700484 public static File getDataUserCeDirectory(String volumeUuid) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700485 return new File(getDataDirectory(volumeUuid), "user");
486 }
487
488 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700489 public static File getDataUserCeDirectory(String volumeUuid, int userId) {
490 return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700491 }
492
493 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700494 public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700495 String packageName) {
496 // TODO: keep consistent with installd
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700497 return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
Jeff Sharkey15447792015-11-05 16:18:51 -0800498 }
499
500 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700501 public static File getDataUserDeDirectory(String volumeUuid) {
Jeff Sharkey15447792015-11-05 16:18:51 -0800502 return new File(getDataDirectory(volumeUuid), "user_de");
503 }
504
505 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700506 public static File getDataUserDeDirectory(String volumeUuid, int userId) {
507 return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
Jeff Sharkey15447792015-11-05 16:18:51 -0800508 }
509
510 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700511 public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
Jeff Sharkey15447792015-11-05 16:18:51 -0800512 String packageName) {
513 // TODO: keep consistent with installd
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700514 return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700515 }
516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 /**
Fyodor Kupolov88257582016-05-24 16:06:56 -0700518 * Return preloads directory.
519 * <p>This directory may contain pre-loaded content such as
520 * {@link #getDataPreloadsDemoDirectory() demo videos} and
521 * {@link #getDataPreloadsAppsDirectory() APK files} .
522 * {@hide}
523 */
524 public static File getDataPreloadsDirectory() {
525 return new File(getDataDirectory(), "preloads");
526 }
527
528 /**
529 * @see #getDataPreloadsDirectory()
530 * {@hide}
531 */
532 public static File getDataPreloadsDemoDirectory() {
533 return new File(getDataPreloadsDirectory(), "demo");
534 }
535
536 /**
537 * @see #getDataPreloadsDirectory()
538 * {@hide}
539 */
540 public static File getDataPreloadsAppsDirectory() {
541 return new File(getDataPreloadsDirectory(), "apps");
542 }
543
544 /**
Fyodor Kupolov19551a82016-08-22 14:46:08 -0700545 * @see #getDataPreloadsDirectory()
546 * {@hide}
547 */
548 public static File getDataPreloadsMediaDirectory() {
549 return new File(getDataPreloadsDirectory(), "media");
550 }
551
552 /**
Fyodor Kupolov6e687062016-09-09 17:42:12 -0700553 * Returns location of preloaded cache directory for package name
554 * @see #getDataPreloadsDirectory()
555 * {@hide}
556 */
557 public static File getDataPreloadsFileCacheDirectory(String packageName) {
558 return new File(getDataPreloadsFileCacheDirectory(), packageName);
559 }
560
561 /**
562 * Returns location of preloaded cache directory.
563 * @see #getDataPreloadsDirectory()
564 * {@hide}
565 */
566 public static File getDataPreloadsFileCacheDirectory() {
567 return new File(getDataPreloadsDirectory(), "file_cache");
568 }
569
570 /**
Sudheer Shankabe0febe2018-11-07 18:24:37 -0800571 * Returns location of packages cache directory.
572 * {@hide}
573 */
574 public static File getPackageCacheDirectory() {
575 return new File(getDataSystemDirectory(), "package_cache");
576 }
577
578 /**
Jeff Sharkey04b4ba12019-12-15 22:42:42 -0700579 * Return locations where media files (such as ringtones, notification
580 * sounds, or alarm sounds) may be located on internal storage. These are
581 * typically indexed under {@link MediaStore#VOLUME_INTERNAL}.
582 *
583 * @hide
584 */
585 @SystemApi
586 public static @NonNull Collection<File> getInternalMediaDirectories() {
587 final ArrayList<File> res = new ArrayList<>();
Hung-ying Tyan774d89e2020-02-05 16:55:01 +0800588 addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
589 addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
590 addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
Jeff Sharkey04b4ba12019-12-15 22:42:42 -0700591 return res;
592 }
593
Hung-ying Tyan774d89e2020-02-05 16:55:01 +0800594 private static void addCanonicalFile(List<File> list, File file) {
595 try {
596 list.add(file.getCanonicalFile());
597 } catch (IOException e) {
598 Log.w(TAG, "Failed to resolve " + file + ": " + e);
599 list.add(file);
600 }
601 }
602
Jeff Sharkey04b4ba12019-12-15 22:42:42 -0700603 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700604 * Return the primary shared/external storage directory. This directory may
605 * not currently be accessible if it has been mounted by the user on their
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800606 * computer, has been removed from the device, or some other problem has
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700607 * happened. You can determine its current state with
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800608 * {@link #getExternalStorageState()}.
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700609 * <p>
610 * <em>Note: don't be confused by the word "external" here. This directory
611 * can better be thought as media/shared storage. It is a filesystem that
612 * can hold a relatively large amount of data and that is shared across all
613 * applications (does not enforce permissions). Traditionally this is an SD
614 * card, but it may also be implemented as built-in storage in a device that
615 * is distinct from the protected internal storage and can be mounted as a
616 * filesystem on a computer.</em>
617 * <p>
618 * On devices with multiple users (as described by {@link UserManager}),
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700619 * each user has their own isolated shared storage. Applications only have
620 * access to the shared storage for the user they're running as.
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700621 * <p>
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700622 * In devices with multiple shared/external storage directories, this
623 * directory represents the primary storage that the user will interact
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700624 * with. Access to secondary storage is available through
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700625 * {@link Context#getExternalFilesDirs(String)},
626 * {@link Context#getExternalCacheDirs()}, and
627 * {@link Context#getExternalMediaDirs()}.
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700628 * <p>
629 * Applications should not directly use this top-level directory, in order
630 * to avoid polluting the user's root namespace. Any files that are private
631 * to the application should be placed in a directory returned by
632 * {@link android.content.Context#getExternalFilesDir
Dianne Hackbornacaf0282010-03-30 14:39:35 -0700633 * Context.getExternalFilesDir}, which the system will take care of deleting
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700634 * if the application is uninstalled. Other shared files should be placed in
635 * one of the directories returned by
636 * {@link #getExternalStoragePublicDirectory}.
637 * <p>
638 * Writing to this path requires the
639 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
Jeff Sharkey488162b2019-04-27 17:03:54 -0600640 * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read
641 * access requires the
Jeff Sharkey8c165792012-10-22 14:08:29 -0700642 * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700643 * which is automatically granted if you hold the write permission.
644 * <p>
Chet Haasee8222dd2013-09-05 07:44:18 -0700645 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700646 * application only needs to store internal data, consider using
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700647 * {@link Context#getExternalFilesDir(String)},
648 * {@link Context#getExternalCacheDir()}, or
649 * {@link Context#getExternalMediaDirs()}, which require no permissions to
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700650 * read or write.
651 * <p>
652 * This path may change between platform versions, so applications should
653 * only persist relative paths.
654 * <p>
655 * Here is an example of typical code to monitor the state of external
656 * storage:
657 * <p>
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700658 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800659 * monitor_storage}
Dianne Hackborn407f6252010-10-04 11:31:17 -0700660 *
661 * @see #getExternalStorageState()
662 * @see #isExternalStorageRemovable()
Jeff Sharkey488162b2019-04-27 17:03:54 -0600663 * @deprecated To improve user privacy, direct access to shared/external
664 * storage devices is deprecated. When an app targets
665 * {@link android.os.Build.VERSION_CODES#Q}, the path returned
666 * from this method is no longer directly accessible to apps.
667 * Apps can continue to access content stored on shared/external
668 * storage by migrating to alternatives such as
669 * {@link Context#getExternalFilesDir(String)},
670 * {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 */
Jeff Sharkey488162b2019-04-27 17:03:54 -0600672 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 public static File getExternalStorageDirectory() {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700674 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000675 return sCurrentUser.getExternalDirs()[0];
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700676 }
677
678 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000679 @UnsupportedAppUsage
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700680 public static File getLegacyExternalStorageDirectory() {
681 return new File(System.getenv(ENV_EXTERNAL_STORAGE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700684 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000685 @UnsupportedAppUsage
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700686 public static File getLegacyExternalStorageObbDirectory() {
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700687 return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700688 }
689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 /**
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800691 * Standard directory in which to place any audio files that should be
692 * in the regular list of music for the user.
693 * This may be combined with
694 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
695 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
696 * of directories to categories a particular audio file as more than one
697 * type.
698 */
699 public static String DIRECTORY_MUSIC = "Music";
Felipe Lemec7b1f892016-01-15 15:02:31 -0800700
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800701 /**
702 * Standard directory in which to place any audio files that should be
703 * in the list of podcasts that the user can select (not as regular
704 * music).
705 * This may be combined with {@link #DIRECTORY_MUSIC},
706 * {@link #DIRECTORY_NOTIFICATIONS},
707 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
708 * of directories to categories a particular audio file as more than one
709 * type.
710 */
711 public static String DIRECTORY_PODCASTS = "Podcasts";
Felipe Lemeb012f912016-01-22 16:49:55 -0800712
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800713 /**
714 * Standard directory in which to place any audio files that should be
715 * in the list of ringtones that the user can select (not as regular
716 * music).
717 * This may be combined with {@link #DIRECTORY_MUSIC},
718 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
719 * {@link #DIRECTORY_ALARMS} as a series
720 * of directories to categories a particular audio file as more than one
721 * type.
722 */
723 public static String DIRECTORY_RINGTONES = "Ringtones";
Felipe Lemeb012f912016-01-22 16:49:55 -0800724
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800725 /**
726 * Standard directory in which to place any audio files that should be
727 * in the list of alarms that the user can select (not as regular
728 * music).
729 * This may be combined with {@link #DIRECTORY_MUSIC},
730 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
731 * and {@link #DIRECTORY_RINGTONES} as a series
732 * of directories to categories a particular audio file as more than one
733 * type.
734 */
735 public static String DIRECTORY_ALARMS = "Alarms";
Felipe Lemeb012f912016-01-22 16:49:55 -0800736
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800737 /**
738 * Standard directory in which to place any audio files that should be
739 * in the list of notifications that the user can select (not as regular
740 * music).
741 * This may be combined with {@link #DIRECTORY_MUSIC},
742 * {@link #DIRECTORY_PODCASTS},
743 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
744 * of directories to categories a particular audio file as more than one
745 * type.
746 */
747 public static String DIRECTORY_NOTIFICATIONS = "Notifications";
Felipe Lemeb012f912016-01-22 16:49:55 -0800748
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800749 /**
750 * Standard directory in which to place pictures that are available to
751 * the user. Note that this is primarily a convention for the top-level
752 * public directory, as the media scanner will find and collect pictures
753 * in any directory.
754 */
755 public static String DIRECTORY_PICTURES = "Pictures";
Felipe Lemeb012f912016-01-22 16:49:55 -0800756
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800757 /**
758 * Standard directory in which to place movies that are available to
759 * the user. Note that this is primarily a convention for the top-level
760 * public directory, as the media scanner will find and collect movies
761 * in any directory.
762 */
763 public static String DIRECTORY_MOVIES = "Movies";
Felipe Lemeb012f912016-01-22 16:49:55 -0800764
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800765 /**
766 * Standard directory in which to place files that have been downloaded by
767 * the user. Note that this is primarily a convention for the top-level
768 * public directory, you are free to download files anywhere in your own
Dianne Hackbornce59fb82010-04-07 17:19:04 -0700769 * private directories. Also note that though the constant here is
770 * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
771 * backwards compatibility reasons.
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800772 */
Dianne Hackbornce59fb82010-04-07 17:19:04 -0700773 public static String DIRECTORY_DOWNLOADS = "Download";
Felipe Lemeb012f912016-01-22 16:49:55 -0800774
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800775 /**
776 * The traditional location for pictures and videos when mounting the
777 * device as a camera. Note that this is primarily a convention for the
778 * top-level public directory, as this convention makes no sense elsewhere.
779 */
780 public static String DIRECTORY_DCIM = "DCIM";
Jeff Sharkey3e1189b2013-09-12 21:59:06 -0700781
782 /**
783 * Standard directory in which to place documents that have been created by
784 * the user.
785 */
786 public static String DIRECTORY_DOCUMENTS = "Documents";
787
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800788 /**
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600789 * Standard directory in which to place screenshots that have been taken by
790 * the user. Typically used as a secondary directory under
791 * {@link #DIRECTORY_PICTURES}.
792 */
793 public static String DIRECTORY_SCREENSHOTS = "Screenshots";
794
795 /**
Jeff Sharkey10887d52018-11-30 13:44:41 -0700796 * Standard directory in which to place any audio files which are
797 * audiobooks.
798 */
799 public static String DIRECTORY_AUDIOBOOKS = "Audiobooks";
800
801 /**
Felipe Lemec7b1f892016-01-15 15:02:31 -0800802 * List of standard storage directories.
803 * <p>
804 * Each of its values have its own constant:
805 * <ul>
806 * <li>{@link #DIRECTORY_MUSIC}
807 * <li>{@link #DIRECTORY_PODCASTS}
808 * <li>{@link #DIRECTORY_ALARMS}
809 * <li>{@link #DIRECTORY_RINGTONES}
810 * <li>{@link #DIRECTORY_NOTIFICATIONS}
811 * <li>{@link #DIRECTORY_PICTURES}
812 * <li>{@link #DIRECTORY_MOVIES}
813 * <li>{@link #DIRECTORY_DOWNLOADS}
814 * <li>{@link #DIRECTORY_DCIM}
815 * <li>{@link #DIRECTORY_DOCUMENTS}
Jeff Sharkey10887d52018-11-30 13:44:41 -0700816 * <li>{@link #DIRECTORY_AUDIOBOOKS}
Felipe Lemec7b1f892016-01-15 15:02:31 -0800817 * </ul>
818 * @hide
819 */
Felipe Leme3e166b22016-02-24 10:17:41 -0800820 public static final String[] STANDARD_DIRECTORIES = {
Felipe Lemec7b1f892016-01-15 15:02:31 -0800821 DIRECTORY_MUSIC,
822 DIRECTORY_PODCASTS,
823 DIRECTORY_RINGTONES,
824 DIRECTORY_ALARMS,
825 DIRECTORY_NOTIFICATIONS,
826 DIRECTORY_PICTURES,
827 DIRECTORY_MOVIES,
828 DIRECTORY_DOWNLOADS,
829 DIRECTORY_DCIM,
Jeff Sharkey10887d52018-11-30 13:44:41 -0700830 DIRECTORY_DOCUMENTS,
831 DIRECTORY_AUDIOBOOKS,
Felipe Lemec7b1f892016-01-15 15:02:31 -0800832 };
833
834 /**
Felipe Lemeb012f912016-01-22 16:49:55 -0800835 * @hide
836 */
837 public static boolean isStandardDirectory(String dir) {
838 for (String valid : STANDARD_DIRECTORIES) {
839 if (valid.equals(dir)) {
840 return true;
841 }
842 }
843 return false;
844 }
845
Jeff Sharkey20356142017-12-06 15:22:05 -0700846 /** {@hide} */ public static final int HAS_MUSIC = 1 << 0;
847 /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1;
848 /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2;
849 /** {@hide} */ public static final int HAS_ALARMS = 1 << 3;
850 /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4;
851 /** {@hide} */ public static final int HAS_PICTURES = 1 << 5;
852 /** {@hide} */ public static final int HAS_MOVIES = 1 << 6;
853 /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7;
854 /** {@hide} */ public static final int HAS_DCIM = 1 << 8;
855 /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9;
Jeff Sharkey10887d52018-11-30 13:44:41 -0700856 /** {@hide} */ public static final int HAS_AUDIOBOOKS = 1 << 10;
Jeff Sharkey20356142017-12-06 15:22:05 -0700857
858 /** {@hide} */ public static final int HAS_ANDROID = 1 << 16;
859 /** {@hide} */ public static final int HAS_OTHER = 1 << 17;
860
861 /**
862 * Classify the content types present on the given external storage device.
863 * <p>
864 * This is typically useful for deciding if an inserted SD card is empty, or
865 * if it contains content like photos that should be preserved.
866 *
867 * @hide
868 */
869 public static int classifyExternalStorageDirectory(File dir) {
870 int res = 0;
871 for (File f : FileUtils.listFilesOrEmpty(dir)) {
872 if (f.isFile() && isInterestingFile(f)) {
873 res |= HAS_OTHER;
874 } else if (f.isDirectory() && hasInterestingFiles(f)) {
875 final String name = f.getName();
876 if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC;
877 else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS;
878 else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES;
879 else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS;
880 else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS;
881 else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES;
882 else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES;
883 else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS;
884 else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM;
885 else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS;
Jeff Sharkey10887d52018-11-30 13:44:41 -0700886 else if (DIRECTORY_AUDIOBOOKS.equals(name)) res |= HAS_AUDIOBOOKS;
Jeff Sharkey20356142017-12-06 15:22:05 -0700887 else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID;
888 else res |= HAS_OTHER;
889 }
890 }
891 return res;
892 }
893
894 private static boolean hasInterestingFiles(File dir) {
895 final LinkedList<File> explore = new LinkedList<>();
896 explore.add(dir);
897 while (!explore.isEmpty()) {
898 dir = explore.pop();
899 for (File f : FileUtils.listFilesOrEmpty(dir)) {
900 if (isInterestingFile(f)) return true;
901 if (f.isDirectory()) explore.add(f);
902 }
903 }
904 return false;
905 }
906
907 private static boolean isInterestingFile(File file) {
908 if (file.isFile()) {
909 final String name = file.getName().toLowerCase();
910 if (name.endsWith(".exe") || name.equals("autorun.inf")
911 || name.equals("launchpad.zip") || name.equals(".nomedia")) {
912 return false;
913 } else {
914 return true;
915 }
916 } else {
917 return false;
918 }
919 }
920
Felipe Lemeb012f912016-01-22 16:49:55 -0800921 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700922 * Get a top-level shared/external storage directory for placing files of a
923 * particular type. This is where the user will typically place and manage
924 * their own files, so you should be careful about what you put here to
925 * ensure you don't erase their files or get in the way of their own
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800926 * organization.
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700927 * <p>
928 * On devices with multiple users (as described by {@link UserManager}),
929 * each user has their own isolated shared storage. Applications only have
930 * access to the shared storage for the user they're running as.
931 * </p>
932 * <p>
933 * Here is an example of typical code to manipulate a picture on the public
934 * shared storage:
935 * </p>
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800936 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
937 * public_picture}
Felipe Lemec7b1f892016-01-15 15:02:31 -0800938 *
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700939 * @param type The type of storage directory to return. Should be one of
940 * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
941 * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
942 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
Felipe Lemec7b1f892016-01-15 15:02:31 -0800943 * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS},
944 * {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null.
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700945 * @return Returns the File path for the directory. Note that this directory
946 * may not yet exist, so you must make sure it exists before using
947 * it such as with {@link File#mkdirs File.mkdirs()}.
Jeff Sharkey488162b2019-04-27 17:03:54 -0600948 * @deprecated To improve user privacy, direct access to shared/external
949 * storage devices is deprecated. When an app targets
950 * {@link android.os.Build.VERSION_CODES#Q}, the path returned
951 * from this method is no longer directly accessible to apps.
952 * Apps can continue to access content stored on shared/external
953 * storage by migrating to alternatives such as
954 * {@link Context#getExternalFilesDir(String)},
955 * {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT}.
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800956 */
Jeff Sharkey488162b2019-04-27 17:03:54 -0600957 @Deprecated
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800958 public static File getExternalStoragePublicDirectory(String type) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700959 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000960 return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800961 }
962
963 /**
964 * Returns the path for android-specific data on the SD card.
965 * @hide
966 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000967 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700968 public static File[] buildExternalStorageAndroidDataDirs() {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700969 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000970 return sCurrentUser.buildExternalStorageAndroidDataDirs();
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800971 }
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700972
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800973 /**
974 * Generates the raw path to an application's data
975 * @hide
976 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000977 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700978 public static File[] buildExternalStorageAppDataDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700979 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000980 return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800981 }
Felipe Lemeb012f912016-01-22 16:49:55 -0800982
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800983 /**
984 * Generates the raw path to an application's media
985 * @hide
986 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000987 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700988 public static File[] buildExternalStorageAppMediaDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700989 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000990 return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800991 }
Felipe Lemeb012f912016-01-22 16:49:55 -0800992
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800993 /**
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800994 * Generates the raw path to an application's OBB files
995 * @hide
996 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000997 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700998 public static File[] buildExternalStorageAppObbDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700999 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +00001000 return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
Dianne Hackborn805fd7e2011-01-16 18:30:29 -08001001 }
Felipe Lemeb012f912016-01-22 16:49:55 -08001002
Dianne Hackborn805fd7e2011-01-16 18:30:29 -08001003 /**
Dianne Hackborne83cefce2010-02-04 17:38:14 -08001004 * Generates the path to an application's files.
1005 * @hide
1006 */
Andrei Onea24ec3212019-03-15 17:35:05 +00001007 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001008 public static File[] buildExternalStorageAppFilesDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -07001009 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +00001010 return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -08001011 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001012
Dianne Hackborne83cefce2010-02-04 17:38:14 -08001013 /**
1014 * Generates the path to an application's cache.
1015 * @hide
1016 */
Andrei Onea24ec3212019-03-15 17:35:05 +00001017 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001018 public static File[] buildExternalStorageAppCacheDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -07001019 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +00001020 return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -08001021 }
Felipe Lemeb012f912016-01-22 16:49:55 -08001022
Sudheer Shanka25f1c6e2019-04-22 17:03:47 -07001023 /** @hide */
1024 public static File[] buildExternalStoragePublicDirs(@NonNull String dirType) {
1025 throwIfUserRequired();
1026 return sCurrentUser.buildExternalStoragePublicDirs(dirType);
1027 }
1028
Dianne Hackborne83cefce2010-02-04 17:38:14 -08001029 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001030 * Return the download/cache content directory.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 */
1032 public static File getDownloadCacheDirectory() {
Jeff Sharkey15447792015-11-05 16:18:51 -08001033 return DIR_DOWNLOAD_CACHE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 }
1035
1036 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001037 * Unknown storage state, such as when a path isn't backed by known storage
1038 * media.
1039 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001040 * @see #getExternalStorageState(File)
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001041 */
1042 public static final String MEDIA_UNKNOWN = "unknown";
1043
1044 /**
1045 * Storage state if the media is not present.
1046 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001047 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 */
1049 public static final String MEDIA_REMOVED = "removed";
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001052 * Storage state if the media is present but not mounted.
1053 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001054 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 */
1056 public static final String MEDIA_UNMOUNTED = "unmounted";
1057
1058 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001059 * Storage state if the media is present and being disk-checked.
1060 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001061 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 */
1063 public static final String MEDIA_CHECKING = "checking";
1064
1065 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001066 * Storage state if the media is present but is blank or is using an
1067 * unsupported filesystem.
1068 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001069 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 */
1071 public static final String MEDIA_NOFS = "nofs";
1072
1073 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001074 * Storage state if the media is present and mounted at its mount point with
1075 * read/write access.
1076 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001077 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001078 */
1079 public static final String MEDIA_MOUNTED = "mounted";
1080
1081 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001082 * Storage state if the media is present and mounted at its mount point with
1083 * read-only access.
1084 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001085 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 */
1087 public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
1088
1089 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001090 * Storage state if the media is present not mounted, and shared via USB
1091 * mass storage.
1092 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001093 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 */
1095 public static final String MEDIA_SHARED = "shared";
1096
1097 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001098 * Storage state if the media was removed before it was unmounted.
1099 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001100 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 */
1102 public static final String MEDIA_BAD_REMOVAL = "bad_removal";
1103
1104 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001105 * Storage state if the media is present but cannot be mounted. Typically
1106 * this happens if the file system on the media is corrupted.
1107 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001108 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 */
1110 public static final String MEDIA_UNMOUNTABLE = "unmountable";
1111
1112 /**
Jeff Sharkey48877892015-03-18 11:27:19 -07001113 * Storage state if the media is in the process of being ejected.
1114 *
1115 * @see #getExternalStorageState(File)
1116 */
1117 public static final String MEDIA_EJECTING = "ejecting";
1118
1119 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001120 * Returns the current state of the primary shared/external storage media.
Felipe Lemec7b1f892016-01-15 15:02:31 -08001121 *
Jeff Sharkey8c165792012-10-22 14:08:29 -07001122 * @see #getExternalStorageDirectory()
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001123 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
1124 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
1125 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
1126 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
1127 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 */
1129 public static String getExternalStorageState() {
Andreas Gamped281b422016-07-08 03:50:27 +00001130 final File externalDir = sCurrentUser.getExternalDirs()[0];
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001131 return getExternalStorageState(externalDir);
1132 }
1133
1134 /**
1135 * @deprecated use {@link #getExternalStorageState(File)}
1136 */
1137 @Deprecated
1138 public static String getStorageState(File path) {
1139 return getExternalStorageState(path);
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001140 }
1141
1142 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001143 * Returns the current state of the shared/external storage media at the
1144 * given path.
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001145 *
1146 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
1147 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
1148 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
1149 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
1150 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
1151 */
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001152 public static String getExternalStorageState(File path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001153 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001154 if (volume != null) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001155 return volume.getState();
1156 } else {
1157 return MEDIA_UNKNOWN;
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 }
1160
Dianne Hackborn407f6252010-10-04 11:31:17 -07001161 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001162 * Returns whether the primary shared/external storage media is physically
1163 * removable.
Dianne Hackborn407f6252010-10-04 11:31:17 -07001164 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001165 * @return true if the storage device can be removed (such as an SD card),
1166 * or false if the storage device is built in and cannot be
1167 * physically removed.
Dianne Hackborn407f6252010-10-04 11:31:17 -07001168 */
1169 public static boolean isExternalStorageRemovable() {
Andreas Gamped281b422016-07-08 03:50:27 +00001170 final File externalDir = sCurrentUser.getExternalDirs()[0];
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001171 return isExternalStorageRemovable(externalDir);
Dianne Hackborn407f6252010-10-04 11:31:17 -07001172 }
1173
Kenny Roote1ff2142010-10-12 11:20:01 -07001174 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001175 * Returns whether the shared/external storage media at the given path is
1176 * physically removable.
Andy Stadler50c294f2011-03-07 19:13:42 -08001177 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001178 * @return true if the storage device can be removed (such as an SD card),
1179 * or false if the storage device is built in and cannot be
1180 * physically removed.
1181 * @throws IllegalArgumentException if the path is not a valid storage
1182 * device.
1183 */
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001184 public static boolean isExternalStorageRemovable(@NonNull File path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001185 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001186 if (volume != null) {
1187 return volume.isRemovable();
1188 } else {
1189 throw new IllegalArgumentException("Failed to find storage device at " + path);
1190 }
1191 }
1192
1193 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001194 * Returns whether the primary shared/external storage media is emulated.
1195 * <p>
1196 * The contents of emulated storage devices are backed by a private user
1197 * data partition, which means there is little benefit to apps storing data
1198 * here instead of the private directories returned by
1199 * {@link Context#getFilesDir()}, etc.
1200 * <p>
1201 * This returns true when emulated storage is backed by either internal
1202 * storage or an adopted storage device.
Andy Stadler50c294f2011-03-07 19:13:42 -08001203 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001204 * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
1205 * boolean)
Kenny Roote1ff2142010-10-12 11:20:01 -07001206 */
1207 public static boolean isExternalStorageEmulated() {
Andreas Gamped281b422016-07-08 03:50:27 +00001208 final File externalDir = sCurrentUser.getExternalDirs()[0];
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001209 return isExternalStorageEmulated(externalDir);
1210 }
1211
1212 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001213 * Returns whether the shared/external storage media at the given path is
1214 * emulated.
1215 * <p>
1216 * The contents of emulated storage devices are backed by a private user
1217 * data partition, which means there is little benefit to apps storing data
1218 * here instead of the private directories returned by
1219 * {@link Context#getFilesDir()}, etc.
1220 * <p>
1221 * This returns true when emulated storage is backed by either internal
1222 * storage or an adopted storage device.
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001223 *
1224 * @throws IllegalArgumentException if the path is not a valid storage
1225 * device.
1226 */
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001227 public static boolean isExternalStorageEmulated(@NonNull File path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001228 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001229 if (volume != null) {
1230 return volume.isEmulated();
1231 } else {
1232 throw new IllegalArgumentException("Failed to find storage device at " + path);
1233 }
Kenny Roote1ff2142010-10-12 11:20:01 -07001234 }
1235
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001236 /**
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +00001237 * Returns whether the shared/external storage media is a
1238 * legacy view that includes files not owned by the app.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001239 * <p>
1240 * This value may be different from the value requested by
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001241 * {@code requestLegacyExternalStorage} in the app's manifest, since an app
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +00001242 * may inherit its legacy state based on when it was first installed, target sdk and other
1243 * factors.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001244 * <p>
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001245 * Non-legacy apps can continue to discover and read media belonging to
1246 * other apps via {@link android.provider.MediaStore}.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001247 */
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001248 public static boolean isExternalStorageLegacy() {
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001249 final File externalDir = sCurrentUser.getExternalDirs()[0];
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001250 return isExternalStorageLegacy(externalDir);
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001251 }
1252
1253 /**
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +00001254 * Returns whether the shared/external storage media is a
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001255 * legacy view that includes files not owned by the app.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001256 * <p>
1257 * This value may be different from the value requested by
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001258 * {@code requestLegacyExternalStorage} in the app's manifest, since an app
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +00001259 * may inherit its legacy state based on when it was first installed, target sdk and other
1260 * factors.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001261 * <p>
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001262 * Non-legacy apps can continue to discover and read media belonging to
1263 * other apps via {@link android.provider.MediaStore}.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001264 *
1265 * @throws IllegalArgumentException if the path is not a valid storage
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +00001266 * device.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001267 */
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001268 public static boolean isExternalStorageLegacy(@NonNull File path) {
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001269 final Context context = AppGlobals.getInitialApplication();
Sudheer Shanka572fdfd2019-06-04 16:46:57 -07001270 final int uid = context.getApplicationInfo().uid;
1271 if (Process.isIsolated(uid)) {
1272 return false;
1273 }
1274
1275 final PackageManager packageManager = context.getPackageManager();
1276 if (packageManager.isInstantApp()) {
1277 return false;
1278 }
1279
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +00001280 // TODO(b/150672994): Compat flags do not override instant app and isolated process's
1281 // behavior.
1282 boolean defaultScopedStorage = Compatibility.isChangeEnabled(DEFAULT_SCOPED_STORAGE);
1283 boolean forceEnableScopedStorage = Compatibility.isChangeEnabled(
1284 FORCE_ENABLE_SCOPED_STORAGE);
1285 // if Scoped Storage is strictly enforced, the app does *not* have legacy storage access
1286 // Note: does not require packagename/uid as this is directly called from an app process
1287 if (isScopedStorageEnforced(defaultScopedStorage, forceEnableScopedStorage)) {
1288 return false;
1289 }
1290 // if Scoped Storage is strictly disabled, the app has legacy storage access
1291 // Note: does not require packagename/uid as this is directly called from an app process
1292 if (isScopedStorageDisabled(defaultScopedStorage, forceEnableScopedStorage)) {
Sudheer Shanka572fdfd2019-06-04 16:46:57 -07001293 return true;
1294 }
1295
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001296 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
Svet Ganovd563e932019-04-14 13:07:41 -07001297 return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
Sudheer Shanka572fdfd2019-06-04 16:46:57 -07001298 uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001299 }
1300
shafik81870652020-03-05 12:59:15 +00001301 /**
1302 * Returns whether the calling app has All Files Access on the primary shared/external storage
1303 * media.
1304 * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
1305 * enough to gain the access.
1306 * <p>To request access, use
1307 * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
1308 */
1309 public static boolean isExternalStorageManager() {
1310 final File externalDir = sCurrentUser.getExternalDirs()[0];
1311 return isExternalStorageManager(externalDir);
1312 }
1313
1314 /**
1315 * Returns whether the calling app has All Files Access at the given {@code path}
1316 * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
1317 * enough to gain the access.
1318 * <p>To request access, use
1319 * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
1320 */
1321 public static boolean isExternalStorageManager(@NonNull File path) {
1322 final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication());
1323 String packageName = Objects.requireNonNull(context.getPackageName());
1324 int uid = context.getApplicationInfo().uid;
1325
1326 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
1327 final int opMode =
1328 appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
1329
1330 switch (opMode) {
1331 case AppOpsManager.MODE_DEFAULT:
1332 return PackageManager.PERMISSION_GRANTED
1333 == context.checkPermission(
1334 Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid);
1335 case AppOpsManager.MODE_ALLOWED:
1336 return true;
1337 case AppOpsManager.MODE_ERRORED:
1338 case AppOpsManager.MODE_IGNORED:
1339 return false;
1340 default:
1341 throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
1342 }
1343 }
1344
Abhijeet Kaur3a6027c2020-03-01 13:21:16 +00001345 private static boolean isScopedStorageEnforced(boolean defaultScopedStorage,
1346 boolean forceEnableScopedStorage) {
1347 return defaultScopedStorage && forceEnableScopedStorage;
1348 }
1349
1350 private static boolean isScopedStorageDisabled(boolean defaultScopedStorage,
1351 boolean forceEnableScopedStorage) {
1352 return !defaultScopedStorage && !forceEnableScopedStorage;
1353 }
1354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 static File getDirectory(String variableName, String defaultPath) {
1356 String path = System.getenv(variableName);
1357 return path == null ? new File(defaultPath) : new File(path);
1358 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001359
Jeff Sharkey48749fc2013-04-19 13:25:04 -07001360 /** {@hide} */
1361 public static void setUserRequired(boolean userRequired) {
Andreas Gamped281b422016-07-08 03:50:27 +00001362 sUserRequired = userRequired;
Jeff Sharkey48749fc2013-04-19 13:25:04 -07001363 }
1364
1365 private static void throwIfUserRequired() {
Andreas Gamped281b422016-07-08 03:50:27 +00001366 if (sUserRequired) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -07001367 Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
1368 new Throwable());
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001369 }
1370 }
1371
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001372 /**
1373 * Append path segments to each given base path, returning result.
1374 *
1375 * @hide
1376 */
Andrei Onea24ec3212019-03-15 17:35:05 +00001377 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001378 public static File[] buildPaths(File[] base, String... segments) {
1379 File[] result = new File[base.length];
1380 for (int i = 0; i < base.length; i++) {
1381 result[i] = buildPath(base[i], segments);
1382 }
1383 return result;
1384 }
1385
1386 /**
1387 * Append path segments to given base path, returning result.
1388 *
1389 * @hide
1390 */
Philip P. Moltmannf80809f2018-04-04 11:20:44 -07001391 @TestApi
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001392 public static File buildPath(File base, String... segments) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001393 File cur = base;
1394 for (String segment : segments) {
1395 if (cur == null) {
1396 cur = new File(segment);
1397 } else {
1398 cur = new File(cur, segment);
1399 }
1400 }
1401 return cur;
1402 }
Jeff Sharkey63d0a062013-03-01 16:12:55 -08001403
1404 /**
1405 * If the given path exists on emulated external storage, return the
1406 * translated backing path hosted on internal storage. This bypasses any
1407 * emulation later, improving performance. This is <em>only</em> suitable
1408 * for read-only access.
1409 * <p>
1410 * Returns original path if given path doesn't meet these criteria. Callers
1411 * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
1412 * permission.
1413 *
Jeff Sharkey70eb34a2018-09-13 11:57:03 -06001414 * @deprecated disabled now that FUSE has been replaced by sdcardfs
Jeff Sharkey63d0a062013-03-01 16:12:55 -08001415 * @hide
1416 */
Andrei Onea24ec3212019-03-15 17:35:05 +00001417 @UnsupportedAppUsage
Jeff Sharkey70eb34a2018-09-13 11:57:03 -06001418 @Deprecated
Jeff Sharkey63d0a062013-03-01 16:12:55 -08001419 public static File maybeTranslateEmulatedPathToInternal(File path) {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001420 return StorageManager.maybeTranslateEmulatedPathToInternal(path);
Jeff Sharkey63d0a062013-03-01 16:12:55 -08001421 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422}