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
This commit is contained in:
mahdihijazi 2018-01-08 18:06:10 +01:00
parent 9a166dca57
commit ae8b469b80
8 changed files with 110 additions and 27 deletions

View File

@ -15,8 +15,6 @@ public class DolphinApplication extends Application
{ {
super.onCreate(); super.onCreate();
NativeLibrary.SetUserDirectory(""); // Empty string means use the default path
if (PermissionsHandler.hasWriteAccess(getApplicationContext())) if (PermissionsHandler.hasWriteAccess(getApplicationContext()))
DirectoryInitializationService.startService(getApplicationContext()); DirectoryInitializationService.startService(getApplicationContext());

View File

@ -158,13 +158,22 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
DirectoryInitializationService.BROADCAST_ACTION); DirectoryInitializationService.BROADCAST_ACTION);
directoryStateReceiver = directoryStateReceiver =
new DirectoryStateReceiver(directoryInitializationState -> { new DirectoryStateReceiver(directoryInitializationState ->
if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) { {
if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
{
mEmulationState.run(activity.isActivityRecreated()); 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) Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show(); .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 // Registers the DirectoryStateReceiver and its intent filters

View File

@ -10,6 +10,7 @@ import android.app.IntentService;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Environment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
@ -22,6 +23,8 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; 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 * 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 BROADCAST_ACTION = "org.dolphinemu.dolphinemu.BROADCAST";
public static final String EXTRA_STATE = "directoryState"; 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 public enum DirectoryInitializationState
{ {
DOLPHIN_DIRECTORIES_INITIALIZED, DOLPHIN_DIRECTORIES_INITIALIZED,
EXTERNAL_STORAGE_PERMISSION_NEEDED EXTERNAL_STORAGE_PERMISSION_NEEDED,
CANT_FIND_EXTERNAL_STORAGE
} }
public DirectoryInitializationService() public DirectoryInitializationService()
@ -55,22 +61,51 @@ public final class DirectoryInitializationService extends IntentService
@Override @Override
protected void onHandleIntent(Intent intent) 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))
} {
else if (PermissionsHandler.hasWriteAccess(this)) if (setDolphinUserDirectory())
{ {
initializeInternalStorage(); initializeInternalStorage();
initializeExternalStorage(); initializeExternalStorage();
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED; directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
sendBroadcastState(directoryState);
} }
else else
{ {
sendBroadcastState(DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED); directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE;
} }
} }
else
{
directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED;
}
}
isDolphinDirectoryInitializationRunning.set(false);
sendBroadcastState(directoryState);
}
private boolean setDolphinUserDirectory()
{
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
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() private void initializeInternalStorage()
{ {
@ -128,6 +163,20 @@ public final class DirectoryInitializationService extends IntentService
return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED; 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) private void sendBroadcastState(DirectoryInitializationState state)
{ {
Intent localIntent = Intent localIntent =

View File

@ -161,6 +161,13 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
.show(); .show();
} }
@Override
public void showExternalStorageNotMountedHint()
{
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
.show();
}
@Override @Override
public HashMap<String, SettingSection> getSettings(int file) public HashMap<String, SettingSection> getSettings(int file)
{ {

View File

@ -6,6 +6,7 @@ import android.os.Bundle;
import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.SettingSection; import org.dolphinemu.dolphinemu.model.settings.SettingSection;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService; import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService.DirectoryInitializationState;
import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver; import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
import org.dolphinemu.dolphinemu.utils.Log; import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.SettingsFile; import org.dolphinemu.dolphinemu.utils.SettingsFile;
@ -40,9 +41,6 @@ public final class SettingsActivityPresenter
{ {
if (savedInstanceState == null) 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; this.menuTag = menuTag;
} }
else else
@ -58,6 +56,13 @@ public final class SettingsActivityPresenter
void loadSettingsUI() 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.showSettingsFragment(menuTag, false);
mView.onSettingsFileLoaded(mSettings); mView.onSettingsFileLoaded(mSettings);
} }
@ -72,14 +77,23 @@ public final class SettingsActivityPresenter
DirectoryInitializationService.BROADCAST_ACTION); DirectoryInitializationService.BROADCAST_ACTION);
directoryStateReceiver = directoryStateReceiver =
new DirectoryStateReceiver(directoryInitializationState -> { new DirectoryStateReceiver(directoryInitializationState ->
if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) { {
if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
{
mView.hideLoading(); mView.hideLoading();
loadSettingsUI(); loadSettingsUI();
} else if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) { }
else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
{
mView.showPermissionNeededHint(); mView.showPermissionNeededHint();
mView.hideLoading(); mView.hideLoading();
} }
else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
{
mView.showExternalStorageNotMountedHint();
mView.hideLoading();
}
}); });
mView.startDirectoryInitializationService(directoryStateReceiver, statusIntentFilter); mView.startDirectoryInitializationService(directoryStateReceiver, statusIntentFilter);

View File

@ -118,6 +118,11 @@ public interface SettingsActivityView
*/ */
void showPermissionNeededHint(); 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. * Start the DirectoryInitializationService and listen for the result.
* *

View File

@ -1,6 +1,5 @@
package org.dolphinemu.dolphinemu.utils; package org.dolphinemu.dolphinemu.utils;
import android.os.Environment;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import org.dolphinemu.dolphinemu.model.settings.BooleanSetting; 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.Setting;
import org.dolphinemu.dolphinemu.model.settings.SettingSection; import org.dolphinemu.dolphinemu.model.settings.SettingSection;
import org.dolphinemu.dolphinemu.model.settings.StringSetting; import org.dolphinemu.dolphinemu.model.settings.StringSetting;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivityView; import org.dolphinemu.dolphinemu.ui.settings.SettingsActivityView;
import java.io.BufferedReader; import java.io.BufferedReader;
@ -393,8 +393,7 @@ public final class SettingsFile
@NonNull @NonNull
private static File getSettingsFile(String fileName) private static File getSettingsFile(String fileName)
{ {
String storagePath = Environment.getExternalStorageDirectory().getAbsolutePath(); return new File(DirectoryInitializationService.getUserDirectory() + "/Config/" + fileName + ".ini");
return new File(storagePath + "/dolphin-emu/Config/" + fileName + ".ini");
} }
private static SettingSection sectionFromLine(String line) private static SettingSection sectionFromLine(String line)

View File

@ -251,4 +251,6 @@
<string name="load_settings">Loading Settings...</string> <string name="load_settings">Loading Settings...</string>
<string name="emulation_change_disc">Change Disc</string> <string name="emulation_change_disc">Change Disc</string>
<string name="external_storage_not_mounted">The external storage needs to be available in order to use Dolphin</string>
</resources> </resources>