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