From ae8b469b80cd2da1cb83d5b77a801ba1d074dcd2 Mon Sep 17 00:00:00 2001 From: mahdihijazi Date: Mon, 8 Jan 2018 18:06:10 +0100 Subject: [PATCH] Android: Don't hard code the user dircetory path to /sdcard/dolphin-emu Android is allowed to pick any path for the external storage media and that's why we should always use Environment.getExternalStorageDirectory() to get the external storage path --- .../dolphinemu/DolphinApplication.java | 2 - .../fragments/EmulationFragment.java | 15 +++- .../DirectoryInitializationService.java | 75 +++++++++++++++---- .../ui/settings/SettingsActivity.java | 7 ++ .../settings/SettingsActivityPresenter.java | 26 +++++-- .../ui/settings/SettingsActivityView.java | 5 ++ .../dolphinemu/utils/SettingsFile.java | 5 +- .../app/src/main/res/values/strings.xml | 2 + 8 files changed, 110 insertions(+), 27 deletions(-) diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/DolphinApplication.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/DolphinApplication.java index 6c2e3be39d..ee051a68a7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/DolphinApplication.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/DolphinApplication.java @@ -15,8 +15,6 @@ public class DolphinApplication extends Application { super.onCreate(); - NativeLibrary.SetUserDirectory(""); // Empty string means use the default path - if (PermissionsHandler.hasWriteAccess(getApplicationContext())) DirectoryInitializationService.startService(getApplicationContext()); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index 6b039e185f..39eb383ae7 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -158,13 +158,22 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C DirectoryInitializationService.BROADCAST_ACTION); directoryStateReceiver = - new DirectoryStateReceiver(directoryInitializationState -> { - if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) { + new DirectoryStateReceiver(directoryInitializationState -> + { + if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) + { mEmulationState.run(activity.isActivityRecreated()); - } else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) { + } + else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) + { Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT) .show(); } + else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE) + { + Toast.makeText(getContext(), R.string.external_storage_not_mounted, Toast.LENGTH_SHORT) + .show(); + } }); // Registers the DirectoryStateReceiver and its intent filters diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/DirectoryInitializationService.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/DirectoryInitializationService.java index 7d41df25ac..d23b478065 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/DirectoryInitializationService.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/DirectoryInitializationService.java @@ -10,6 +10,7 @@ import android.app.IntentService; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.os.Environment; import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; @@ -22,6 +23,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.concurrent.atomic.AtomicBoolean; + /** * A service that spawns its own thread in order to copy several binary and shader files @@ -32,12 +35,15 @@ public final class DirectoryInitializationService extends IntentService public static final String BROADCAST_ACTION = "org.dolphinemu.dolphinemu.BROADCAST"; public static final String EXTRA_STATE = "directoryState"; - private static DirectoryInitializationState directoryState = null; + private static volatile DirectoryInitializationState directoryState = null; + private static String userPath; + private static AtomicBoolean isDolphinDirectoryInitializationRunning = new AtomicBoolean(false); public enum DirectoryInitializationState { DOLPHIN_DIRECTORIES_INITIALIZED, - EXTERNAL_STORAGE_PERMISSION_NEEDED + EXTERNAL_STORAGE_PERMISSION_NEEDED, + CANT_FIND_EXTERNAL_STORAGE } public DirectoryInitializationService() @@ -55,21 +61,50 @@ public final class DirectoryInitializationService extends IntentService @Override protected void onHandleIntent(Intent intent) { - if (directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) + isDolphinDirectoryInitializationRunning.set(true); + + if (directoryState != DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) { - sendBroadcastState(DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED); + if (PermissionsHandler.hasWriteAccess(this)) + { + if (setDolphinUserDirectory()) + { + initializeInternalStorage(); + initializeExternalStorage(); + + directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED; + } + else + { + directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE; + } + } + else + { + directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED; + } } - else if (PermissionsHandler.hasWriteAccess(this)) + + isDolphinDirectoryInitializationRunning.set(false); + sendBroadcastState(directoryState); + } + + private boolean setDolphinUserDirectory() + { + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { - initializeInternalStorage(); - initializeExternalStorage(); - directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED; - sendBroadcastState(directoryState); - } - else - { - sendBroadcastState(DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED); + File externalPath = Environment.getExternalStorageDirectory(); + if (externalPath != null) + { + userPath = externalPath.getAbsolutePath() + "/dolphin-emu"; + Log.debug("[DirectoryInitializationService] User Dir: " + userPath); + NativeLibrary.SetUserDirectory(userPath); + return true; + } + } + + return false; } private void initializeInternalStorage() @@ -128,6 +163,20 @@ public final class DirectoryInitializationService extends IntentService return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED; } + public static String getUserDirectory() + { + if (directoryState == null) + { + throw new IllegalStateException("DirectoryInitializationService has to run at least once!"); + } + else if (isDolphinDirectoryInitializationRunning.get()) + { + throw new IllegalStateException("DirectoryInitializationService has to finish running first!"); + } + return userPath; + + } + private void sendBroadcastState(DirectoryInitializationState state) { Intent localIntent = diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java index cd942eb091..9ea6828b67 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java @@ -161,6 +161,13 @@ public final class SettingsActivity extends AppCompatActivity implements Setting .show(); } + @Override + public void showExternalStorageNotMountedHint() + { + Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT) + .show(); + } + @Override public HashMap getSettings(int file) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityPresenter.java index 20cf5bcc78..ca25ea5d2b 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityPresenter.java @@ -6,6 +6,7 @@ import android.os.Bundle; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.model.settings.SettingSection; import org.dolphinemu.dolphinemu.services.DirectoryInitializationService; +import org.dolphinemu.dolphinemu.services.DirectoryInitializationService.DirectoryInitializationState; import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver; import org.dolphinemu.dolphinemu.utils.Log; import org.dolphinemu.dolphinemu.utils.SettingsFile; @@ -40,9 +41,6 @@ public final class SettingsActivityPresenter { if (savedInstanceState == null) { - mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile(SettingsFile.FILE_NAME_DOLPHIN, mView)); - mSettings.add(SettingsFile.SETTINGS_GFX, SettingsFile.readFile(SettingsFile.FILE_NAME_GFX, mView)); - mSettings.add(SettingsFile.SETTINGS_WIIMOTE, SettingsFile.readFile(SettingsFile.FILE_NAME_WIIMOTE, mView)); this.menuTag = menuTag; } else @@ -58,6 +56,13 @@ public final class SettingsActivityPresenter void loadSettingsUI() { + if (mSettings.isEmpty()) + { + mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile(SettingsFile.FILE_NAME_DOLPHIN, mView)); + mSettings.add(SettingsFile.SETTINGS_GFX, SettingsFile.readFile(SettingsFile.FILE_NAME_GFX, mView)); + mSettings.add(SettingsFile.SETTINGS_WIIMOTE, SettingsFile.readFile(SettingsFile.FILE_NAME_WIIMOTE, mView)); + } + mView.showSettingsFragment(menuTag, false); mView.onSettingsFileLoaded(mSettings); } @@ -72,14 +77,23 @@ public final class SettingsActivityPresenter DirectoryInitializationService.BROADCAST_ACTION); directoryStateReceiver = - new DirectoryStateReceiver(directoryInitializationState -> { - if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) { + new DirectoryStateReceiver(directoryInitializationState -> + { + if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) + { mView.hideLoading(); loadSettingsUI(); - } else if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) { + } + else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) + { mView.showPermissionNeededHint(); mView.hideLoading(); } + else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE) + { + mView.showExternalStorageNotMountedHint(); + mView.hideLoading(); + } }); mView.startDirectoryInitializationService(directoryStateReceiver, statusIntentFilter); diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityView.java index 686338eaee..d7649a729d 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityView.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityView.java @@ -118,6 +118,11 @@ public interface SettingsActivityView */ void showPermissionNeededHint(); + /** + * Show a hint to the user that the app needs the external storage to be mounted + */ + void showExternalStorageNotMountedHint(); + /** * Start the DirectoryInitializationService and listen for the result. * diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java index a57b116e2a..385b65476f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/SettingsFile.java @@ -1,6 +1,5 @@ package org.dolphinemu.dolphinemu.utils; -import android.os.Environment; import android.support.annotation.NonNull; import org.dolphinemu.dolphinemu.model.settings.BooleanSetting; @@ -9,6 +8,7 @@ import org.dolphinemu.dolphinemu.model.settings.IntSetting; import org.dolphinemu.dolphinemu.model.settings.Setting; import org.dolphinemu.dolphinemu.model.settings.SettingSection; import org.dolphinemu.dolphinemu.model.settings.StringSetting; +import org.dolphinemu.dolphinemu.services.DirectoryInitializationService; import org.dolphinemu.dolphinemu.ui.settings.SettingsActivityView; import java.io.BufferedReader; @@ -393,8 +393,7 @@ public final class SettingsFile @NonNull private static File getSettingsFile(String fileName) { - String storagePath = Environment.getExternalStorageDirectory().getAbsolutePath(); - return new File(storagePath + "/dolphin-emu/Config/" + fileName + ".ini"); + return new File(DirectoryInitializationService.getUserDirectory() + "/Config/" + fileName + ".ini"); } private static SettingSection sectionFromLine(String line) diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 8c1ed538ac..aada82b4ed 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -251,4 +251,6 @@ Loading Settings... Change Disc + + The external storage needs to be available in order to use Dolphin