blob: 3462d1f56b6758628da7a7c6b8331e2e1dfcd24e [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;
Andrei Onea24ec3212019-03-15 17:35:05 +000023import android.annotation.UnsupportedAppUsage;
Jeff Sharkeybcff13c2019-03-28 14:29:35 -060024import android.app.AppGlobals;
25import android.app.AppOpsManager;
Jeff Sharkey4ca728c2014-01-10 16:27:19 -080026import android.app.admin.DevicePolicyManager;
Jeff Sharkey1abdb712013-08-11 16:28:14 -070027import android.content.Context;
Jeff Sharkey488162b2019-04-27 17:03:54 -060028import android.content.Intent;
Sudheer Shanka572fdfd2019-06-04 16:46:57 -070029import android.content.pm.PackageManager;
Jeff Sharkey48877892015-03-18 11:27:19 -070030import android.os.storage.StorageManager;
Mike Lockwood2f6a3882011-05-09 19:08:06 -070031import android.os.storage.StorageVolume;
Jeff Sharkey488162b2019-04-27 17:03:54 -060032import android.provider.MediaStore;
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -070033import android.text.TextUtils;
Kenny Rootb2278dc2011-01-18 13:03:28 -080034import android.util.Log;
San Mehat7fd0fee2009-12-17 07:12:23 -080035
Gilles Debunneee1d6302011-05-13 10:09:32 -070036import java.io.File;
Jeff Sharkey20356142017-12-06 15:22:05 -070037import java.util.LinkedList;
Gilles Debunneee1d6302011-05-13 10:09:32 -070038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039/**
40 * Provides access to environment variables.
41 */
42public class Environment {
Kenny Rootb2278dc2011-01-18 13:03:28 -080043 private static final String TAG = "Environment";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044
Jeff Sharkeydd02e332018-06-27 14:41:57 -060045 // NOTE: keep credential-protected paths in sync with StrictMode.java
46
Jeff Sharkeyb049e212012-09-07 23:16:01 -070047 private static final String ENV_EXTERNAL_STORAGE = "EXTERNAL_STORAGE";
Jeff Sharkey63d0a062013-03-01 16:12:55 -080048 private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
Jeff Sharkey48877892015-03-18 11:27:19 -070049 private static final String ENV_ANDROID_DATA = "ANDROID_DATA";
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -060050 private static final String ENV_ANDROID_EXPAND = "ANDROID_EXPAND";
Jeff Sharkey48877892015-03-18 11:27:19 -070051 private static final String ENV_ANDROID_STORAGE = "ANDROID_STORAGE";
Jeff Sharkey15447792015-11-05 16:18:51 -080052 private static final String ENV_DOWNLOAD_CACHE = "DOWNLOAD_CACHE";
Jeff Sharkey1be762c2014-03-06 09:56:23 -080053 private static final String ENV_OEM_ROOT = "OEM_ROOT";
Hung-ying Tyanbdc9d582015-11-20 11:53:39 +080054 private static final String ENV_ODM_ROOT = "ODM_ROOT";
Christopher Tate740888f2014-04-18 12:24:57 -070055 private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
Jaekyun Seok1713d9e2018-01-12 21:47:26 +090056 private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
Jeongik Cha9ec059a2019-07-04 21:12:06 +090057 private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT";
Jeff Sharkeyb049e212012-09-07 23:16:01 -070058
Jeff Sharkeydfa45302012-09-12 16:25:22 -070059 /** {@hide} */
Jeff Sharkey1abdb712013-08-11 16:28:14 -070060 public static final String DIR_ANDROID = "Android";
61 private static final String DIR_DATA = "data";
62 private static final String DIR_MEDIA = "media";
63 private static final String DIR_OBB = "obb";
64 private static final String DIR_FILES = "files";
65 private static final String DIR_CACHE = "cache";
66
67 /** {@hide} */
68 @Deprecated
69 public static final String DIRECTORY_ANDROID = DIR_ANDROID;
Jeff Sharkeydfa45302012-09-12 16:25:22 -070070
Jeff Sharkey63d0a062013-03-01 16:12:55 -080071 private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
Jeff Sharkey48877892015-03-18 11:27:19 -070072 private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -060073 private static final File DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, "/mnt/expand");
Jeff Sharkey48877892015-03-18 11:27:19 -070074 private static final File DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, "/storage");
Jeff Sharkey15447792015-11-05 16:18:51 -080075 private static final File DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, "/cache");
Jeff Sharkey1be762c2014-03-06 09:56:23 -080076 private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
Hung-ying Tyanbdc9d582015-11-20 11:53:39 +080077 private static final File DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, "/odm");
Christopher Tate740888f2014-04-18 12:24:57 -070078 private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
Jaekyun Seok1713d9e2018-01-12 21:47:26 +090079 private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
Jeongik Cha9ec059a2019-07-04 21:12:06 +090080 private static final File DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT,
81 "/system_ext");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082
Andrei Onea24ec3212019-03-15 17:35:05 +000083 @UnsupportedAppUsage
Andreas Gamped281b422016-07-08 03:50:27 +000084 private static UserEnvironment sCurrentUser;
85 private static boolean sUserRequired;
Kenny Roote1ff2142010-10-12 11:20:01 -070086
Andreas Gamped281b422016-07-08 03:50:27 +000087 static {
88 initForCurrentUser();
Jeff Sharkeyb049e212012-09-07 23:16:01 -070089 }
90
91 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +000092 @UnsupportedAppUsage
Andreas Gamped281b422016-07-08 03:50:27 +000093 public static void initForCurrentUser() {
94 final int userId = UserHandle.myUserId();
95 sCurrentUser = new UserEnvironment(userId);
Jeff Sharkeyb049e212012-09-07 23:16:01 -070096 }
97
98 /** {@hide} */
99 public static class UserEnvironment {
Jeff Sharkey48877892015-03-18 11:27:19 -0700100 private final int mUserId;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700101
Andrei Onea24ec3212019-03-15 17:35:05 +0000102 @UnsupportedAppUsage
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700103 public UserEnvironment(int userId) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700104 mUserId = userId;
105 }
Jeff Sharkey44cbdec2013-10-07 16:49:47 -0700106
Andrei Onea24ec3212019-03-15 17:35:05 +0000107 @UnsupportedAppUsage
Jeff Sharkey48877892015-03-18 11:27:19 -0700108 public File[] getExternalDirs() {
Jeff Sharkey46349872015-07-28 10:49:47 -0700109 final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId,
110 StorageManager.FLAG_FOR_WRITE);
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700111 final File[] files = new File[volumes.length];
Jeff Sharkey48877892015-03-18 11:27:19 -0700112 for (int i = 0; i < volumes.length; i++) {
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700113 files[i] = volumes[i].getPathFile();
Jeff Sharkey3fe5bf62012-09-18 15:54:52 -0700114 }
Jeff Sharkey1b8ef7e2015-04-03 17:14:45 -0700115 return files;
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700116 }
117
Andrei Onea24ec3212019-03-15 17:35:05 +0000118 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700119 @Deprecated
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700120 public File getExternalStorageDirectory() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700121 return getExternalDirs()[0];
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700122 }
123
Andrei Onea24ec3212019-03-15 17:35:05 +0000124 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700125 @Deprecated
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700126 public File getExternalStoragePublicDirectory(String type) {
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700127 return buildExternalStoragePublicDirs(type)[0];
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700128 }
129
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700130 public File[] buildExternalStoragePublicDirs(String type) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700131 return buildPaths(getExternalDirs(), type);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700132 }
133
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700134 public File[] buildExternalStorageAndroidDataDirs() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700135 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700136 }
137
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700138 public File[] buildExternalStorageAndroidObbDirs() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700139 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700140 }
141
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700142 public File[] buildExternalStorageAppDataDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700143 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName);
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700144 }
Jeff Sharkey3fe5bf62012-09-18 15:54:52 -0700145
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700146 public File[] buildExternalStorageAppMediaDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700147 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName);
Jeff Sharkey2ee3c1e2014-05-30 15:38:35 -0700148 }
149
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700150 public File[] buildExternalStorageAppObbDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700151 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName);
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700152 }
153
154 public File[] buildExternalStorageAppFilesDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700155 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700156 }
157
158 public File[] buildExternalStorageAppCacheDirs(String packageName) {
Jeff Sharkey48877892015-03-18 11:27:19 -0700159 return buildPaths(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);
Jeff Sharkey3fe5bf62012-09-18 15:54:52 -0700160 }
Mike Lockwood2f6a3882011-05-09 19:08:06 -0700161 }
San Mehat7fd0fee2009-12-17 07:12:23 -0800162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 /**
Jeff Sharkey1be762c2014-03-06 09:56:23 -0800164 * Return root of the "system" partition holding the core Android OS.
165 * Always present and mounted read-only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 */
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700167 public static @NonNull File getRootDirectory() {
Jeff Sharkey63d0a062013-03-01 16:12:55 -0800168 return DIR_ANDROID_ROOT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 }
170
Jeff Sharkey48877892015-03-18 11:27:19 -0700171 /** {@hide} */
Jeff Sharkeyc6091162018-06-29 17:15:40 -0600172 @TestApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700173 public static @NonNull File getStorageDirectory() {
Jeff Sharkey48877892015-03-18 11:27:19 -0700174 return DIR_ANDROID_STORAGE;
175 }
176
Jason parksa3cdaa52011-01-13 14:15:43 -0600177 /**
Jeff Sharkey1be762c2014-03-06 09:56:23 -0800178 * Return root directory of the "oem" partition holding OEM customizations,
179 * if any. If present, the partition is mounted read-only.
180 *
181 * @hide
182 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600183 @SystemApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700184 public static @NonNull File getOemDirectory() {
Jeff Sharkey1be762c2014-03-06 09:56:23 -0800185 return DIR_OEM_ROOT;
186 }
187
188 /**
Hung-ying Tyanbdc9d582015-11-20 11:53:39 +0800189 * Return root directory of the "odm" partition holding ODM customizations,
190 * if any. If present, the partition is mounted read-only.
191 *
192 * @hide
193 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600194 @SystemApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700195 public static @NonNull File getOdmDirectory() {
Hung-ying Tyanbdc9d582015-11-20 11:53:39 +0800196 return DIR_ODM_ROOT;
197 }
198
199 /**
Christopher Tate740888f2014-04-18 12:24:57 -0700200 * Return root directory of the "vendor" partition that holds vendor-provided
201 * software that should persist across simple reflashing of the "system" partition.
202 * @hide
203 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600204 @SystemApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700205 public static @NonNull File getVendorDirectory() {
Christopher Tate740888f2014-04-18 12:24:57 -0700206 return DIR_VENDOR_ROOT;
207 }
208
Jason parksa3cdaa52011-01-13 14:15:43 -0600209 /**
Jaekyun Seok1713d9e2018-01-12 21:47:26 +0900210 * Return root directory of the "product" partition holding product-specific
211 * customizations if any. If present, the partition is mounted read-only.
212 *
213 * @hide
214 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600215 @SystemApi
Anton Hansson09e47be2018-11-08 12:56:18 +0000216 @TestApi
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700217 public static @NonNull File getProductDirectory() {
Jaekyun Seok1713d9e2018-01-12 21:47:26 +0900218 return DIR_PRODUCT_ROOT;
219 }
220
221 /**
Dario Freni2bef1762018-06-01 14:02:08 +0100222 * Return root directory of the "product_services" partition holding middleware
223 * services if any. If present, the partition is mounted read-only.
224 *
Jeongik Cha9ec059a2019-07-04 21:12:06 +0900225 * @deprecated This directory is not guaranteed to exist.
226 * Its name is changed to "system_ext" because the partition's purpose is changed.
227 * {@link #getSystemExtDirectory()}
Dario Freni2bef1762018-06-01 14:02:08 +0100228 * @hide
229 */
Jeff Sharkey70eb34a2018-09-13 11:57:03 -0600230 @SystemApi
Jeongik Cha9ec059a2019-07-04 21:12:06 +0900231 @Deprecated
Jeff Sharkeya30e5c32019-02-28 12:02:10 -0700232 public static @NonNull File getProductServicesDirectory() {
Jeongik Cha9ec059a2019-07-04 21:12:06 +0900233 return getDirectory("PRODUCT_SERVICES_ROOT", "/product_services");
234 }
235
236 /**
237 * Return root directory of the "system_ext" partition holding system partition's extension
238 * If present, the partition is mounted read-only.
239 *
240 * @hide
241 */
242 @SystemApi
243 public static @NonNull File getSystemExtDirectory() {
244 return DIR_SYSTEM_EXT_ROOT;
Dario Freni2bef1762018-06-01 14:02:08 +0100245 }
246
247 /**
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700248 * Return the system directory for a user. This is for use by system
249 * services to store files relating to the user. This directory will be
250 * automatically deleted when the user is removed.
Amith Yamasani61f57372012-08-31 12:12:28 -0700251 *
Jeff Sharkey3a6a61e2018-10-03 10:45:51 -0600252 * @deprecated This directory is valid and still exists, but but callers
253 * should <em>strongly</em> consider switching to using either
254 * {@link #getDataSystemCeDirectory(int)} or
255 * {@link #getDataSystemDeDirectory(int)}, both of which support
256 * fast user wipe.
Amith Yamasani61f57372012-08-31 12:12:28 -0700257 * @hide
258 */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700259 @Deprecated
Amith Yamasani61f57372012-08-31 12:12:28 -0700260 public static File getUserSystemDirectory(int userId) {
Jeff Sharkey15447792015-11-05 16:18:51 -0800261 return new File(new File(getDataSystemDirectory(), "users"), Integer.toString(userId));
Amith Yamasani61f57372012-08-31 12:12:28 -0700262 }
263
264 /**
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700265 * Returns the config directory for a user. This is for use by system
266 * services to store files relating to the user which should be readable by
267 * any app running as that user.
Robin Lee69591332014-04-28 16:03:22 +0100268 *
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700269 * @deprecated This directory is valid and still exists, but callers should
270 * <em>strongly</em> consider switching to
271 * {@link #getDataMiscCeDirectory(int)} which is protected with
272 * user credentials or {@link #getDataMiscDeDirectory(int)}
273 * which supports fast user wipe.
Robin Lee69591332014-04-28 16:03:22 +0100274 * @hide
275 */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700276 @Deprecated
Robin Lee69591332014-04-28 16:03:22 +0100277 public static File getUserConfigDirectory(int userId) {
278 return new File(new File(new File(
279 getDataDirectory(), "misc"), "user"), Integer.toString(userId));
280 }
281
282 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700283 * Return the user data directory.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 */
285 public static File getDataDirectory() {
Jeff Sharkey15447792015-11-05 16:18:51 -0800286 return DIR_ANDROID_DATA;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 }
288
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -0700289 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700290 public static File getDataDirectory(String volumeUuid) {
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -0700291 if (TextUtils.isEmpty(volumeUuid)) {
Jeff Sharkey15447792015-11-05 16:18:51 -0800292 return DIR_ANDROID_DATA;
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -0700293 } else {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700294 return new File("/mnt/expand/" + volumeUuid);
Jeff Sharkeybd0e9e42015-04-30 16:04:50 -0700295 }
296 }
297
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700298 /** {@hide} */
Jeff Sharkeycf3f0a12016-03-17 19:57:58 -0600299 public static File getExpandDirectory() {
300 return DIR_ANDROID_EXPAND;
301 }
302
303 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000304 @UnsupportedAppUsage
Jeff Sharkey15447792015-11-05 16:18:51 -0800305 public static File getDataSystemDirectory() {
306 return new File(getDataDirectory(), "system");
307 }
308
Amith Yamasanid04aaa32016-06-13 12:09:36 -0700309 /**
310 * Returns the base directory for per-user system directory, device encrypted.
311 * {@hide}
312 */
313 public static File getDataSystemDeDirectory() {
314 return buildPath(getDataDirectory(), "system_de");
315 }
316
317 /**
318 * Returns the base directory for per-user system directory, credential encrypted.
319 * {@hide}
320 */
321 public static File getDataSystemCeDirectory() {
322 return buildPath(getDataDirectory(), "system_ce");
323 }
324
Jeff Sharkey3a6a61e2018-10-03 10:45:51 -0600325 /**
326 * Return the "credential encrypted" system directory for a user. This is
327 * for use by system services to store files relating to the user. This
328 * directory supports fast user wipe, and will be automatically deleted when
329 * the user is removed.
330 * <p>
331 * Data stored under this path is "credential encrypted", which uses an
332 * encryption key that is entangled with user credentials, such as a PIN or
333 * password. The contents will only be available once the user has been
334 * unlocked, as reported by {@code SystemService.onUnlockUser()}.
335 * <p>
336 * New code should <em>strongly</em> prefer storing sensitive data in these
337 * credential encrypted areas.
338 *
339 * @hide
340 */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700341 public static File getDataSystemCeDirectory(int userId) {
342 return buildPath(getDataDirectory(), "system_ce", String.valueOf(userId));
Jeff Sharkey15447792015-11-05 16:18:51 -0800343 }
344
Jeff Sharkey3a6a61e2018-10-03 10:45:51 -0600345 /**
346 * Return the "device encrypted" system directory for a user. This is for
347 * use by system services to store files relating to the user. This
348 * directory supports fast user wipe, and will be automatically deleted when
349 * the user is removed.
350 * <p>
351 * Data stored under this path is "device encrypted", which uses an
352 * encryption key that is tied to the physical device. The contents will
353 * only be available once the device has finished a {@code dm-verity}
354 * protected boot.
355 * <p>
356 * New code should <em>strongly</em> avoid storing sensitive data in these
357 * device encrypted areas.
358 *
359 * @hide
360 */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700361 public static File getDataSystemDeDirectory(int userId) {
362 return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
363 }
364
365 /** {@hide} */
366 public static File getDataMiscDirectory() {
367 return new File(getDataDirectory(), "misc");
368 }
369
370 /** {@hide} */
Amith Yamasania2807132017-01-26 12:35:14 -0800371 public static File getDataMiscCeDirectory() {
372 return buildPath(getDataDirectory(), "misc_ce");
373 }
374
375 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700376 public static File getDataMiscCeDirectory(int userId) {
377 return buildPath(getDataDirectory(), "misc_ce", String.valueOf(userId));
378 }
379
380 /** {@hide} */
381 public static File getDataMiscDeDirectory(int userId) {
382 return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
Jeff Sharkey15447792015-11-05 16:18:51 -0800383 }
384
Calin Juravled479b522016-02-24 16:22:03 +0000385 private static File getDataProfilesDeDirectory(int userId) {
386 return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
387 }
388
389 /** {@hide} */
Andreas Huber7fe20532018-01-22 11:26:44 -0800390 public static File getDataVendorCeDirectory(int userId) {
391 return buildPath(getDataDirectory(), "vendor_ce", String.valueOf(userId));
392 }
393
394 /** {@hide} */
395 public static File getDataVendorDeDirectory(int userId) {
396 return buildPath(getDataDirectory(), "vendor_de", String.valueOf(userId));
397 }
398
399 /** {@hide} */
Calin Juravle6ae39fc2018-01-19 20:32:47 -0800400 public static File getDataRefProfilesDePackageDirectory(String packageName) {
401 return buildPath(getDataDirectory(), "misc", "profiles", "ref", packageName);
Calin Juravle0bd77622016-07-12 15:56:41 +0100402 }
403
404 /** {@hide} */
Calin Juravled479b522016-02-24 16:22:03 +0000405 public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
406 return buildPath(getDataProfilesDeDirectory(userId), packageName);
407 }
408
409 /** {@hide} */
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700410 public static File getDataAppDirectory(String volumeUuid) {
411 return new File(getDataDirectory(volumeUuid), "app");
412 }
413
414 /** {@hide} */
Dario Frenia8f4b132018-12-30 00:36:49 +0000415 public static File getDataStagingDirectory(String volumeUuid) {
Gavin Corkery296c8b92019-02-27 12:06:24 +0000416 return new File(getDataDirectory(volumeUuid), "app-staging");
Dario Frenia8f4b132018-12-30 00:36:49 +0000417 }
418
419 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700420 public static File getDataUserCeDirectory(String volumeUuid) {
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700421 return new File(getDataDirectory(volumeUuid), "user");
422 }
423
424 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700425 public static File getDataUserCeDirectory(String volumeUuid, int userId) {
426 return new File(getDataUserCeDirectory(volumeUuid), String.valueOf(userId));
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700427 }
428
429 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700430 public static File getDataUserCePackageDirectory(String volumeUuid, int userId,
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700431 String packageName) {
432 // TODO: keep consistent with installd
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700433 return new File(getDataUserCeDirectory(volumeUuid, userId), packageName);
Jeff Sharkey15447792015-11-05 16:18:51 -0800434 }
435
436 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700437 public static File getDataUserDeDirectory(String volumeUuid) {
Jeff Sharkey15447792015-11-05 16:18:51 -0800438 return new File(getDataDirectory(volumeUuid), "user_de");
439 }
440
441 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700442 public static File getDataUserDeDirectory(String volumeUuid, int userId) {
443 return new File(getDataUserDeDirectory(volumeUuid), String.valueOf(userId));
Jeff Sharkey15447792015-11-05 16:18:51 -0800444 }
445
446 /** {@hide} */
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700447 public static File getDataUserDePackageDirectory(String volumeUuid, int userId,
Jeff Sharkey15447792015-11-05 16:18:51 -0800448 String packageName) {
449 // TODO: keep consistent with installd
Jeff Sharkey8212ae02016-02-10 14:46:43 -0700450 return new File(getDataUserDeDirectory(volumeUuid, userId), packageName);
Jeff Sharkey6dce4962015-07-03 18:08:41 -0700451 }
452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 /**
Fyodor Kupolov88257582016-05-24 16:06:56 -0700454 * Return preloads directory.
455 * <p>This directory may contain pre-loaded content such as
456 * {@link #getDataPreloadsDemoDirectory() demo videos} and
457 * {@link #getDataPreloadsAppsDirectory() APK files} .
458 * {@hide}
459 */
460 public static File getDataPreloadsDirectory() {
461 return new File(getDataDirectory(), "preloads");
462 }
463
464 /**
465 * @see #getDataPreloadsDirectory()
466 * {@hide}
467 */
468 public static File getDataPreloadsDemoDirectory() {
469 return new File(getDataPreloadsDirectory(), "demo");
470 }
471
472 /**
473 * @see #getDataPreloadsDirectory()
474 * {@hide}
475 */
476 public static File getDataPreloadsAppsDirectory() {
477 return new File(getDataPreloadsDirectory(), "apps");
478 }
479
480 /**
Fyodor Kupolov19551a82016-08-22 14:46:08 -0700481 * @see #getDataPreloadsDirectory()
482 * {@hide}
483 */
484 public static File getDataPreloadsMediaDirectory() {
485 return new File(getDataPreloadsDirectory(), "media");
486 }
487
488 /**
Fyodor Kupolov6e687062016-09-09 17:42:12 -0700489 * Returns location of preloaded cache directory for package name
490 * @see #getDataPreloadsDirectory()
491 * {@hide}
492 */
493 public static File getDataPreloadsFileCacheDirectory(String packageName) {
494 return new File(getDataPreloadsFileCacheDirectory(), packageName);
495 }
496
497 /**
498 * Returns location of preloaded cache directory.
499 * @see #getDataPreloadsDirectory()
500 * {@hide}
501 */
502 public static File getDataPreloadsFileCacheDirectory() {
503 return new File(getDataPreloadsDirectory(), "file_cache");
504 }
505
506 /**
Sudheer Shankabe0febe2018-11-07 18:24:37 -0800507 * Returns location of packages cache directory.
508 * {@hide}
509 */
510 public static File getPackageCacheDirectory() {
511 return new File(getDataSystemDirectory(), "package_cache");
512 }
513
514 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700515 * Return the primary shared/external storage directory. This directory may
516 * not currently be accessible if it has been mounted by the user on their
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800517 * computer, has been removed from the device, or some other problem has
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700518 * happened. You can determine its current state with
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800519 * {@link #getExternalStorageState()}.
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700520 * <p>
521 * <em>Note: don't be confused by the word "external" here. This directory
522 * can better be thought as media/shared storage. It is a filesystem that
523 * can hold a relatively large amount of data and that is shared across all
524 * applications (does not enforce permissions). Traditionally this is an SD
525 * card, but it may also be implemented as built-in storage in a device that
526 * is distinct from the protected internal storage and can be mounted as a
527 * filesystem on a computer.</em>
528 * <p>
529 * On devices with multiple users (as described by {@link UserManager}),
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700530 * each user has their own isolated shared storage. Applications only have
531 * access to the shared storage for the user they're running as.
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700532 * <p>
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700533 * In devices with multiple shared/external storage directories, this
534 * directory represents the primary storage that the user will interact
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700535 * with. Access to secondary storage is available through
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700536 * {@link Context#getExternalFilesDirs(String)},
537 * {@link Context#getExternalCacheDirs()}, and
538 * {@link Context#getExternalMediaDirs()}.
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700539 * <p>
540 * Applications should not directly use this top-level directory, in order
541 * to avoid polluting the user's root namespace. Any files that are private
542 * to the application should be placed in a directory returned by
543 * {@link android.content.Context#getExternalFilesDir
Dianne Hackbornacaf0282010-03-30 14:39:35 -0700544 * Context.getExternalFilesDir}, which the system will take care of deleting
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700545 * if the application is uninstalled. Other shared files should be placed in
546 * one of the directories returned by
547 * {@link #getExternalStoragePublicDirectory}.
548 * <p>
549 * Writing to this path requires the
550 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission,
Jeff Sharkey488162b2019-04-27 17:03:54 -0600551 * and starting in {@link android.os.Build.VERSION_CODES#KITKAT}, read
552 * access requires the
Jeff Sharkey8c165792012-10-22 14:08:29 -0700553 * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700554 * which is automatically granted if you hold the write permission.
555 * <p>
Chet Haasee8222dd2013-09-05 07:44:18 -0700556 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, if your
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700557 * application only needs to store internal data, consider using
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700558 * {@link Context#getExternalFilesDir(String)},
559 * {@link Context#getExternalCacheDir()}, or
560 * {@link Context#getExternalMediaDirs()}, which require no permissions to
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700561 * read or write.
562 * <p>
563 * This path may change between platform versions, so applications should
564 * only persist relative paths.
565 * <p>
566 * Here is an example of typical code to monitor the state of external
567 * storage:
568 * <p>
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700569 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800570 * monitor_storage}
Dianne Hackborn407f6252010-10-04 11:31:17 -0700571 *
572 * @see #getExternalStorageState()
573 * @see #isExternalStorageRemovable()
Jeff Sharkey488162b2019-04-27 17:03:54 -0600574 * @deprecated To improve user privacy, direct access to shared/external
575 * storage devices is deprecated. When an app targets
576 * {@link android.os.Build.VERSION_CODES#Q}, the path returned
577 * from this method is no longer directly accessible to apps.
578 * Apps can continue to access content stored on shared/external
579 * storage by migrating to alternatives such as
580 * {@link Context#getExternalFilesDir(String)},
581 * {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 */
Jeff Sharkey488162b2019-04-27 17:03:54 -0600583 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 public static File getExternalStorageDirectory() {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700585 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000586 return sCurrentUser.getExternalDirs()[0];
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700587 }
588
589 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000590 @UnsupportedAppUsage
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700591 public static File getLegacyExternalStorageDirectory() {
592 return new File(System.getenv(ENV_EXTERNAL_STORAGE));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 }
594
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700595 /** {@hide} */
Andrei Onea24ec3212019-03-15 17:35:05 +0000596 @UnsupportedAppUsage
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700597 public static File getLegacyExternalStorageObbDirectory() {
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700598 return buildPath(getLegacyExternalStorageDirectory(), DIR_ANDROID, DIR_OBB);
Jeff Sharkey4fbbda42012-09-24 18:34:07 -0700599 }
600
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 /**
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800602 * Standard directory in which to place any audio files that should be
603 * in the regular list of music for the user.
604 * This may be combined with
605 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
606 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
607 * of directories to categories a particular audio file as more than one
608 * type.
609 */
610 public static String DIRECTORY_MUSIC = "Music";
Felipe Lemec7b1f892016-01-15 15:02:31 -0800611
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800612 /**
613 * Standard directory in which to place any audio files that should be
614 * in the list of podcasts that the user can select (not as regular
615 * music).
616 * This may be combined with {@link #DIRECTORY_MUSIC},
617 * {@link #DIRECTORY_NOTIFICATIONS},
618 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
619 * of directories to categories a particular audio file as more than one
620 * type.
621 */
622 public static String DIRECTORY_PODCASTS = "Podcasts";
Felipe Lemeb012f912016-01-22 16:49:55 -0800623
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800624 /**
625 * Standard directory in which to place any audio files that should be
626 * in the list of ringtones that the user can select (not as regular
627 * music).
628 * This may be combined with {@link #DIRECTORY_MUSIC},
629 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS}, and
630 * {@link #DIRECTORY_ALARMS} as a series
631 * of directories to categories a particular audio file as more than one
632 * type.
633 */
634 public static String DIRECTORY_RINGTONES = "Ringtones";
Felipe Lemeb012f912016-01-22 16:49:55 -0800635
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800636 /**
637 * Standard directory in which to place any audio files that should be
638 * in the list of alarms that the user can select (not as regular
639 * music).
640 * This may be combined with {@link #DIRECTORY_MUSIC},
641 * {@link #DIRECTORY_PODCASTS}, {@link #DIRECTORY_NOTIFICATIONS},
642 * and {@link #DIRECTORY_RINGTONES} as a series
643 * of directories to categories a particular audio file as more than one
644 * type.
645 */
646 public static String DIRECTORY_ALARMS = "Alarms";
Felipe Lemeb012f912016-01-22 16:49:55 -0800647
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800648 /**
649 * Standard directory in which to place any audio files that should be
650 * in the list of notifications that the user can select (not as regular
651 * music).
652 * This may be combined with {@link #DIRECTORY_MUSIC},
653 * {@link #DIRECTORY_PODCASTS},
654 * {@link #DIRECTORY_ALARMS}, and {@link #DIRECTORY_RINGTONES} as a series
655 * of directories to categories a particular audio file as more than one
656 * type.
657 */
658 public static String DIRECTORY_NOTIFICATIONS = "Notifications";
Felipe Lemeb012f912016-01-22 16:49:55 -0800659
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800660 /**
661 * Standard directory in which to place pictures that are available to
662 * the user. Note that this is primarily a convention for the top-level
663 * public directory, as the media scanner will find and collect pictures
664 * in any directory.
665 */
666 public static String DIRECTORY_PICTURES = "Pictures";
Felipe Lemeb012f912016-01-22 16:49:55 -0800667
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800668 /**
669 * Standard directory in which to place movies that are available to
670 * the user. Note that this is primarily a convention for the top-level
671 * public directory, as the media scanner will find and collect movies
672 * in any directory.
673 */
674 public static String DIRECTORY_MOVIES = "Movies";
Felipe Lemeb012f912016-01-22 16:49:55 -0800675
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800676 /**
677 * Standard directory in which to place files that have been downloaded by
678 * the user. Note that this is primarily a convention for the top-level
679 * public directory, you are free to download files anywhere in your own
Dianne Hackbornce59fb82010-04-07 17:19:04 -0700680 * private directories. Also note that though the constant here is
681 * named DIRECTORY_DOWNLOADS (plural), the actual file name is non-plural for
682 * backwards compatibility reasons.
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800683 */
Dianne Hackbornce59fb82010-04-07 17:19:04 -0700684 public static String DIRECTORY_DOWNLOADS = "Download";
Felipe Lemeb012f912016-01-22 16:49:55 -0800685
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800686 /**
687 * The traditional location for pictures and videos when mounting the
688 * device as a camera. Note that this is primarily a convention for the
689 * top-level public directory, as this convention makes no sense elsewhere.
690 */
691 public static String DIRECTORY_DCIM = "DCIM";
Jeff Sharkey3e1189b2013-09-12 21:59:06 -0700692
693 /**
694 * Standard directory in which to place documents that have been created by
695 * the user.
696 */
697 public static String DIRECTORY_DOCUMENTS = "Documents";
698
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800699 /**
Jeff Sharkeyc8e49242018-11-02 14:34:44 -0600700 * Standard directory in which to place screenshots that have been taken by
701 * the user. Typically used as a secondary directory under
702 * {@link #DIRECTORY_PICTURES}.
703 */
704 public static String DIRECTORY_SCREENSHOTS = "Screenshots";
705
706 /**
Jeff Sharkey10887d52018-11-30 13:44:41 -0700707 * Standard directory in which to place any audio files which are
708 * audiobooks.
709 */
710 public static String DIRECTORY_AUDIOBOOKS = "Audiobooks";
711
712 /**
Felipe Lemec7b1f892016-01-15 15:02:31 -0800713 * List of standard storage directories.
714 * <p>
715 * Each of its values have its own constant:
716 * <ul>
717 * <li>{@link #DIRECTORY_MUSIC}
718 * <li>{@link #DIRECTORY_PODCASTS}
719 * <li>{@link #DIRECTORY_ALARMS}
720 * <li>{@link #DIRECTORY_RINGTONES}
721 * <li>{@link #DIRECTORY_NOTIFICATIONS}
722 * <li>{@link #DIRECTORY_PICTURES}
723 * <li>{@link #DIRECTORY_MOVIES}
724 * <li>{@link #DIRECTORY_DOWNLOADS}
725 * <li>{@link #DIRECTORY_DCIM}
726 * <li>{@link #DIRECTORY_DOCUMENTS}
Jeff Sharkey10887d52018-11-30 13:44:41 -0700727 * <li>{@link #DIRECTORY_AUDIOBOOKS}
Felipe Lemec7b1f892016-01-15 15:02:31 -0800728 * </ul>
729 * @hide
730 */
Felipe Leme3e166b22016-02-24 10:17:41 -0800731 public static final String[] STANDARD_DIRECTORIES = {
Felipe Lemec7b1f892016-01-15 15:02:31 -0800732 DIRECTORY_MUSIC,
733 DIRECTORY_PODCASTS,
734 DIRECTORY_RINGTONES,
735 DIRECTORY_ALARMS,
736 DIRECTORY_NOTIFICATIONS,
737 DIRECTORY_PICTURES,
738 DIRECTORY_MOVIES,
739 DIRECTORY_DOWNLOADS,
740 DIRECTORY_DCIM,
Jeff Sharkey10887d52018-11-30 13:44:41 -0700741 DIRECTORY_DOCUMENTS,
742 DIRECTORY_AUDIOBOOKS,
Felipe Lemec7b1f892016-01-15 15:02:31 -0800743 };
744
745 /**
Felipe Lemeb012f912016-01-22 16:49:55 -0800746 * @hide
747 */
748 public static boolean isStandardDirectory(String dir) {
749 for (String valid : STANDARD_DIRECTORIES) {
750 if (valid.equals(dir)) {
751 return true;
752 }
753 }
754 return false;
755 }
756
Jeff Sharkey20356142017-12-06 15:22:05 -0700757 /** {@hide} */ public static final int HAS_MUSIC = 1 << 0;
758 /** {@hide} */ public static final int HAS_PODCASTS = 1 << 1;
759 /** {@hide} */ public static final int HAS_RINGTONES = 1 << 2;
760 /** {@hide} */ public static final int HAS_ALARMS = 1 << 3;
761 /** {@hide} */ public static final int HAS_NOTIFICATIONS = 1 << 4;
762 /** {@hide} */ public static final int HAS_PICTURES = 1 << 5;
763 /** {@hide} */ public static final int HAS_MOVIES = 1 << 6;
764 /** {@hide} */ public static final int HAS_DOWNLOADS = 1 << 7;
765 /** {@hide} */ public static final int HAS_DCIM = 1 << 8;
766 /** {@hide} */ public static final int HAS_DOCUMENTS = 1 << 9;
Jeff Sharkey10887d52018-11-30 13:44:41 -0700767 /** {@hide} */ public static final int HAS_AUDIOBOOKS = 1 << 10;
Jeff Sharkey20356142017-12-06 15:22:05 -0700768
769 /** {@hide} */ public static final int HAS_ANDROID = 1 << 16;
770 /** {@hide} */ public static final int HAS_OTHER = 1 << 17;
771
772 /**
773 * Classify the content types present on the given external storage device.
774 * <p>
775 * This is typically useful for deciding if an inserted SD card is empty, or
776 * if it contains content like photos that should be preserved.
777 *
778 * @hide
779 */
780 public static int classifyExternalStorageDirectory(File dir) {
781 int res = 0;
782 for (File f : FileUtils.listFilesOrEmpty(dir)) {
783 if (f.isFile() && isInterestingFile(f)) {
784 res |= HAS_OTHER;
785 } else if (f.isDirectory() && hasInterestingFiles(f)) {
786 final String name = f.getName();
787 if (DIRECTORY_MUSIC.equals(name)) res |= HAS_MUSIC;
788 else if (DIRECTORY_PODCASTS.equals(name)) res |= HAS_PODCASTS;
789 else if (DIRECTORY_RINGTONES.equals(name)) res |= HAS_RINGTONES;
790 else if (DIRECTORY_ALARMS.equals(name)) res |= HAS_ALARMS;
791 else if (DIRECTORY_NOTIFICATIONS.equals(name)) res |= HAS_NOTIFICATIONS;
792 else if (DIRECTORY_PICTURES.equals(name)) res |= HAS_PICTURES;
793 else if (DIRECTORY_MOVIES.equals(name)) res |= HAS_MOVIES;
794 else if (DIRECTORY_DOWNLOADS.equals(name)) res |= HAS_DOWNLOADS;
795 else if (DIRECTORY_DCIM.equals(name)) res |= HAS_DCIM;
796 else if (DIRECTORY_DOCUMENTS.equals(name)) res |= HAS_DOCUMENTS;
Jeff Sharkey10887d52018-11-30 13:44:41 -0700797 else if (DIRECTORY_AUDIOBOOKS.equals(name)) res |= HAS_AUDIOBOOKS;
Jeff Sharkey20356142017-12-06 15:22:05 -0700798 else if (DIRECTORY_ANDROID.equals(name)) res |= HAS_ANDROID;
799 else res |= HAS_OTHER;
800 }
801 }
802 return res;
803 }
804
805 private static boolean hasInterestingFiles(File dir) {
806 final LinkedList<File> explore = new LinkedList<>();
807 explore.add(dir);
808 while (!explore.isEmpty()) {
809 dir = explore.pop();
810 for (File f : FileUtils.listFilesOrEmpty(dir)) {
811 if (isInterestingFile(f)) return true;
812 if (f.isDirectory()) explore.add(f);
813 }
814 }
815 return false;
816 }
817
818 private static boolean isInterestingFile(File file) {
819 if (file.isFile()) {
820 final String name = file.getName().toLowerCase();
821 if (name.endsWith(".exe") || name.equals("autorun.inf")
822 || name.equals("launchpad.zip") || name.equals(".nomedia")) {
823 return false;
824 } else {
825 return true;
826 }
827 } else {
828 return false;
829 }
830 }
831
Felipe Lemeb012f912016-01-22 16:49:55 -0800832 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700833 * Get a top-level shared/external storage directory for placing files of a
834 * particular type. This is where the user will typically place and manage
835 * their own files, so you should be careful about what you put here to
836 * ensure you don't erase their files or get in the way of their own
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800837 * organization.
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700838 * <p>
839 * On devices with multiple users (as described by {@link UserManager}),
840 * each user has their own isolated shared storage. Applications only have
841 * access to the shared storage for the user they're running as.
842 * </p>
843 * <p>
844 * Here is an example of typical code to manipulate a picture on the public
845 * shared storage:
846 * </p>
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800847 * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java
848 * public_picture}
Felipe Lemec7b1f892016-01-15 15:02:31 -0800849 *
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700850 * @param type The type of storage directory to return. Should be one of
851 * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
852 * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
853 * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
Felipe Lemec7b1f892016-01-15 15:02:31 -0800854 * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS},
855 * {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null.
Jeff Sharkey59d28dc82015-10-14 13:56:23 -0700856 * @return Returns the File path for the directory. Note that this directory
857 * may not yet exist, so you must make sure it exists before using
858 * it such as with {@link File#mkdirs File.mkdirs()}.
Jeff Sharkey488162b2019-04-27 17:03:54 -0600859 * @deprecated To improve user privacy, direct access to shared/external
860 * storage devices is deprecated. When an app targets
861 * {@link android.os.Build.VERSION_CODES#Q}, the path returned
862 * from this method is no longer directly accessible to apps.
863 * Apps can continue to access content stored on shared/external
864 * storage by migrating to alternatives such as
865 * {@link Context#getExternalFilesDir(String)},
866 * {@link MediaStore}, or {@link Intent#ACTION_OPEN_DOCUMENT}.
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800867 */
Jeff Sharkey488162b2019-04-27 17:03:54 -0600868 @Deprecated
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800869 public static File getExternalStoragePublicDirectory(String type) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700870 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000871 return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800872 }
873
874 /**
875 * Returns the path for android-specific data on the SD card.
876 * @hide
877 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000878 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700879 public static File[] buildExternalStorageAndroidDataDirs() {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700880 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000881 return sCurrentUser.buildExternalStorageAndroidDataDirs();
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800882 }
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700883
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800884 /**
885 * Generates the raw path to an application's data
886 * @hide
887 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000888 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700889 public static File[] buildExternalStorageAppDataDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700890 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000891 return sCurrentUser.buildExternalStorageAppDataDirs(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800892 }
Felipe Lemeb012f912016-01-22 16:49:55 -0800893
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800894 /**
895 * Generates the raw path to an application's media
896 * @hide
897 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000898 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700899 public static File[] buildExternalStorageAppMediaDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700900 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000901 return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800902 }
Felipe Lemeb012f912016-01-22 16:49:55 -0800903
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800904 /**
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800905 * Generates the raw path to an application's OBB files
906 * @hide
907 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000908 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700909 public static File[] buildExternalStorageAppObbDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700910 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000911 return sCurrentUser.buildExternalStorageAppObbDirs(packageName);
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800912 }
Felipe Lemeb012f912016-01-22 16:49:55 -0800913
Dianne Hackborn805fd7e2011-01-16 18:30:29 -0800914 /**
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800915 * Generates the path to an application's files.
916 * @hide
917 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000918 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700919 public static File[] buildExternalStorageAppFilesDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700920 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000921 return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800922 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -0700923
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800924 /**
925 * Generates the path to an application's cache.
926 * @hide
927 */
Andrei Onea24ec3212019-03-15 17:35:05 +0000928 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700929 public static File[] buildExternalStorageAppCacheDirs(String packageName) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -0700930 throwIfUserRequired();
Andreas Gamped281b422016-07-08 03:50:27 +0000931 return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800932 }
Felipe Lemeb012f912016-01-22 16:49:55 -0800933
Sudheer Shanka25f1c6e2019-04-22 17:03:47 -0700934 /** @hide */
935 public static File[] buildExternalStoragePublicDirs(@NonNull String dirType) {
936 throwIfUserRequired();
937 return sCurrentUser.buildExternalStoragePublicDirs(dirType);
938 }
939
Dianne Hackborne83cefce2010-02-04 17:38:14 -0800940 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700941 * Return the download/cache content directory.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 */
943 public static File getDownloadCacheDirectory() {
Jeff Sharkey15447792015-11-05 16:18:51 -0800944 return DIR_DOWNLOAD_CACHE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 }
946
947 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700948 * Unknown storage state, such as when a path isn't backed by known storage
949 * media.
950 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -0800951 * @see #getExternalStorageState(File)
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700952 */
953 public static final String MEDIA_UNKNOWN = "unknown";
954
955 /**
956 * Storage state if the media is not present.
957 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -0800958 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 */
960 public static final String MEDIA_REMOVED = "removed";
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700963 * Storage state if the media is present but not mounted.
964 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -0800965 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800966 */
967 public static final String MEDIA_UNMOUNTED = "unmounted";
968
969 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700970 * Storage state if the media is present and being disk-checked.
971 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -0800972 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 */
974 public static final String MEDIA_CHECKING = "checking";
975
976 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700977 * Storage state if the media is present but is blank or is using an
978 * unsupported filesystem.
979 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -0800980 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 */
982 public static final String MEDIA_NOFS = "nofs";
983
984 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700985 * Storage state if the media is present and mounted at its mount point with
986 * read/write access.
987 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -0800988 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 */
990 public static final String MEDIA_MOUNTED = "mounted";
991
992 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -0700993 * Storage state if the media is present and mounted at its mount point with
994 * read-only access.
995 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -0800996 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 */
998 public static final String MEDIA_MOUNTED_READ_ONLY = "mounted_ro";
999
1000 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001001 * Storage state if the media is present not mounted, and shared via USB
1002 * mass storage.
1003 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001004 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 */
1006 public static final String MEDIA_SHARED = "shared";
1007
1008 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001009 * Storage state if the media was removed before it was unmounted.
1010 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001011 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 */
1013 public static final String MEDIA_BAD_REMOVAL = "bad_removal";
1014
1015 /**
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001016 * Storage state if the media is present but cannot be mounted. Typically
1017 * this happens if the file system on the media is corrupted.
1018 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001019 * @see #getExternalStorageState(File)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 */
1021 public static final String MEDIA_UNMOUNTABLE = "unmountable";
1022
1023 /**
Jeff Sharkey48877892015-03-18 11:27:19 -07001024 * Storage state if the media is in the process of being ejected.
1025 *
1026 * @see #getExternalStorageState(File)
1027 */
1028 public static final String MEDIA_EJECTING = "ejecting";
1029
1030 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001031 * Returns the current state of the primary shared/external storage media.
Felipe Lemec7b1f892016-01-15 15:02:31 -08001032 *
Jeff Sharkey8c165792012-10-22 14:08:29 -07001033 * @see #getExternalStorageDirectory()
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001034 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
1035 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
1036 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
1037 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
1038 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 */
1040 public static String getExternalStorageState() {
Andreas Gamped281b422016-07-08 03:50:27 +00001041 final File externalDir = sCurrentUser.getExternalDirs()[0];
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001042 return getExternalStorageState(externalDir);
1043 }
1044
1045 /**
1046 * @deprecated use {@link #getExternalStorageState(File)}
1047 */
1048 @Deprecated
1049 public static String getStorageState(File path) {
1050 return getExternalStorageState(path);
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001051 }
1052
1053 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001054 * Returns the current state of the shared/external storage media at the
1055 * given path.
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001056 *
1057 * @return one of {@link #MEDIA_UNKNOWN}, {@link #MEDIA_REMOVED},
1058 * {@link #MEDIA_UNMOUNTED}, {@link #MEDIA_CHECKING},
1059 * {@link #MEDIA_NOFS}, {@link #MEDIA_MOUNTED},
1060 * {@link #MEDIA_MOUNTED_READ_ONLY}, {@link #MEDIA_SHARED},
1061 * {@link #MEDIA_BAD_REMOVAL}, or {@link #MEDIA_UNMOUNTABLE}.
1062 */
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001063 public static String getExternalStorageState(File path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001064 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001065 if (volume != null) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001066 return volume.getState();
1067 } else {
1068 return MEDIA_UNKNOWN;
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 }
1071
Dianne Hackborn407f6252010-10-04 11:31:17 -07001072 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001073 * Returns whether the primary shared/external storage media is physically
1074 * removable.
Dianne Hackborn407f6252010-10-04 11:31:17 -07001075 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001076 * @return true if the storage device can be removed (such as an SD card),
1077 * or false if the storage device is built in and cannot be
1078 * physically removed.
Dianne Hackborn407f6252010-10-04 11:31:17 -07001079 */
1080 public static boolean isExternalStorageRemovable() {
Andreas Gamped281b422016-07-08 03:50:27 +00001081 final File externalDir = sCurrentUser.getExternalDirs()[0];
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001082 return isExternalStorageRemovable(externalDir);
Dianne Hackborn407f6252010-10-04 11:31:17 -07001083 }
1084
Kenny Roote1ff2142010-10-12 11:20:01 -07001085 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001086 * Returns whether the shared/external storage media at the given path is
1087 * physically removable.
Andy Stadler50c294f2011-03-07 19:13:42 -08001088 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001089 * @return true if the storage device can be removed (such as an SD card),
1090 * or false if the storage device is built in and cannot be
1091 * physically removed.
1092 * @throws IllegalArgumentException if the path is not a valid storage
1093 * device.
1094 */
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001095 public static boolean isExternalStorageRemovable(@NonNull File path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001096 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001097 if (volume != null) {
1098 return volume.isRemovable();
1099 } else {
1100 throw new IllegalArgumentException("Failed to find storage device at " + path);
1101 }
1102 }
1103
1104 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001105 * Returns whether the primary shared/external storage media is emulated.
1106 * <p>
1107 * The contents of emulated storage devices are backed by a private user
1108 * data partition, which means there is little benefit to apps storing data
1109 * here instead of the private directories returned by
1110 * {@link Context#getFilesDir()}, etc.
1111 * <p>
1112 * This returns true when emulated storage is backed by either internal
1113 * storage or an adopted storage device.
Andy Stadler50c294f2011-03-07 19:13:42 -08001114 *
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001115 * @see DevicePolicyManager#setStorageEncryption(android.content.ComponentName,
1116 * boolean)
Kenny Roote1ff2142010-10-12 11:20:01 -07001117 */
1118 public static boolean isExternalStorageEmulated() {
Andreas Gamped281b422016-07-08 03:50:27 +00001119 final File externalDir = sCurrentUser.getExternalDirs()[0];
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001120 return isExternalStorageEmulated(externalDir);
1121 }
1122
1123 /**
Jeff Sharkey59d28dc82015-10-14 13:56:23 -07001124 * Returns whether the shared/external storage media at the given path is
1125 * emulated.
1126 * <p>
1127 * The contents of emulated storage devices are backed by a private user
1128 * data partition, which means there is little benefit to apps storing data
1129 * here instead of the private directories returned by
1130 * {@link Context#getFilesDir()}, etc.
1131 * <p>
1132 * This returns true when emulated storage is backed by either internal
1133 * storage or an adopted storage device.
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001134 *
1135 * @throws IllegalArgumentException if the path is not a valid storage
1136 * device.
1137 */
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001138 public static boolean isExternalStorageEmulated(@NonNull File path) {
Jeff Sharkey48877892015-03-18 11:27:19 -07001139 final StorageVolume volume = StorageManager.getStorageVolume(path, UserHandle.myUserId());
Jeff Sharkey4ca728c2014-01-10 16:27:19 -08001140 if (volume != null) {
1141 return volume.isEmulated();
1142 } else {
1143 throw new IllegalArgumentException("Failed to find storage device at " + path);
1144 }
Kenny Roote1ff2142010-10-12 11:20:01 -07001145 }
1146
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001147 /**
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001148 * Returns whether the primary shared/external storage media is a legacy
1149 * view that includes files not owned by the app.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001150 * <p>
1151 * This value may be different from the value requested by
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001152 * {@code requestLegacyExternalStorage} in the app's manifest, since an app
1153 * may inherit its legacy state based on when it was first installed.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001154 * <p>
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001155 * Non-legacy apps can continue to discover and read media belonging to
1156 * other apps via {@link android.provider.MediaStore}.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001157 */
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001158 public static boolean isExternalStorageLegacy() {
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001159 final File externalDir = sCurrentUser.getExternalDirs()[0];
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001160 return isExternalStorageLegacy(externalDir);
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001161 }
1162
1163 /**
1164 * Returns whether the shared/external storage media at the given path is a
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001165 * legacy view that includes files not owned by the app.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001166 * <p>
1167 * This value may be different from the value requested by
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001168 * {@code requestLegacyExternalStorage} in the app's manifest, since an app
1169 * may inherit its legacy state based on when it was first installed.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001170 * <p>
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001171 * Non-legacy apps can continue to discover and read media belonging to
1172 * other apps via {@link android.provider.MediaStore}.
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001173 *
1174 * @throws IllegalArgumentException if the path is not a valid storage
1175 * device.
1176 */
Jeff Sharkey8926fc12019-04-21 09:38:42 -06001177 public static boolean isExternalStorageLegacy(@NonNull File path) {
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001178 final Context context = AppGlobals.getInitialApplication();
Sudheer Shanka572fdfd2019-06-04 16:46:57 -07001179 final int uid = context.getApplicationInfo().uid;
1180 if (Process.isIsolated(uid)) {
1181 return false;
1182 }
1183
1184 final PackageManager packageManager = context.getPackageManager();
1185 if (packageManager.isInstantApp()) {
1186 return false;
1187 }
1188
1189 if (packageManager.checkPermission(Manifest.permission.WRITE_MEDIA_STORAGE,
1190 context.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
1191 return true;
1192 }
1193
1194 if (packageManager.checkPermission(Manifest.permission.INSTALL_PACKAGES,
1195 context.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
1196 return true;
1197 }
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001198 final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
Sudheer Shanka572fdfd2019-06-04 16:46:57 -07001199 final String[] packagesForUid = packageManager.getPackagesForUid(uid);
1200 for (String packageName : packagesForUid) {
1201 if (appOps.checkOpNoThrow(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES,
1202 uid, packageName) == AppOpsManager.MODE_ALLOWED) {
1203 return true;
1204 }
1205 }
Jeff Sharkeye9fcabc2019-04-04 11:19:22 -06001206
Svet Ganovd563e932019-04-14 13:07:41 -07001207 return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
Sudheer Shanka572fdfd2019-06-04 16:46:57 -07001208 uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
Jeff Sharkeybcff13c2019-03-28 14:29:35 -06001209 }
1210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001211 static File getDirectory(String variableName, String defaultPath) {
1212 String path = System.getenv(variableName);
1213 return path == null ? new File(defaultPath) : new File(path);
1214 }
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001215
Jeff Sharkey48749fc2013-04-19 13:25:04 -07001216 /** {@hide} */
1217 public static void setUserRequired(boolean userRequired) {
Andreas Gamped281b422016-07-08 03:50:27 +00001218 sUserRequired = userRequired;
Jeff Sharkey48749fc2013-04-19 13:25:04 -07001219 }
1220
1221 private static void throwIfUserRequired() {
Andreas Gamped281b422016-07-08 03:50:27 +00001222 if (sUserRequired) {
Jeff Sharkey48749fc2013-04-19 13:25:04 -07001223 Log.wtf(TAG, "Path requests must specify a user by using UserEnvironment",
1224 new Throwable());
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001225 }
1226 }
1227
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001228 /**
1229 * Append path segments to each given base path, returning result.
1230 *
1231 * @hide
1232 */
Andrei Onea24ec3212019-03-15 17:35:05 +00001233 @UnsupportedAppUsage
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001234 public static File[] buildPaths(File[] base, String... segments) {
1235 File[] result = new File[base.length];
1236 for (int i = 0; i < base.length; i++) {
1237 result[i] = buildPath(base[i], segments);
1238 }
1239 return result;
1240 }
1241
1242 /**
1243 * Append path segments to given base path, returning result.
1244 *
1245 * @hide
1246 */
Philip P. Moltmannf80809f2018-04-04 11:20:44 -07001247 @TestApi
Jeff Sharkey1abdb712013-08-11 16:28:14 -07001248 public static File buildPath(File base, String... segments) {
Jeff Sharkeyb049e212012-09-07 23:16:01 -07001249 File cur = base;
1250 for (String segment : segments) {
1251 if (cur == null) {
1252 cur = new File(segment);
1253 } else {
1254 cur = new File(cur, segment);
1255 }
1256 }
1257 return cur;
1258 }
Jeff Sharkey63d0a062013-03-01 16:12:55 -08001259
1260 /**
1261 * If the given path exists on emulated external storage, return the
1262 * translated backing path hosted on internal storage. This bypasses any
1263 * emulation later, improving performance. This is <em>only</em> suitable
1264 * for read-only access.
1265 * <p>
1266 * Returns original path if given path doesn't meet these criteria. Callers
1267 * must hold {@link android.Manifest.permission#WRITE_MEDIA_STORAGE}
1268 * permission.
1269 *
Jeff Sharkey70eb34a2018-09-13 11:57:03 -06001270 * @deprecated disabled now that FUSE has been replaced by sdcardfs
Jeff Sharkey63d0a062013-03-01 16:12:55 -08001271 * @hide
1272 */
Andrei Onea24ec3212019-03-15 17:35:05 +00001273 @UnsupportedAppUsage
Jeff Sharkey70eb34a2018-09-13 11:57:03 -06001274 @Deprecated
Jeff Sharkey63d0a062013-03-01 16:12:55 -08001275 public static File maybeTranslateEmulatedPathToInternal(File path) {
Jeff Sharkey50a05452015-04-29 11:24:52 -07001276 return StorageManager.maybeTranslateEmulatedPathToInternal(path);
Jeff Sharkey63d0a062013-03-01 16:12:55 -08001277 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278}