Merge pull request #6258 from mahdihijazi/extract_service
[Android] Refactor AssetCopyService and the way we extract resources …
This commit is contained in:
commit
bfa7c14fef
|
@ -65,7 +65,7 @@
|
||||||
android:theme="@style/DolphinEmulationGamecube"/>
|
android:theme="@style/DolphinEmulationGamecube"/>
|
||||||
|
|
||||||
|
|
||||||
<service android:name=".services.AssetCopyService"/>
|
<service android:name=".services.DirectoryInitializationService"/>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name=".model.GameProvider"
|
android:name=".model.GameProvider"
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package org.dolphinemu.dolphinemu.fragments;
|
package org.dolphinemu.dolphinemu.fragments;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
|
@ -12,13 +14,19 @@ import android.view.SurfaceView;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
import org.dolphinemu.dolphinemu.overlay.InputOverlay;
|
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 org.dolphinemu.dolphinemu.utils.Log;
|
||||||
|
|
||||||
|
import rx.functions.Action1;
|
||||||
|
|
||||||
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
||||||
{
|
{
|
||||||
private static final String KEY_GAMEPATH = "gamepath";
|
private static final String KEY_GAMEPATH = "gamepath";
|
||||||
|
@ -29,6 +37,8 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
|
|
||||||
private EmulationState mEmulationState;
|
private EmulationState mEmulationState;
|
||||||
|
|
||||||
|
private DirectoryStateReceiver directoryStateReceiver;
|
||||||
|
|
||||||
public static EmulationFragment newInstance(String gamePath)
|
public static EmulationFragment newInstance(String gamePath)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -108,12 +118,25 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
public void onResume()
|
public void onResume()
|
||||||
{
|
{
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mEmulationState.run();
|
if (DirectoryInitializationService.areDolphinDirectoriesReady())
|
||||||
|
{
|
||||||
|
mEmulationState.run();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setupDolphinDirectoriesThenStartEmulation();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause()
|
public void onPause()
|
||||||
{
|
{
|
||||||
|
if (directoryStateReceiver != null)
|
||||||
|
{
|
||||||
|
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
|
||||||
|
directoryStateReceiver = null;
|
||||||
|
}
|
||||||
|
|
||||||
mEmulationState.pause();
|
mEmulationState.pause();
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
@ -125,6 +148,27 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
super.onDetach();
|
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()
|
public void toggleInputOverlayVisibility()
|
||||||
{
|
{
|
||||||
SharedPreferences.Editor editor = mPreferences.edit();
|
SharedPreferences.Editor editor = mPreferences.edit();
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity;
|
import org.dolphinemu.dolphinemu.activities.AddDirectoryActivity;
|
||||||
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
|
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
|
||||||
import org.dolphinemu.dolphinemu.model.GameProvider;
|
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.Platform;
|
||||||
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
|
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
|
||||||
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
|
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
|
||||||
|
@ -154,7 +155,7 @@ public final class MainActivity extends AppCompatActivity implements MainView
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
||||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
StartupHandler.copyAssetsIfNeeded(this);
|
DirectoryInitializationService.startService(this);
|
||||||
|
|
||||||
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
|
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
|
||||||
getSupportFragmentManager(), this);
|
getSupportFragmentManager(), this);
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
|
||||||
import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
|
import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
|
||||||
import org.dolphinemu.dolphinemu.model.Game;
|
import org.dolphinemu.dolphinemu.model.Game;
|
||||||
import org.dolphinemu.dolphinemu.model.TvSettingsItem;
|
import org.dolphinemu.dolphinemu.model.TvSettingsItem;
|
||||||
|
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
||||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
||||||
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
|
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
|
||||||
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
||||||
|
@ -157,7 +158,7 @@ public final class TvMainActivity extends FragmentActivity implements MainView
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
||||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
StartupHandler.copyAssetsIfNeeded(this);
|
DirectoryInitializationService.startService(this);
|
||||||
loadGames();
|
loadGames();
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
package org.dolphinemu.dolphinemu.ui.settings;
|
package org.dolphinemu.dolphinemu.ui.settings;
|
||||||
|
|
||||||
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
|
@ -12,6 +15,8 @@ import android.widget.Toast;
|
||||||
|
|
||||||
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.utils.DirectoryStateReceiver;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -22,6 +27,8 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
|
||||||
private static final String FRAGMENT_TAG = "settings";
|
private static final String FRAGMENT_TAG = "settings";
|
||||||
private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this);
|
private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this);
|
||||||
|
|
||||||
|
private ProgressDialog dialog;
|
||||||
|
|
||||||
public static void launch(Context context, String menuTag)
|
public static void launch(Context context, String menuTag)
|
||||||
{
|
{
|
||||||
Intent settings = new Intent(context, SettingsActivity.class);
|
Intent settings = new Intent(context, SettingsActivity.class);
|
||||||
|
@ -65,6 +72,13 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
|
||||||
mPresenter.saveState(outState);
|
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
|
* 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
|
* home button) and will expect their changes to be persisted. So we kick off an
|
||||||
|
@ -106,6 +120,47 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public HashMap<String, SettingSection> getSettings(int file)
|
public HashMap<String, SettingSection> getSettings(int file)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
package org.dolphinemu.dolphinemu.ui.settings;
|
package org.dolphinemu.dolphinemu.ui.settings;
|
||||||
|
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.os.Bundle;
|
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.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;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import rx.functions.Action1;
|
||||||
|
|
||||||
public final class SettingsActivityPresenter
|
public final class SettingsActivityPresenter
|
||||||
{
|
{
|
||||||
private static final String KEY_SHOULD_SAVE = "should_save";
|
private static final String KEY_SHOULD_SAVE = "should_save";
|
||||||
|
@ -22,6 +27,10 @@ public final class SettingsActivityPresenter
|
||||||
|
|
||||||
private boolean mShouldSave;
|
private boolean mShouldSave;
|
||||||
|
|
||||||
|
private DirectoryStateReceiver directoryStateReceiver;
|
||||||
|
|
||||||
|
private String menuTag;
|
||||||
|
|
||||||
public SettingsActivityPresenter(SettingsActivityView view)
|
public SettingsActivityPresenter(SettingsActivityView view)
|
||||||
{
|
{
|
||||||
mView = view;
|
mView = view;
|
||||||
|
@ -31,12 +40,10 @@ public final class SettingsActivityPresenter
|
||||||
{
|
{
|
||||||
if (savedInstanceState == null)
|
if (savedInstanceState == null)
|
||||||
{
|
{
|
||||||
mView.showSettingsFragment(menuTag, false);
|
|
||||||
|
|
||||||
mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile(SettingsFile.FILE_NAME_DOLPHIN, mView));
|
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_GFX, SettingsFile.readFile(SettingsFile.FILE_NAME_GFX, mView));
|
||||||
mSettings.add(SettingsFile.SETTINGS_WIIMOTE, SettingsFile.readFile(SettingsFile.FILE_NAME_WIIMOTE, mView));
|
mSettings.add(SettingsFile.SETTINGS_WIIMOTE, SettingsFile.readFile(SettingsFile.FILE_NAME_WIIMOTE, mView));
|
||||||
mView.onSettingsFileLoaded(mSettings);
|
this.menuTag = menuTag;
|
||||||
}
|
}
|
||||||
else
|
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)
|
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings)
|
||||||
{
|
{
|
||||||
mSettings = settings;
|
mSettings = settings;
|
||||||
|
@ -56,6 +98,12 @@ public final class SettingsActivityPresenter
|
||||||
|
|
||||||
public void onStop(boolean finishing)
|
public void onStop(boolean finishing)
|
||||||
{
|
{
|
||||||
|
if (directoryStateReceiver != null)
|
||||||
|
{
|
||||||
|
mView.stopListeningToDirectoryInitializationService(directoryStateReceiver);
|
||||||
|
directoryStateReceiver = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (mSettings != null && finishing && mShouldSave)
|
if (mSettings != null && finishing && mShouldSave)
|
||||||
{
|
{
|
||||||
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
|
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package org.dolphinemu.dolphinemu.ui.settings;
|
package org.dolphinemu.dolphinemu.ui.settings;
|
||||||
|
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
|
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
|
||||||
|
import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -99,4 +102,34 @@ public interface SettingsActivityView
|
||||||
* @param value New setting for the extension.
|
* @param value New setting for the extension.
|
||||||
*/
|
*/
|
||||||
void onExtensionSettingChanged(String key, int value);
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package org.dolphinemu.dolphinemu.utils;
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
@ -40,9 +41,9 @@ public class PermissionsHandler {
|
||||||
return true;
|
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) {
|
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;
|
return hasWritePermission == PackageManager.PERMISSION_GRANTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
package org.dolphinemu.dolphinemu.utils;
|
package org.dolphinemu.dolphinemu.utils;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.NativeLibrary;
|
import org.dolphinemu.dolphinemu.NativeLibrary;
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
import org.dolphinemu.dolphinemu.services.AssetCopyService;
|
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
||||||
|
|
||||||
public final class StartupHandler
|
public final class StartupHandler
|
||||||
{
|
{
|
||||||
|
@ -17,9 +15,8 @@ public final class StartupHandler
|
||||||
{
|
{
|
||||||
NativeLibrary.SetUserDirectory(""); // Auto-Detect
|
NativeLibrary.SetUserDirectory(""); // Auto-Detect
|
||||||
|
|
||||||
// Only perform these extensive copy operations once.
|
|
||||||
if (PermissionsHandler.checkWritePermission(parent)) {
|
if (PermissionsHandler.checkWritePermission(parent)) {
|
||||||
copyAssetsIfNeeded(parent);
|
DirectoryInitializationService.startService(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = parent.getIntent();
|
Intent intent = parent.getIntent();
|
||||||
|
@ -45,16 +42,4 @@ public final class StartupHandler
|
||||||
}
|
}
|
||||||
return false;
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,4 +247,6 @@
|
||||||
<string name="header_controllers">Controllers</string>
|
<string name="header_controllers">Controllers</string>
|
||||||
|
|
||||||
<string name="write_permission_needed">You need to allow write access to external storage for the emulator to work</string>
|
<string name="write_permission_needed">You need to allow write access to external storage for the emulator to work</string>
|
||||||
|
|
||||||
|
<string name="load_settings">Loading Settings...</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue