Skip to content

Commit

Permalink
Merge pull request #6225 from gwicks/android-game-settings
Browse files Browse the repository at this point in the history
Android: Implement user game-specific settings overrides.
  • Loading branch information
degasus committed Feb 19, 2018
2 parents 4876b9d + e19922c commit be1a736
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 37 deletions.
1 change: 0 additions & 1 deletion Source/Android/app/build.gradle
Expand Up @@ -96,7 +96,6 @@ dependencies {

// Allows FRP-style asynchronous operations in Android.
implementation 'io.reactivex:rxandroid:1.2.1'

implementation 'com.nononsenseapps:filepicker:4.1.0'
}

Expand Down
Expand Up @@ -11,6 +11,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.content.res.AssetManager;
import android.view.Surface;
import android.widget.Toast;

Expand Down Expand Up @@ -231,6 +232,12 @@ private NativeLibrary()
*/
public static native void onGamePadMoveEvent(String Device, int Axis, float Value);

public static native String GetUserSetting(String gameID, String Section, String Key);

public static native void SetUserSetting(String gameID, String Section, String Key, String Value);

public static native void InitGameIni(String gameID);

/**
* Gets a value from a key in the given ini-based config file.
*
Expand Down
@@ -1,5 +1,7 @@
package org.dolphinemu.dolphinemu.adapters;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.graphics.Rect;
Expand All @@ -8,15 +10,20 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.dialogs.GameDetailsDialog;
import org.dolphinemu.dolphinemu.model.GameDatabase;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.PicassoUtils;
import org.dolphinemu.dolphinemu.utils.SettingsFile;
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;

import java.io.File;

/**
* This adapter gets its information from a database Cursor. This fact, paired with the usage of
* ContentProviders and Loaders, allows for efficient display of a limited view into a (possibly)
Expand Down Expand Up @@ -222,17 +229,46 @@ public boolean onLongClick(View view)
GameViewHolder holder = (GameViewHolder) view.getTag();

// Get the ID of the game we want to look at.
// TODO This should be all we need to pass in, eventually.
// String gameId = (String) holder.gameId;
String gameId = (String) holder.gameId;

FragmentActivity activity = (FragmentActivity) view.getContext();
GameDetailsDialog.newInstance(holder.title,
holder.description,
holder.country,
holder.company,
holder.path,
holder.screenshotPath).show(activity.getSupportFragmentManager(), "game_details");


AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings")
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
SettingsActivity.launch(activity, SettingsFile.FILE_NAME_DOLPHIN, gameId);
break;
case 1:
SettingsActivity.launch(activity, SettingsFile.FILE_NAME_GFX, gameId);
break;
case 2:
String path = DirectoryInitializationService.getUserDirectory() + "/GameSettings/" + gameId + ".ini";
File gameSettingsFile = new File(path);
if (gameSettingsFile.exists())
{
if (gameSettingsFile.delete())
{
Toast.makeText(view.getContext(), "Cleared settings for " + gameId, Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(view.getContext(), "Unable to clear settings for " + gameId, Toast.LENGTH_SHORT).show();
}
}
else
{
Toast.makeText(view.getContext(), "No game settings to delete", Toast.LENGTH_SHORT).show();
}
break;
}
}
});

builder.show();
return true;
}

Expand Down
@@ -1,18 +1,28 @@
package org.dolphinemu.dolphinemu.adapters;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.support.v17.leanback.widget.ImageCardView;
import android.support.v17.leanback.widget.Presenter;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;

import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.Game;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.ui.settings.SettingsActivity;
import org.dolphinemu.dolphinemu.utils.PicassoUtils;
import org.dolphinemu.dolphinemu.utils.SettingsFile;
import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder;

import java.io.File;

/**
* The Leanback library / docs call this a Presenter, but it works very
* similarly to a RecyclerView.Adapter.
Expand Down Expand Up @@ -78,8 +88,54 @@ public void onBindViewHolder(ViewHolder viewHolder, Object item)
Context context = holder.cardParent.getContext();
Drawable background = ContextCompat.getDrawable(context, backgroundId);
holder.cardParent.setInfoAreaBackground(background);
holder.cardParent.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view)
{
FragmentActivity activity = (FragmentActivity) view.getContext();


AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings")
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
SettingsActivity.launch(activity, SettingsFile.FILE_NAME_DOLPHIN, game.getGameId());
break;
case 1:
SettingsActivity.launch(activity, SettingsFile.FILE_NAME_GFX, game.getGameId());
break;
case 2:
String path = DirectoryInitializationService.getUserDirectory() + "/GameSettings/" + game.getGameId() + ".ini";
File gameSettingsFile = new File(path);
if (gameSettingsFile.exists())
{
if (gameSettingsFile.delete())
{
Toast.makeText(view.getContext(), "Cleared settings for " + game.getGameId(), Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(view.getContext(), "Unable to clear settings for " + game.getGameId(), Toast.LENGTH_SHORT).show();
}
}
else
{
Toast.makeText(view.getContext(), "No game settings to delete", Toast.LENGTH_SHORT).show();
}
break;
}
}
});

builder.show();
return true;
}
});
}


@Override
public void onUnbindViewHolder(ViewHolder viewHolder)
{
Expand Down
Expand Up @@ -129,7 +129,7 @@ public void refreshFragmentScreenshot(int fragmentPosition)
@Override
public void launchSettingsActivity(String menuTag)
{
SettingsActivity.launch(this, menuTag);
SettingsActivity.launch(this, menuTag, "");
}

@Override
Expand Down
Expand Up @@ -123,7 +123,7 @@ public void refreshFragmentScreenshot(int fragmentPosition)
@Override
public void launchSettingsActivity(String menuTag)
{
SettingsActivity.launch(this, menuTag);
SettingsActivity.launch(this, menuTag, "");
}

@Override
Expand Down
Expand Up @@ -18,22 +18,27 @@
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 java.util.ArrayList;
import java.util.HashMap;

public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView
{
private static final String ARG_FILE_NAME = "file_name";
private static final String ARG_GAME_ID = "game_id";

private static final String FRAGMENT_TAG = "settings";
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, String gameId)
{
Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARG_FILE_NAME, menuTag);
settings.putExtra(ARG_GAME_ID, gameId);

context.startActivity(settings);
}

Expand All @@ -46,8 +51,9 @@ protected void onCreate(Bundle savedInstanceState)

Intent launcher = getIntent();
String filename = launcher.getStringExtra(ARG_FILE_NAME);
String gameID = launcher.getStringExtra(ARG_GAME_ID);

mPresenter.onCreate(savedInstanceState, filename);
mPresenter.onCreate(savedInstanceState, filename, gameID);
}

@Override
Expand Down Expand Up @@ -101,7 +107,7 @@ public void onBackPressed()


@Override
public void showSettingsFragment(String menuTag, boolean addToStack)
public void showSettingsFragment(String menuTag, boolean addToStack, String gameID)
{
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

Expand All @@ -119,7 +125,7 @@ public void showSettingsFragment(String menuTag, boolean addToStack)
transaction.addToBackStack(null);
mPresenter.addToStack();
}
transaction.replace(R.id.frame_content, SettingsFragment.newInstance(menuTag), FRAGMENT_TAG);
transaction.replace(R.id.frame_content, SettingsFragment.newInstance(menuTag, gameID), FRAGMENT_TAG);

transaction.commit();
}
Expand Down
Expand Up @@ -2,6 +2,7 @@

import android.content.IntentFilter;
import android.os.Bundle;
import android.text.TextUtils;

import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.settings.SettingSection;
Expand Down Expand Up @@ -31,17 +32,19 @@ public final class SettingsActivityPresenter
private DirectoryStateReceiver directoryStateReceiver;

private String menuTag;
private String gameId;

public SettingsActivityPresenter(SettingsActivityView view)
{
mView = view;
}

public void onCreate(Bundle savedInstanceState, String menuTag)
public void onCreate(Bundle savedInstanceState, String menuTag, String gameId)
{
if (savedInstanceState == null)
{
this.menuTag = menuTag;
this.gameId = gameId;
}
else
{
Expand All @@ -58,12 +61,21 @@ 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));
if (!TextUtils.isEmpty(gameId))
{
mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile("../GameSettings/" + gameId, mView));
mSettings.add(SettingsFile.SETTINGS_GFX, SettingsFile.readFile("../GameSettings/" + gameId, mView));
mSettings.add(SettingsFile.SETTINGS_WIIMOTE, SettingsFile.readFile("../GameSettings/" + gameId, mView));
}
else
{
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, gameId);
mView.onSettingsFileLoaded(mSettings);
}

Expand Down Expand Up @@ -120,11 +132,25 @@ public void onStop(boolean finishing)

if (mSettings != null && finishing && mShouldSave)
{
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
SettingsFile.saveFile(SettingsFile.FILE_NAME_DOLPHIN, mSettings.get(SettingsFile.SETTINGS_DOLPHIN), mView);
SettingsFile.saveFile(SettingsFile.FILE_NAME_GFX, mSettings.get(SettingsFile.SETTINGS_GFX), mView);
SettingsFile.saveFile(SettingsFile.FILE_NAME_WIIMOTE, mSettings.get(SettingsFile.SETTINGS_WIIMOTE), mView);
mView.showToastMessage("Saved settings to INI files");
if (!TextUtils.isEmpty(gameId)) {
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
// Needed workaround for now due to an odd bug in how it handles saving two different settings sections to the same file. It won't save GFX settings if it follows the normal saving pattern
if (menuTag.equals("Dolphin"))
{
SettingsFile.saveFile("../GameSettings/" + gameId, mSettings.get(SettingsFile.SETTINGS_DOLPHIN), mView);
}
else if (menuTag.equals("GFX"))
{
SettingsFile.saveFile("../GameSettings/" + gameId, mSettings.get(SettingsFile.SETTINGS_GFX), mView);
}
mView.showToastMessage("Saved settings for " + gameId);
} else {
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
SettingsFile.saveFile(SettingsFile.FILE_NAME_DOLPHIN, mSettings.get(SettingsFile.SETTINGS_DOLPHIN), mView);
SettingsFile.saveFile(SettingsFile.FILE_NAME_GFX, mSettings.get(SettingsFile.SETTINGS_GFX), mView);
SettingsFile.saveFile(SettingsFile.FILE_NAME_WIIMOTE, mSettings.get(SettingsFile.SETTINGS_WIIMOTE), mView);
mView.showToastMessage("Saved settings to INI files");
}
}
}

Expand Down Expand Up @@ -172,7 +198,7 @@ public void onGcPadSettingChanged(String key, int value)
{
if (value != 0) // Not disabled
{
mView.showSettingsFragment(key + (value / 6), true);
mView.showSettingsFragment(key + (value / 6), true, gameId);
}
}

Expand All @@ -181,7 +207,7 @@ public void onWiimoteSettingChanged(String section, int value)
switch (value)
{
case 1:
mView.showSettingsFragment(section, true);
mView.showSettingsFragment(section, true, gameId);
break;

case 2:
Expand All @@ -194,7 +220,7 @@ public void onExtensionSettingChanged(String key, int value)
{
if (value != 0) // None
{
mView.showSettingsFragment(key + value, true);
mView.showSettingsFragment(key + value, true, gameId);
}
}
}
Expand Up @@ -19,7 +19,7 @@ public interface SettingsActivityView
* @param menuTag Identifier for the settings group that should be displayed.
* @param addToStack Whether or not this fragment should replace a previous one.
*/
void showSettingsFragment(String menuTag, boolean addToStack);
void showSettingsFragment(String menuTag, boolean addToStack, String gameId);

/**
* Called by a contained Fragment to get access to the Setting HashMap
Expand Down

0 comments on commit be1a736

Please sign in to comment.