ShadowEnvironment.java revision d5191fc46f3997c3dedfea14680ec4f114124619
1cfb3d242306311ce27ec51bf511764377c173a7cKiran Ryali + Christian Williamspackage org.robolectric.shadows;
2e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Moore
343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglassimport java.io.File;
4c472650a6c989986a7276fcde482af7cdeba065aAlexander Blomimport java.io.IOException;
5c472650a6c989986a7276fcde482af7cdeba065aAlexander Blomimport java.nio.file.Files;
6c472650a6c989986a7276fcde482af7cdeba065aAlexander Blomimport java.nio.file.Path;
743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglassimport java.util.Map;
843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglassimport java.util.HashMap;
9e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Mooreimport android.os.Environment;
1043a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglassimport org.robolectric.annotation.Resetter;
11402e2422266b331d25374a90339711ed332952c0Christian Williamsimport org.robolectric.annotation.Implements;
1243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglassimport org.robolectric.annotation.Implementation;
13c472650a6c989986a7276fcde482af7cdeba065aAlexander Blomimport org.robolectric.util.TempDirectory;
149e11c64f01e0d72a3f469d5866b695c778387c26Christian Williams & Dimitris Couchell
15d5191fc46f3997c3dedfea14680ec4f114124619Christian Williamsimport static android.os.Build.VERSION_CODES;
16d5191fc46f3997c3dedfea14680ec4f114124619Christian Williamsimport static android.os.Build.VERSION_CODES.KITKAT;
17d5191fc46f3997c3dedfea14680ec4f114124619Christian Williamsimport static android.os.Build.VERSION_CODES.LOLLIPOP;
18d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams
1913e343bf0b12d99043d3cdced94e86fb284e48d4Erich Douglass/**
2013e343bf0b12d99043d3cdced94e86fb284e48d4Erich Douglass * Shadow for {@link android.os.Environment}.
2113e343bf0b12d99043d3cdced94e86fb284e48d4Erich Douglass */
22e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Moore@Implements(Environment.class)
23e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Moorepublic class ShadowEnvironment {
2443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  private static String externalStorageState = Environment.MEDIA_REMOVED;
2543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  private static final Map<File, Boolean> STORAGE_EMULATED = new HashMap<>();
2643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  private static final Map<File, Boolean> STORAGE_REMOVABLE = new HashMap<>();
2729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
28c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom  static Path EXTERNAL_CACHE_DIR;
29c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom  static Path EXTERNAL_FILES_DIR;
30c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom
3129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  @Implementation
3229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  public static String getExternalStorageState() {
3329a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    return externalStorageState;
3429a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
3529a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
3643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  /**
3743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * Non-Android accessor. Sets the return value of {@link #getExternalStorageState()}.
3843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   *
3943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param externalStorageState Value to return from {@link #getExternalStorageState()}.
4043a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   */
4143a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static void setExternalStorageState(String externalStorageState) {
4243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    ShadowEnvironment.externalStorageState = externalStorageState;
4343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
4443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
4543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  @Implementation
4643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static File getExternalStorageDirectory() {
47c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    if (!exists(EXTERNAL_CACHE_DIR)) EXTERNAL_CACHE_DIR = TempDirectory.create();
48c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    return EXTERNAL_CACHE_DIR.toFile();
4943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
5043a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
5143a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  @Implementation
5243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static File getExternalStoragePublicDirectory(String type) {
53c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    if (!exists(EXTERNAL_FILES_DIR)) EXTERNAL_FILES_DIR = TempDirectory.create();
54c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    if (type == null) return EXTERNAL_FILES_DIR.toFile();
55c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    Path path = EXTERNAL_FILES_DIR.resolve(type);
56c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    try {
57f00fb170b988ce99dcc1ff5190e17c0d35b67234Alexander Blom      Files.createDirectories(path);
58c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    } catch (IOException e) {
59c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom      throw new RuntimeException(e);
60c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    }
61c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    return path.toFile();
6243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
6343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
6443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  @Resetter
6543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static void reset() {
66c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    TempDirectory.destroy(EXTERNAL_CACHE_DIR);
67c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    TempDirectory.destroy(EXTERNAL_FILES_DIR);
68c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom
69c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    EXTERNAL_CACHE_DIR = null;
70c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    EXTERNAL_FILES_DIR = null;
71c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom
7243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    STORAGE_EMULATED.clear();
7343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    STORAGE_REMOVABLE.clear();
7443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
7543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
76c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom  private static boolean exists(Path path) {
77c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    return path != null && Files.exists(path);
78c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom  }
79c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom
80df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish  @Implementation
81df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish  public static boolean isExternalStorageRemovable() {
82df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish    final Boolean exists = STORAGE_REMOVABLE.get(getExternalStorageDirectory());
83df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish    return exists != null ? exists : false;
84df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish  }
85df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish
86d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams  @Implementation(minSdk = KITKAT)
87ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish  public static String getStorageState(File path) {
88ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish    return externalStorageState;
89ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish  }
90ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish
91d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams  @Implementation(minSdk = LOLLIPOP)
92ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish  public static String getExternalStorageState(File path) {
93ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish    return externalStorageState;
94ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish  }
95ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish
96d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams  @Implementation(minSdk = LOLLIPOP)
9743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static boolean isExternalStorageRemovable(File path) {
9843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    final Boolean exists = STORAGE_REMOVABLE.get(path);
9943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    return exists != null ? exists : false;
10029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
10129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
102d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams  @Implementation(minSdk = LOLLIPOP)
10343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static boolean isExternalStorageEmulated(File path) {
10443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    final Boolean emulated = STORAGE_EMULATED.get(path);
10543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    return emulated != null ? emulated : false;
10629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
1079fbd34e2cfc7b9b2be99ae8e27afa623cc61ae72Dimitris Couchell
10843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  /**
10943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * Non-Android accessor. Sets the "isRemovable" flag of a particular file.
11043a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   *
11143a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param file Target file.
11243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param isRemovable True if the filesystem is removable.
11343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   */
11443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static void setExternalStorageRemovable(File file, boolean isRemovable) {
11543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    STORAGE_REMOVABLE.put(file, isRemovable);
11643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
11743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
11843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  /**
11943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * Non-Android accessor. Sets the "isEmulated" flag of a particular file.
12043a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   *
12143a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param file Target file.
12243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param isEmulated True if the filesystem is emulated.
12343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   */
12443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static void setExternalStorageEmulated(File file, boolean isEmulated) {
12543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    STORAGE_EMULATED.put(file, isEmulated);
12629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
127e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Moore}
128