1cfb3d242306311ce27ec51bf511764377c173a7cKiran Ryali + Christian Williamspackage org.robolectric.shadows;
2e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Moore
3d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
4d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport static android.os.Build.VERSION_CODES.KITKAT;
5d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport static android.os.Build.VERSION_CODES.LOLLIPOP;
6d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport static android.os.Build.VERSION_CODES.M;
7d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
8d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport android.os.Environment;
943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglassimport java.io.File;
10c472650a6c989986a7276fcde482af7cdeba065aAlexander Blomimport java.io.IOException;
11c472650a6c989986a7276fcde482af7cdeba065aAlexander Blomimport java.nio.file.Files;
12c472650a6c989986a7276fcde482af7cdeba065aAlexander Blomimport java.nio.file.Path;
13084d588b645d53c1110ff24b82433b5a331cc6d3James Lemieuximport java.util.ArrayList;
1443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglassimport java.util.HashMap;
15d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport java.util.List;
16d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport java.util.Map;
17d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport org.robolectric.RuntimeEnvironment;
1843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglassimport org.robolectric.annotation.Implementation;
19d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport org.robolectric.annotation.Implements;
20d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport org.robolectric.annotation.Resetter;
21d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabotimport org.robolectric.util.ReflectionHelpers;
229e11c64f01e0d72a3f469d5866b695c778387c26Christian Williams & Dimitris Couchell
23e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Moore@Implements(Environment.class)
24e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Moorepublic class ShadowEnvironment {
2543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  private static String externalStorageState = Environment.MEDIA_REMOVED;
2643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  private static final Map<File, Boolean> STORAGE_EMULATED = new HashMap<>();
2743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  private static final Map<File, Boolean> STORAGE_REMOVABLE = new HashMap<>();
280a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie  private static boolean sIsExternalStorageEmulated;
291b698c5055f7ad57d68b4b8fca1d3d7aa5fce1b0Jonathan Gerrish  private static Path tmpExternalFilesDirBase;
30084d588b645d53c1110ff24b82433b5a331cc6d3James Lemieux  private static final List<File> externalDirs = new ArrayList<>();
31d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  private static Map<Path, String> storageState = new HashMap<>();
3229a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
33c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom  static Path EXTERNAL_CACHE_DIR;
34c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom  static Path EXTERNAL_FILES_DIR;
35c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom
3629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  @Implementation
3729a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  public static String getExternalStorageState() {
3829a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams    return externalStorageState;
3929a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
4029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
4143a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  /**
42d5dcccbc5fdf62c40af6fb046197878843c0cb5dChristian Williams   * Sets the return value of {@link #getExternalStorageState()}.
4343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   *
4443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param externalStorageState Value to return from {@link #getExternalStorageState()}.
4543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   */
4643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static void setExternalStorageState(String externalStorageState) {
4743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    ShadowEnvironment.externalStorageState = externalStorageState;
4843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
4943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
500a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie  /**
51d5dcccbc5fdf62c40af6fb046197878843c0cb5dChristian Williams   * Sets the return value of {@link #isExternalStorageEmulated()}.
520a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie   *
530a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie   * @param emulated Value to return from {@link #isExternalStorageEmulated()}.
540a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie   */
550a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie  public static void setIsExternalStorageEmulated(boolean emulated) {
560a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie    ShadowEnvironment.sIsExternalStorageEmulated = emulated;
570a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie  }
580a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie
5943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  @Implementation
6043a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static File getExternalStorageDirectory() {
611b698c5055f7ad57d68b4b8fca1d3d7aa5fce1b0Jonathan Gerrish    if (!exists(EXTERNAL_CACHE_DIR)) EXTERNAL_CACHE_DIR = RuntimeEnvironment.getTempDirectory().create("external-cache");
62c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    return EXTERNAL_CACHE_DIR.toFile();
6343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
6443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
6543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  @Implementation
6643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static File getExternalStoragePublicDirectory(String type) {
671b698c5055f7ad57d68b4b8fca1d3d7aa5fce1b0Jonathan Gerrish    if (!exists(EXTERNAL_FILES_DIR)) EXTERNAL_FILES_DIR = RuntimeEnvironment.getTempDirectory().create("external-files");
68c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    if (type == null) return EXTERNAL_FILES_DIR.toFile();
69c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    Path path = EXTERNAL_FILES_DIR.resolve(type);
70c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    try {
71f00fb170b988ce99dcc1ff5190e17c0d35b67234Alexander Blom      Files.createDirectories(path);
72c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    } catch (IOException e) {
73c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom      throw new RuntimeException(e);
74c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    }
75c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    return path.toFile();
7643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
7743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
7843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  @Resetter
7943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static void reset() {
80c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom
81c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    EXTERNAL_CACHE_DIR = null;
82c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    EXTERNAL_FILES_DIR = null;
83c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom
8443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    STORAGE_EMULATED.clear();
8543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    STORAGE_REMOVABLE.clear();
860a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie
87d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    storageState = new HashMap<>();
88d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    externalDirs.clear();
89d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
900a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie    sIsExternalStorageEmulated = false;
9143a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
9243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
93c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom  private static boolean exists(Path path) {
94c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom    return path != null && Files.exists(path);
95c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom  }
96c472650a6c989986a7276fcde482af7cdeba065aAlexander Blom
97df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish  @Implementation
98df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish  public static boolean isExternalStorageRemovable() {
99df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish    final Boolean exists = STORAGE_REMOVABLE.get(getExternalStorageDirectory());
100df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish    return exists != null ? exists : false;
101df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish  }
102df6ac64d05f00add83341e8f538072f0efcb85dcJonathan Gerrish
103d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams  @Implementation(minSdk = KITKAT)
104d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  public static String getStorageState(File directory) {
105d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    Path directoryPath = directory.toPath();
106d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    for (Map.Entry<Path, String> entry : storageState.entrySet()) {
107d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      if (directoryPath.startsWith(entry.getKey())) {
108d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        return entry.getValue();
109d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      }
110d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    }
111d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    return null;
112ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish  }
113ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish
114d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams  @Implementation(minSdk = LOLLIPOP)
115d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  public static String getExternalStorageState(File directory) {
116d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    Path directoryPath = directory.toPath();
117d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    for (Map.Entry<Path, String> entry : storageState.entrySet()) {
118d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      if (directoryPath.startsWith(entry.getKey())) {
119d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        return entry.getValue();
120d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      }
121d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    }
122d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    return null;
123ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish  }
124ef61bd4a7e62b3e1623ac7d8735232f1d629d6dfJonathan Gerrish
125d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
126d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams  @Implementation(minSdk = LOLLIPOP)
12743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static boolean isExternalStorageRemovable(File path) {
12843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    final Boolean exists = STORAGE_REMOVABLE.get(path);
12943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    return exists != null ? exists : false;
13029a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
13129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams
132d5191fc46f3997c3dedfea14680ec4f114124619Christian Williams  @Implementation(minSdk = LOLLIPOP)
13343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static boolean isExternalStorageEmulated(File path) {
13443a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    final Boolean emulated = STORAGE_EMULATED.get(path);
13543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    return emulated != null ? emulated : false;
13629a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
1379fbd34e2cfc7b9b2be99ae8e27afa623cc61ae72Dimitris Couchell
1380a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie  @Implementation
1390a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie  public static boolean isExternalStorageEmulated() {
1400a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie    return sIsExternalStorageEmulated;
1410a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie  }
1420a3c4710aadbab8090414c6c576fba7ad36e89feMichael Hoisie
14343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  /**
144d5dcccbc5fdf62c40af6fb046197878843c0cb5dChristian Williams   * Sets the "isRemovable" flag of a particular file.
14543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   *
14643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param file Target file.
14743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param isRemovable True if the filesystem is removable.
14843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   */
14943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static void setExternalStorageRemovable(File file, boolean isRemovable) {
15043a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    STORAGE_REMOVABLE.put(file, isRemovable);
15143a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  }
15243a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass
15343a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  /**
154d5dcccbc5fdf62c40af6fb046197878843c0cb5dChristian Williams   * Sets the "isEmulated" flag of a particular file.
15543a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   *
15643a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param file Target file.
15743a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   * @param isEmulated True if the filesystem is emulated.
15843a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass   */
15943a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass  public static void setExternalStorageEmulated(File file, boolean isEmulated) {
16043a35d3623cad51c47f5b07c41d71665e891b6a3Erich Douglass    STORAGE_EMULATED.put(file, isEmulated);
16129a8359eaef1ee9f40c967d3c4b5c1117c8c2a43Christian Williams  }
162d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
163d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  /**
164d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   * Adds a directory to list returned by {@link ShadowUserEnvironment#getExternalDirs()}.
165d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   *
166d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   * @param path the external dir to add
167d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   */
168d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  public static File addExternalDir(String path) {
169d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    Path externalFileDir;
170d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    if (path == null) {
171d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      externalFileDir = null;
172d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    } else {
173d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      try {
1741b698c5055f7ad57d68b4b8fca1d3d7aa5fce1b0Jonathan Gerrish        if (tmpExternalFilesDirBase == null) {
1751b698c5055f7ad57d68b4b8fca1d3d7aa5fce1b0Jonathan Gerrish          tmpExternalFilesDirBase = RuntimeEnvironment.getTempDirectory().create("external-files-base");
1761b698c5055f7ad57d68b4b8fca1d3d7aa5fce1b0Jonathan Gerrish        }
177d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        externalFileDir = tmpExternalFilesDirBase.resolve(path);
178d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        Files.createDirectories(externalFileDir);
179d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        externalDirs.add(externalFileDir.toFile());
180d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      } catch (IOException e) {
181d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        throw new RuntimeException("Could not create external files dir", e);
182d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      }
183d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    }
184d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
185d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    if (RuntimeEnvironment.getApiLevel() >= JELLY_BEAN_MR1
186d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        && RuntimeEnvironment.getApiLevel() < KITKAT) {
187d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      if (externalDirs.size() == 1 && externalFileDir != null) {
188d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        Environment.UserEnvironment userEnvironment =
189d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot            ReflectionHelpers.getStaticField(Environment.class, "sCurrentUser");
190d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot        ReflectionHelpers.setField(
191d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot            userEnvironment, "mExternalStorageAndroidData", externalFileDir.toFile());
192d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      }
193d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    } else if (RuntimeEnvironment.getApiLevel() >= KITKAT && RuntimeEnvironment.getApiLevel() < M) {
194d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      Environment.UserEnvironment userEnvironment =
195d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot          ReflectionHelpers.getStaticField(Environment.class, "sCurrentUser");
196d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      ReflectionHelpers.setField(userEnvironment, "mExternalDirsForApp",
197d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot          externalDirs.toArray(new File[externalDirs.size()]));
198d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    }
199d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
200d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    if (externalFileDir == null) {
201d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      return null;
202d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    }
203d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    return externalFileDir.toFile();
204d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  }
205d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
206d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  /**
207d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   * Sets the {@link #getExternalStorageState(File)} for given directory.
208d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   *
209d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   * @param externalStorageState Value to return from {@link #getExternalStorageState(File)}.
210d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   */
211d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  public static void setExternalStorageState(File directory, String state) {
212d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    storageState.put(directory.toPath(), state);
213d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  }
214d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
215d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  /**
216d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   * Shadow for {@link android.os.Environment.UserEnvironment}
217d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot   */
218d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  @Implements(className = "android.os.Environment$UserEnvironment", isInAndroidSdk = false)
219d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  public static class ShadowUserEnvironment {
220d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot
221d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    @Implementation
222d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    public File[] getExternalDirs() {
223d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot      return externalDirs.toArray(new File[externalDirs.size()]);
224d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot    }
225d1f45b44eb9b6ebb83fb9ae1f4adbfb52861c886Brett Chabot  }
226e9d4b241c1e9b9225da1424698942c358ef22162Chris Heisterkamp & Joe Moore}
227