summaryrefslogtreecommitdiff
path: root/Source/Android/app/src/main/java
diff options
context:
space:
mode:
authormahdihijazi <mahdi.hijaz@hotmail.com>2017-12-17 01:09:55 +0100
committermahdihijazi <mahdi.hijaz@hotmail.com>2017-12-18 14:32:39 +0100
commit1190afef51fc91042efce96e7c4a0cafe3d78ae5 (patch)
tree029e6ee724add8664ab6bc581a40ee14573b057e /Source/Android/app/src/main/java
parent9f9b4bc0286a79f7b3d15fa11b1c5e2a70eb1b81 (diff)
[Android] Refactor AssetCopyService and the way we extract resources from the assets
This solves the following issues: 1. If user uninstall Dolphin and install it again the resources will not be copied unless the user manually clear the app cache because we are enabling the allowBackup flag in the manifest which will make the app restore the settings saved in the shared prefernces including the flag assetsCopied. This PR always copy the files everytime you open Dolphin. 2. If the AssetCopyService took long time and you tried to open the settings screen or start a game the behaviour was not expected or the emulator will crash, this PR make sure that whatever we add to the DirectoryInitializationService or how long it will take will still work as expected by blocking both the settings screen and the emulaion screen to wait untill all resources needed are copied. 3. Better communication between the DirectoryInitializationService and the UI screens using brocast messages.
Diffstat (limited to 'Source/Android/app/src/main/java')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java46
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/AssetCopyService.java112
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/DirectoryInitializationService.java154
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java3
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java3
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivity.java55
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityPresenter.java54
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/settings/SettingsActivityView.java33
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryStateReceiver.java24
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java5
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java19
11 files changed, 371 insertions, 137 deletions
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 68b7ddad4d..27d32db0d5 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
@@ -1,10 +1,12 @@
package org.dolphinemu.dolphinemu.fragments;
import android.content.Context;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
+import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceHolder;
@@ -12,13 +14,19 @@ import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
+import android.widget.Toast;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.overlay.InputOverlay;
+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 rx.functions.Action1;
+
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
{
private static final String KEY_GAMEPATH = "gamepath";
@@ -29,6 +37,8 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
private EmulationState mEmulationState;
+ private DirectoryStateReceiver directoryStateReceiver;
+
public static EmulationFragment newInstance(String gamePath)
{
@@ -108,12 +118,25 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
public void onResume()
{
super.onResume();
- mEmulationState.run();
+ if (DirectoryInitializationService.areDolphinDirectoriesReady())
+ {
+ mEmulationState.run();
+ }
+ else
+ {
+ setupDolphinDirectoriesThenStartEmulation();
+ }
}
@Override
public void onPause()
{
+ if (directoryStateReceiver != null)
+ {
+ LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
+ directoryStateReceiver = null;
+ }
+
mEmulationState.pause();
super.onPause();
}
@@ -125,6 +148,27 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
super.onDetach();
}
+ private void setupDolphinDirectoriesThenStartEmulation() {
+ IntentFilter statusIntentFilter = new IntentFilter(
+ DirectoryInitializationService.BROADCAST_ACTION);
+
+ directoryStateReceiver =
+ new DirectoryStateReceiver(directoryInitializationState -> {
+ if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) {
+ mEmulationState.run();
+ } else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) {
+ Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT)
+ .show();
+ }
+ });
+
+ // Registers the DirectoryStateReceiver and its intent filters
+ LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
+ directoryStateReceiver,
+ statusIntentFilter);
+ DirectoryInitializationService.startService(getActivity());
+ }
+
public void toggleInputOverlayVisibility()
{
SharedPreferences.Editor editor = mPreferences.edit();
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/AssetCopyService.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/AssetCopyService.java
deleted file mode 100644
index d8c39459f6..0000000000
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/AssetCopyService.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Copyright 2014 Dolphin Emulator Project
- * Licensed under GPLv2+
- * Refer to the license.txt file included.
- */
-
-package org.dolphinemu.dolphinemu.services;
-
-import android.app.IntentService;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
-
-import org.dolphinemu.dolphinemu.NativeLibrary;
-import org.dolphinemu.dolphinemu.utils.Log;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * A service that spawns its own thread in order to copy several binary and shader files
- * from the Dolphin APK to the external file system.
- */
-public final class AssetCopyService extends IntentService
-{
- public AssetCopyService()
- {
- // Superclass constructor is called to name the thread on which this service executes.
- super("AssetCopyService");
- }
-
- @Override
- protected void onHandleIntent(Intent intent)
- {
- String BaseDir = NativeLibrary.GetUserDirectory();
- String ConfigDir = BaseDir + File.separator + "Config";
-
- // Copy assets if needed
- NativeLibrary.CreateUserFolders();
- copyAssetFolder("GC", BaseDir + File.separator + "GC", false);
- copyAssetFolder("Shaders", BaseDir + File.separator + "Shaders", false);
- copyAssetFolder("Wii", BaseDir + File.separator + "Wii", false);
-
- // Always copy over the GCPad config in case of change or corruption.
- // Not a user configurable file.
- copyAsset("GCPadNew.ini", ConfigDir + File.separator + "GCPadNew.ini", true);
- copyAsset("WiimoteNew.ini", ConfigDir + File.separator + "WiimoteNew.ini", true);
-
- // Record the fact that we've done this before, so we don't do it on every launch.
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
- SharedPreferences.Editor editor = preferences.edit();
-
- editor.putBoolean("assetsCopied", true);
- editor.apply();
- }
-
- private void copyAsset(String asset, String output, Boolean overwrite)
- {
- Log.verbose("[AssetCopyService] Copying File " + asset + " to " + output);
- InputStream in;
- OutputStream out;
-
- try
- {
- File file = new File(output);
- if(!file.exists() || overwrite)
- {
- in = getAssets().open(asset);
- out = new FileOutputStream(output);
- copyFile(in, out);
- in.close();
- out.close();
- }
- }
- catch (IOException e)
- {
- Log.error("[AssetCopyService] Failed to copy asset file: " + asset + e.getMessage());
- }
- }
-
- private void copyAssetFolder(String assetFolder, String outputFolder, Boolean overwrite)
- {
- Log.verbose("[AssetCopyService] Copying Folder " + assetFolder + " to " + outputFolder);
-
- try
- {
- for (String file : getAssets().list(assetFolder))
- {
- copyAssetFolder(assetFolder + File.separator + file, outputFolder + File.separator + file, overwrite);
- copyAsset(assetFolder + File.separator + file, outputFolder + File.separator + file, overwrite);
- }
- }
- catch (IOException e)
- {
- Log.error("[AssetCopyService] Failed to copy asset folder: " + assetFolder + e.getMessage());
- }
- }
-
- private void copyFile(InputStream in, OutputStream out) throws IOException
- {
- byte[] buffer = new byte[1024];
- int read;
-
- while ((read = in.read(buffer)) != -1)
- {
- out.write(buffer, 0, read);
- }
- }
-}
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
new file mode 100644
index 0000000000..acd1f9f821
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/services/DirectoryInitializationService.java
@@ -0,0 +1,154 @@
+/**
+ * Copyright 2014 Dolphin Emulator Project
+ * Licensed under GPLv2+
+ * Refer to the license.txt file included.
+ */
+
+package org.dolphinemu.dolphinemu.services;
+
+import android.app.IntentService;
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.LocalBroadcastManager;
+
+import org.dolphinemu.dolphinemu.NativeLibrary;
+import org.dolphinemu.dolphinemu.utils.Log;
+import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A service that spawns its own thread in order to copy several binary and shader files
+ * from the Dolphin APK to the external file system.
+ */
+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;
+
+ public enum DirectoryInitializationState
+ {
+ DOLPHIN_DIRECTORIES_INITIALIZED,
+ EXTERNAL_STORAGE_PERMISSION_NEEDED
+ }
+
+ public DirectoryInitializationService()
+ {
+ // Superclass constructor is called to name the thread on which this service executes.
+ super("DirectoryInitializationService");
+ }
+
+ public static void startService(Context context)
+ {
+ Intent intent = new Intent(context, DirectoryInitializationService.class);
+ context.startService(intent);
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent)
+ {
+ if (directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
+ {
+ sendBroadcastState(DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED);
+ }
+ else if (PermissionsHandler.hasWriteAccess(this))
+ {
+ initDolphinDirectories();
+ directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
+ sendBroadcastState(directoryState);
+ }
+ else
+ {
+ sendBroadcastState(DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED);
+ }
+ }
+
+ private void initDolphinDirectories()
+ {
+ String BaseDir = NativeLibrary.GetUserDirectory();
+ String ConfigDir = BaseDir + File.separator + "Config";
+
+ // Copy assets if needed
+ NativeLibrary.CreateUserFolders();
+ copyAssetFolder("GC", BaseDir + File.separator + "GC", false);
+ copyAssetFolder("Shaders", BaseDir + File.separator + "Shaders", false);
+ copyAssetFolder("Wii", BaseDir + File.separator + "Wii", false);
+
+ // Always copy over the GCPad config in case of change or corruption.
+ // Not a user configurable file.
+ copyAsset("GCPadNew.ini", ConfigDir + File.separator + "GCPadNew.ini", true);
+ copyAsset("WiimoteNew.ini", ConfigDir + File.separator + "WiimoteNew.ini", true);
+ }
+
+ public static boolean areDolphinDirectoriesReady()
+ {
+ return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
+ }
+
+ private void sendBroadcastState(DirectoryInitializationState state)
+ {
+ Intent localIntent =
+ new Intent(BROADCAST_ACTION)
+ .putExtra(EXTRA_STATE, state);
+ LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
+ }
+
+ private void copyAsset(String asset, String output, Boolean overwrite)
+ {
+ Log.verbose("[DirectoryInitializationService] Copying File " + asset + " to " + output);
+ InputStream in;
+ OutputStream out;
+
+ try
+ {
+ File file = new File(output);
+ if (!file.exists() || overwrite)
+ {
+ in = getAssets().open(asset);
+ out = new FileOutputStream(output);
+ copyFile(in, out);
+ in.close();
+ out.close();
+ }
+ }
+ catch (IOException e)
+ {
+ Log.error("[DirectoryInitializationService] Failed to copy asset file: " + asset + e.getMessage());
+ }
+ }
+
+ private void copyAssetFolder(String assetFolder, String outputFolder, Boolean overwrite)
+ {
+ Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " + outputFolder);
+
+ try
+ {
+ for (String file : getAssets().list(assetFolder))
+ {
+ copyAssetFolder(assetFolder + File.separator + file, outputFolder + File.separator + file, overwrite);
+ copyAsset(assetFolder + File.separator + file, outputFolder + File.separator + file, overwrite);
+ }
+ }
+ catch (IOException e)
+ {
+ Log.error("[DirectoryInitializationService] Failed to copy asset folder: " + assetFolder + e.getMessage());
+ }
+ }
+
+ private void copyFile(InputStream in, OutputStream out) throws IOException
+ {
+ byte[] buffer = new byte[1024];
+ int read;
+
+ while ((read = in.read(buffer)) != -1)
+ {
+ out.write(buffer, 0, read);
+ }
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java
index 38c478480c..72a9477f00 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java
@@ -20,6 +20,7 @@ import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity;
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
import org.dolphinemu.dolphinemu.model.GameProvider;
+import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
@@ -154,7 +155,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
switch (requestCode) {
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- StartupHandler.copyAssetsIfNeeded(this);
+ DirectoryInitializationService.startService(this);
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
getSupportFragmentManager(), this);
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java
index 6e4dfa6063..cb72c34a3e 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java
@@ -28,6 +28,7 @@ import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
import org.dolphinemu.dolphinemu.model.Game;
import org.dolphinemu.dolphinemu.model.TvSettingsItem;
+import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
@@ -157,7 +158,7 @@ public final class TvMainActivity extends FragmentActivity implements MainView
switch (requestCode) {
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- StartupHandler.copyAssetsIfNeeded(this);
+ DirectoryInitializationService.startService(this);
loadGames();
} else {
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
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 43715cecba..cd942eb091 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
@@ -1,9 +1,12 @@
package org.dolphinemu.dolphinemu.ui.settings;
+import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
+import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
@@ -12,6 +15,8 @@ import android.widget.Toast;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
+import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
+import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
import java.util.ArrayList;
import java.util.HashMap;
@@ -22,6 +27,8 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
private static final String FRAGMENT_TAG = "settings";
private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this);
+ private ProgressDialog dialog;
+
public static void launch(Context context, String menuTag)
{
Intent settings = new Intent(context, SettingsActivity.class);
@@ -65,6 +72,13 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
mPresenter.saveState(outState);
}
+ @Override
+ protected void onStart()
+ {
+ super.onStart();
+ mPresenter.onStart();
+ }
+
/**
* If this is called, the user has left the settings screen (potentially through the
* home button) and will expect their changes to be persisted. So we kick off an
@@ -107,6 +121,47 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
}
@Override
+ public void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter)
+ {
+ LocalBroadcastManager.getInstance(this).registerReceiver(
+ receiver,
+ filter);
+ DirectoryInitializationService.startService(this);
+ }
+
+ @Override
+ public void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver)
+ {
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
+ }
+
+ @Override
+ public void showLoading()
+ {
+ if (dialog == null)
+ {
+ dialog = new ProgressDialog(this);
+ dialog.setMessage(getString(R.string.load_settings));
+ dialog.setIndeterminate(true);
+ }
+
+ dialog.show();
+ }
+
+ @Override
+ public void hideLoading()
+ {
+ dialog.dismiss();
+ }
+
+ @Override
+ public void showPermissionNeededHint()
+ {
+ Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ @Override
public HashMap<String, SettingSection> getSettings(int file)
{
return mPresenter.getSettings(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 9e68c00d20..20cf5bcc78 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
@@ -1,15 +1,20 @@
package org.dolphinemu.dolphinemu.ui.settings;
+import android.content.IntentFilter;
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.utils.DirectoryStateReceiver;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.SettingsFile;
import java.util.ArrayList;
import java.util.HashMap;
+import rx.functions.Action1;
+
public final class SettingsActivityPresenter
{
private static final String KEY_SHOULD_SAVE = "should_save";
@@ -22,6 +27,10 @@ public final class SettingsActivityPresenter
private boolean mShouldSave;
+ private DirectoryStateReceiver directoryStateReceiver;
+
+ private String menuTag;
+
public SettingsActivityPresenter(SettingsActivityView view)
{
mView = view;
@@ -31,12 +40,10 @@ public final class SettingsActivityPresenter
{
if (savedInstanceState == null)
{
- mView.showSettingsFragment(menuTag, false);
-
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.onSettingsFileLoaded(mSettings);
+ this.menuTag = menuTag;
}
else
{
@@ -44,6 +51,41 @@ public final class SettingsActivityPresenter
}
}
+ public void onStart()
+ {
+ prepareDolphinDirectoriesIfNeeded();
+ }
+
+ void loadSettingsUI()
+ {
+ mView.showSettingsFragment(menuTag, false);
+ mView.onSettingsFileLoaded(mSettings);
+ }
+
+ private void prepareDolphinDirectoriesIfNeeded()
+ {
+ if (DirectoryInitializationService.areDolphinDirectoriesReady()) {
+ loadSettingsUI();
+ } else {
+ mView.showLoading();
+ IntentFilter statusIntentFilter = new IntentFilter(
+ DirectoryInitializationService.BROADCAST_ACTION);
+
+ directoryStateReceiver =
+ new DirectoryStateReceiver(directoryInitializationState -> {
+ if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) {
+ mView.hideLoading();
+ loadSettingsUI();
+ } else if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) {
+ mView.showPermissionNeededHint();
+ mView.hideLoading();
+ }
+ });
+
+ mView.startDirectoryInitializationService(directoryStateReceiver, statusIntentFilter);
+ }
+ }
+
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings)
{
mSettings = settings;
@@ -56,6 +98,12 @@ public final class SettingsActivityPresenter
public void onStop(boolean finishing)
{
+ if (directoryStateReceiver != null)
+ {
+ mView.stopListeningToDirectoryInitializationService(directoryStateReceiver);
+ directoryStateReceiver = null;
+ }
+
if (mSettings != null && finishing && mShouldSave)
{
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
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 8c5d6b9731..686338eaee 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
@@ -1,6 +1,9 @@
package org.dolphinemu.dolphinemu.ui.settings;
+import android.content.IntentFilter;
+
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
+import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
import java.util.ArrayList;
import java.util.HashMap;
@@ -99,4 +102,34 @@ public interface SettingsActivityView
* @param value New setting for the extension.
*/
void onExtensionSettingChanged(String key, int value);
+
+ /**
+ * Show loading dialog while loading the settings
+ */
+ void showLoading();
+
+ /**
+ * Hide the loading the dialog
+ */
+ void hideLoading();
+
+ /**
+ * Show a hint to the user that the app needs write to external storage access
+ */
+ void showPermissionNeededHint();
+
+ /**
+ * Start the DirectoryInitializationService and listen for the result.
+ *
+ * @param receiver the broadcast receiver for the DirectoryInitializationService
+ * @param filter the Intent broadcasts to be received.
+ */
+ void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter);
+
+ /**
+ * Stop listening to the DirectoryInitializationService.
+ *
+ * @param receiver The broadcast receiver to unregister.
+ */
+ void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver);
}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryStateReceiver.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryStateReceiver.java
new file mode 100644
index 0000000000..ac00782366
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryStateReceiver.java
@@ -0,0 +1,24 @@
+package org.dolphinemu.dolphinemu.utils;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
+import org.dolphinemu.dolphinemu.services.DirectoryInitializationService.DirectoryInitializationState;
+
+import rx.functions.Action1;
+
+public class DirectoryStateReceiver extends BroadcastReceiver {
+ Action1<DirectoryInitializationState> callback;
+ public DirectoryStateReceiver(Action1<DirectoryInitializationState> callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent)
+ {
+ DirectoryInitializationState state = (DirectoryInitializationState) intent.getSerializableExtra(DirectoryInitializationService.EXTRA_STATE);
+ callback.call(state);
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java
index e569df112a..a38e33207a 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/PermissionsHandler.java
@@ -2,6 +2,7 @@ package org.dolphinemu.dolphinemu.utils;
import android.annotation.TargetApi;
import android.app.AlertDialog;
+import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Build;
@@ -40,9 +41,9 @@ public class PermissionsHandler {
return true;
}
- public static boolean hasWriteAccess(FragmentActivity activity) {
+ public static boolean hasWriteAccess(Context context) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- int hasWritePermission = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
+ int hasWritePermission = ContextCompat.checkSelfPermission(context, WRITE_EXTERNAL_STORAGE);
return hasWritePermission == PackageManager.PERMISSION_GRANTED;
}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java
index 34cde9e59c..398f569741 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/StartupHandler.java
@@ -1,15 +1,13 @@
package org.dolphinemu.dolphinemu.utils;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.os.Bundle;
-import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
-import org.dolphinemu.dolphinemu.services.AssetCopyService;
+import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
public final class StartupHandler
{
@@ -17,9 +15,8 @@ public final class StartupHandler
{
NativeLibrary.SetUserDirectory(""); // Auto-Detect
- // Only perform these extensive copy operations once.
if (PermissionsHandler.checkWritePermission(parent)) {
- copyAssetsIfNeeded(parent);
+ DirectoryInitializationService.startService(parent);
}
Intent intent = parent.getIntent();
@@ -45,16 +42,4 @@ public final class StartupHandler
}
return false;
}
-
- public static void copyAssetsIfNeeded(FragmentActivity parent) {
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(parent);
- boolean assetsCopied = preferences.getBoolean("assetsCopied", false);
-
- if (!assetsCopied)
- {
- // Copy assets into appropriate locations.
- Intent copyAssets = new Intent(parent, AssetCopyService.class);
- parent.startService(copyAssets);
- }
- }
}