@@ -28,6 +28,7 @@
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 void onRequestPermissionsResult(int requestCode, String[] permissions, in
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)
@@ -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 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 @@ protected void onSaveInstanceState(Bundle 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
* home button) and will expect their changes to be persisted. So we kick off an
@@ -106,6 +120,47 @@ public void showSettingsFragment(String menuTag, boolean addToStack)
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
public HashMap<String, SettingSection> getSettings(int file)
{
@@ -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 @@

private boolean mShouldSave;

private DirectoryStateReceiver directoryStateReceiver;

private String menuTag;

public SettingsActivityPresenter(SettingsActivityView view)
{
mView = view;
@@ -31,19 +40,52 @@ public void onCreate(Bundle savedInstanceState, String menuTag)
{
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
{
mShouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
}
}

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 HashMap<String, SettingSection> getSettings(int file)

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...");
@@ -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 @@
* @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);
}
@@ -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 @@

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 static boolean checkWritePermission(final FragmentActivity activity) {
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;
}

@@ -1,25 +1,22 @@
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
{
public static boolean HandleInit(FragmentActivity parent)
{
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 static boolean HandleInit(FragmentActivity parent)
}
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="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>