android: frontend: auto-reformat all code for consistent style.
This commit is contained in:
parent
59b4d4dda7
commit
0011a432bf
@ -6,18 +6,16 @@ import org.citra.citra_android.model.GameDatabase;
|
||||
import org.citra.citra_android.services.DirectoryInitializationService;
|
||||
import org.citra.citra_android.utils.PermissionsHandler;
|
||||
|
||||
public class DolphinApplication extends Application
|
||||
{
|
||||
public static GameDatabase databaseHelper;
|
||||
public class DolphinApplication extends Application {
|
||||
public static GameDatabase databaseHelper;
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
if (PermissionsHandler.hasWriteAccess(getApplicationContext()))
|
||||
DirectoryInitializationService.startService(getApplicationContext());
|
||||
if (PermissionsHandler.hasWriteAccess(getApplicationContext()))
|
||||
DirectoryInitializationService.startService(getApplicationContext());
|
||||
|
||||
databaseHelper = new GameDatabase(this);
|
||||
}
|
||||
databaseHelper = new GameDatabase(this);
|
||||
}
|
||||
}
|
||||
|
@ -18,411 +18,385 @@ import java.lang.ref.WeakReference;
|
||||
* Class which contains methods that interact
|
||||
* with the native side of the Dolphin code.
|
||||
*/
|
||||
public final class NativeLibrary
|
||||
{
|
||||
public static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
|
||||
public final class NativeLibrary {
|
||||
/**
|
||||
* Default touchscreen device
|
||||
*/
|
||||
public static final String TouchScreenDevice = "Touchscreen";
|
||||
public static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
|
||||
private static boolean alertResult = false;
|
||||
|
||||
/**
|
||||
* Button type for use in onTouchEvent
|
||||
*/
|
||||
public static final class ButtonType
|
||||
{
|
||||
public static final int BUTTON_A = 700;
|
||||
public static final int BUTTON_B = 701;
|
||||
public static final int BUTTON_X = 702;
|
||||
public static final int BUTTON_Y = 703;
|
||||
public static final int BUTTON_START = 704;
|
||||
public static final int BUTTON_SELECT = 705;
|
||||
public static final int BUTTON_HOME = 706;
|
||||
public static final int BUTTON_ZL = 707;
|
||||
public static final int BUTTON_ZR = 708;
|
||||
public static final int DPAD_UP = 709;
|
||||
public static final int DPAD_DOWN = 710;
|
||||
public static final int DPAD_LEFT = 711;
|
||||
public static final int DPAD_RIGHT = 712;
|
||||
public static final int STICK_LEFT = 713;
|
||||
public static final int STICK_LEFT_UP = 714;
|
||||
public static final int STICK_LEFT_DOWN = 715;
|
||||
public static final int STICK_LEFT_LEFT = 716;
|
||||
public static final int STICK_LEFT_RIGHT = 717;
|
||||
public static final int STICK_C = 718;
|
||||
public static final int STICK_C_UP = 719;
|
||||
public static final int STICK_C_DOWN = 720;
|
||||
public static final int STICK_C_LEFT = 771;
|
||||
public static final int STICK_C_RIGHT = 772;
|
||||
public static final int TRIGGER_L = 773;
|
||||
public static final int TRIGGER_R = 774;
|
||||
}
|
||||
|
||||
/**
|
||||
* Button states
|
||||
*/
|
||||
public static final class ButtonState
|
||||
{
|
||||
public static final int RELEASED = 0;
|
||||
public static final int PRESSED = 1;
|
||||
}
|
||||
|
||||
private NativeLibrary()
|
||||
{
|
||||
// Disallows instantiation.
|
||||
}
|
||||
|
||||
/**
|
||||
* Default touchscreen device
|
||||
*/
|
||||
public static final String TouchScreenDevice = "Touchscreen";
|
||||
|
||||
/**
|
||||
* Handles button press events for a gamepad.
|
||||
*
|
||||
* @param Device The input descriptor of the gamepad.
|
||||
* @param Button Key code identifying which button was pressed.
|
||||
* @param Action Mask identifying which action is happening (button pressed down, or button released).
|
||||
* @return If we handled the button press.
|
||||
*/
|
||||
public static native boolean onGamePadEvent(String Device, int Button, int Action);
|
||||
|
||||
/**
|
||||
* Handles gamepad movement events.
|
||||
*
|
||||
* @param Device The device ID of the gamepad.
|
||||
* @param Axis The axis ID
|
||||
* @param x_axis The value of the x-axis represented by the given ID.
|
||||
* @param y_axis The value of the y-axis represented by the given ID
|
||||
*/
|
||||
public static native boolean onGamePadMoveEvent(String Device, int Axis, float x_axis, float y_axis);
|
||||
|
||||
/**
|
||||
* Handles gamepad movement events.
|
||||
*
|
||||
* @param Device The device ID of the gamepad.
|
||||
* @param Axis_id The axis ID
|
||||
* @param axis_val The value of the axis represented by the given ID.
|
||||
*/
|
||||
public static native boolean onGamePadAxisEvent(String Device, int Axis_id, float axis_val);
|
||||
|
||||
/**
|
||||
* Handles touch events.
|
||||
*
|
||||
* @param x_axis The value of the x-axis.
|
||||
* @param y_axis The value of the y-axis
|
||||
* @param pressed To identify if the touch held down or released.
|
||||
*/
|
||||
public static native void onTouchEvent(float x_axis, float y_axis, boolean pressed);
|
||||
|
||||
/**
|
||||
* Handles touch movement.
|
||||
*
|
||||
* @param x_axis The value of the instantaneous x-axis.
|
||||
* @param y_axis The value of the instantaneous y-axis.
|
||||
*/
|
||||
public static native void onTouchMoved(float x_axis, float y_axis);
|
||||
|
||||
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.
|
||||
*
|
||||
* @param configFile The ini-based config file to get the value from.
|
||||
* @param Section The section key that the actual key is in.
|
||||
* @param Key The key to get the value from.
|
||||
* @param Default The value to return in the event the given key doesn't exist.
|
||||
* @return the value stored at the key, or a default value if it doesn't exist.
|
||||
*/
|
||||
public static native String GetConfig(String configFile, String Section, String Key,
|
||||
String Default);
|
||||
|
||||
/**
|
||||
* Sets a value to a key in the given ini config file.
|
||||
*
|
||||
* @param configFile The ini-based config file to add the value to.
|
||||
* @param Section The section key for the ini key
|
||||
* @param Key The actual ini key to set.
|
||||
* @param Value The string to set the ini key to.
|
||||
*/
|
||||
public static native void SetConfig(String configFile, String Section, String Key, String Value);
|
||||
|
||||
/**
|
||||
* Gets the embedded banner within the given ISO/ROM.
|
||||
*
|
||||
* @param filename the file path to the ISO/ROM.
|
||||
* @return an integer array containing the color data for the banner.
|
||||
*/
|
||||
public static native int[] GetBanner(String filename);
|
||||
|
||||
/**
|
||||
* Gets the embedded title of the given ISO/ROM.
|
||||
*
|
||||
* @param filename The file path to the ISO/ROM.
|
||||
* @return the embedded title of the ISO/ROM.
|
||||
*/
|
||||
public static native String GetTitle(String filename);
|
||||
|
||||
public static native String GetDescription(String filename);
|
||||
|
||||
public static native String GetGameId(String filename);
|
||||
|
||||
public static native int GetCountry(String filename);
|
||||
|
||||
public static native String GetCompany(String filename);
|
||||
|
||||
public static native long GetFilesize(String filename);
|
||||
|
||||
public static native int GetPlatform(String filename);
|
||||
|
||||
/**
|
||||
* Gets the Dolphin version string.
|
||||
*
|
||||
* @return the Dolphin version string.
|
||||
*/
|
||||
public static native String GetVersionString();
|
||||
|
||||
public static native String GetGitRevision();
|
||||
|
||||
/**
|
||||
* Saves a screen capture of the game
|
||||
*/
|
||||
public static native void SaveScreenShot();
|
||||
|
||||
/**
|
||||
* Saves a game state to the slot number.
|
||||
*
|
||||
* @param slot The slot location to save state to.
|
||||
* @param wait If false, returns as early as possible.
|
||||
* If true, returns once the savestate has been written to disk.
|
||||
*/
|
||||
public static native void SaveState(int slot, boolean wait);
|
||||
|
||||
/**
|
||||
* Saves a game state to the specified path.
|
||||
*
|
||||
* @param path The path to save state to.
|
||||
* @param wait If false, returns as early as possible.
|
||||
* If true, returns once the savestate has been written to disk.
|
||||
*/
|
||||
public static native void SaveStateAs(String path, boolean wait);
|
||||
|
||||
/**
|
||||
* Loads a game state from the slot number.
|
||||
*
|
||||
* @param slot The slot location to load state from.
|
||||
*/
|
||||
public static native void LoadState(int slot);
|
||||
|
||||
/**
|
||||
* Loads a game state from the specified path.
|
||||
*
|
||||
* @param path The path to load state from.
|
||||
*/
|
||||
public static native void LoadStateAs(String path);
|
||||
|
||||
/**
|
||||
* Sets the current working user directory
|
||||
* If not set, it auto-detects a location
|
||||
*/
|
||||
public static native void SetUserDirectory(String directory);
|
||||
|
||||
/**
|
||||
* Returns the current working user directory
|
||||
*/
|
||||
public static native String GetUserDirectory();
|
||||
|
||||
// Create the config.ini file.
|
||||
public static native void CreateConfigFile();
|
||||
|
||||
public static native int DefaultCPUCore();
|
||||
|
||||
/**
|
||||
* Begins emulation.
|
||||
*/
|
||||
public static native void Run(String path);
|
||||
|
||||
/**
|
||||
* Begins emulation from the specified savestate.
|
||||
*/
|
||||
public static native void Run(String path, String savestatePath, boolean deleteSavestate);
|
||||
|
||||
public static native void ChangeDisc(String path);
|
||||
|
||||
// Surface Handling
|
||||
public static native void SurfaceChanged(Surface surf);
|
||||
|
||||
public static native void SurfaceDestroyed();
|
||||
|
||||
/**
|
||||
* Unpauses emulation from a paused state.
|
||||
*/
|
||||
public static native void UnPauseEmulation();
|
||||
|
||||
/**
|
||||
* Pauses emulation.
|
||||
*/
|
||||
public static native void PauseEmulation();
|
||||
|
||||
/**
|
||||
* Stops emulation.
|
||||
*/
|
||||
public static native void StopEmulation();
|
||||
|
||||
/**
|
||||
* Returns true if emulation is running (or is paused).
|
||||
*/
|
||||
public static native boolean IsRunning();
|
||||
|
||||
/**
|
||||
* Enables or disables CPU block profiling
|
||||
*
|
||||
* @param enable
|
||||
*/
|
||||
public static native void SetProfiling(boolean enable);
|
||||
|
||||
/**
|
||||
* Writes out the block profile results
|
||||
*/
|
||||
public static native void WriteProfileResults();
|
||||
|
||||
/**
|
||||
* Native EGL functions not exposed by Java bindings
|
||||
**/
|
||||
public static native void eglBindAPI(int api);
|
||||
|
||||
/**
|
||||
* Provides a way to refresh the connections on Wiimotes
|
||||
*/
|
||||
public static native void RefreshWiimotes();
|
||||
|
||||
/**
|
||||
* Returns the performance stats for the current game
|
||||
**/
|
||||
public static native double[] GetPerfStats();
|
||||
|
||||
/**
|
||||
* The methods C++ uses to find references to Java classes and methods
|
||||
* are really expensive. Rather than calling them every time we want to
|
||||
* run them, do it once when we load the native library.
|
||||
*/
|
||||
private static native void CacheClassesAndMethods();
|
||||
|
||||
/**
|
||||
* Switches the screen layout.
|
||||
*/
|
||||
public static native void SwitchScreenLayout();
|
||||
|
||||
/**
|
||||
* Swaps the top and bottom screens.
|
||||
*/
|
||||
public static native void SwapScreens();
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
System.loadLibrary("main");
|
||||
}
|
||||
catch (UnsatisfiedLinkError ex)
|
||||
{
|
||||
Log.error("[NativeLibrary] " + ex.toString());
|
||||
}
|
||||
|
||||
CacheClassesAndMethods();
|
||||
}
|
||||
|
||||
private static boolean alertResult = false;
|
||||
|
||||
public static boolean displayAlertMsg(final String caption, final String text,
|
||||
final boolean yesNo)
|
||||
{
|
||||
Log.error("[NativeLibrary] Alert: " + text);
|
||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
||||
boolean result = false;
|
||||
if (emulationActivity == null)
|
||||
{
|
||||
Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create object used for waiting.
|
||||
final Object lock = new Object();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
|
||||
.setTitle(caption)
|
||||
.setMessage(text);
|
||||
|
||||
// If not yes/no dialog just have one button that dismisses modal,
|
||||
// otherwise have a yes and no button that sets alertResult accordingly.
|
||||
if (!yesNo)
|
||||
{
|
||||
builder
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("OK", (dialog, whichButton) ->
|
||||
{
|
||||
dialog.dismiss();
|
||||
synchronized (lock)
|
||||
{
|
||||
lock.notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
alertResult = false;
|
||||
|
||||
builder
|
||||
.setPositiveButton("Yes", (dialog, whichButton) ->
|
||||
{
|
||||
alertResult = true;
|
||||
dialog.dismiss();
|
||||
synchronized (lock)
|
||||
{
|
||||
lock.notify();
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", (dialog, whichButton) ->
|
||||
{
|
||||
alertResult = false;
|
||||
dialog.dismiss();
|
||||
synchronized (lock)
|
||||
{
|
||||
lock.notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Show the AlertDialog on the main thread.
|
||||
emulationActivity.runOnUiThread(() -> builder.show());
|
||||
|
||||
// Wait for the lock to notify that it is complete.
|
||||
synchronized (lock)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock.wait();
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("main");
|
||||
} catch (UnsatisfiedLinkError ex) {
|
||||
Log.error("[NativeLibrary] " + ex.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (yesNo)
|
||||
result = alertResult;
|
||||
CacheClassesAndMethods();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void setEmulationActivity(EmulationActivity emulationActivity)
|
||||
{
|
||||
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
|
||||
sEmulationActivity = new WeakReference<>(emulationActivity);
|
||||
}
|
||||
private NativeLibrary() {
|
||||
// Disallows instantiation.
|
||||
}
|
||||
|
||||
public static void clearEmulationActivity()
|
||||
{
|
||||
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.");
|
||||
/**
|
||||
* Handles button press events for a gamepad.
|
||||
*
|
||||
* @param Device The input descriptor of the gamepad.
|
||||
* @param Button Key code identifying which button was pressed.
|
||||
* @param Action Mask identifying which action is happening (button pressed down, or button released).
|
||||
* @return If we handled the button press.
|
||||
*/
|
||||
public static native boolean onGamePadEvent(String Device, int Button, int Action);
|
||||
|
||||
sEmulationActivity.clear();
|
||||
}
|
||||
/**
|
||||
* Handles gamepad movement events.
|
||||
*
|
||||
* @param Device The device ID of the gamepad.
|
||||
* @param Axis The axis ID
|
||||
* @param x_axis The value of the x-axis represented by the given ID.
|
||||
* @param y_axis The value of the y-axis represented by the given ID
|
||||
*/
|
||||
public static native boolean onGamePadMoveEvent(String Device, int Axis, float x_axis, float y_axis);
|
||||
|
||||
/**
|
||||
* Handles gamepad movement events.
|
||||
*
|
||||
* @param Device The device ID of the gamepad.
|
||||
* @param Axis_id The axis ID
|
||||
* @param axis_val The value of the axis represented by the given ID.
|
||||
*/
|
||||
public static native boolean onGamePadAxisEvent(String Device, int Axis_id, float axis_val);
|
||||
|
||||
/**
|
||||
* Handles touch events.
|
||||
*
|
||||
* @param x_axis The value of the x-axis.
|
||||
* @param y_axis The value of the y-axis
|
||||
* @param pressed To identify if the touch held down or released.
|
||||
*/
|
||||
public static native void onTouchEvent(float x_axis, float y_axis, boolean pressed);
|
||||
|
||||
/**
|
||||
* Handles touch movement.
|
||||
*
|
||||
* @param x_axis The value of the instantaneous x-axis.
|
||||
* @param y_axis The value of the instantaneous y-axis.
|
||||
*/
|
||||
public static native void onTouchMoved(float x_axis, float y_axis);
|
||||
|
||||
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.
|
||||
*
|
||||
* @param configFile The ini-based config file to get the value from.
|
||||
* @param Section The section key that the actual key is in.
|
||||
* @param Key The key to get the value from.
|
||||
* @param Default The value to return in the event the given key doesn't exist.
|
||||
* @return the value stored at the key, or a default value if it doesn't exist.
|
||||
*/
|
||||
public static native String GetConfig(String configFile, String Section, String Key,
|
||||
String Default);
|
||||
|
||||
/**
|
||||
* Sets a value to a key in the given ini config file.
|
||||
*
|
||||
* @param configFile The ini-based config file to add the value to.
|
||||
* @param Section The section key for the ini key
|
||||
* @param Key The actual ini key to set.
|
||||
* @param Value The string to set the ini key to.
|
||||
*/
|
||||
public static native void SetConfig(String configFile, String Section, String Key, String Value);
|
||||
|
||||
/**
|
||||
* Gets the embedded banner within the given ISO/ROM.
|
||||
*
|
||||
* @param filename the file path to the ISO/ROM.
|
||||
* @return an integer array containing the color data for the banner.
|
||||
*/
|
||||
public static native int[] GetBanner(String filename);
|
||||
|
||||
/**
|
||||
* Gets the embedded title of the given ISO/ROM.
|
||||
*
|
||||
* @param filename The file path to the ISO/ROM.
|
||||
* @return the embedded title of the ISO/ROM.
|
||||
*/
|
||||
public static native String GetTitle(String filename);
|
||||
|
||||
public static native String GetDescription(String filename);
|
||||
|
||||
public static native String GetGameId(String filename);
|
||||
|
||||
public static native int GetCountry(String filename);
|
||||
|
||||
public static native String GetCompany(String filename);
|
||||
|
||||
public static native long GetFilesize(String filename);
|
||||
|
||||
public static native int GetPlatform(String filename);
|
||||
|
||||
/**
|
||||
* Gets the Dolphin version string.
|
||||
*
|
||||
* @return the Dolphin version string.
|
||||
*/
|
||||
public static native String GetVersionString();
|
||||
|
||||
public static native String GetGitRevision();
|
||||
|
||||
/**
|
||||
* Saves a screen capture of the game
|
||||
*/
|
||||
public static native void SaveScreenShot();
|
||||
|
||||
/**
|
||||
* Saves a game state to the slot number.
|
||||
*
|
||||
* @param slot The slot location to save state to.
|
||||
* @param wait If false, returns as early as possible.
|
||||
* If true, returns once the savestate has been written to disk.
|
||||
*/
|
||||
public static native void SaveState(int slot, boolean wait);
|
||||
|
||||
/**
|
||||
* Saves a game state to the specified path.
|
||||
*
|
||||
* @param path The path to save state to.
|
||||
* @param wait If false, returns as early as possible.
|
||||
* If true, returns once the savestate has been written to disk.
|
||||
*/
|
||||
public static native void SaveStateAs(String path, boolean wait);
|
||||
|
||||
/**
|
||||
* Loads a game state from the slot number.
|
||||
*
|
||||
* @param slot The slot location to load state from.
|
||||
*/
|
||||
public static native void LoadState(int slot);
|
||||
|
||||
/**
|
||||
* Loads a game state from the specified path.
|
||||
*
|
||||
* @param path The path to load state from.
|
||||
*/
|
||||
public static native void LoadStateAs(String path);
|
||||
|
||||
/**
|
||||
* Sets the current working user directory
|
||||
* If not set, it auto-detects a location
|
||||
*/
|
||||
public static native void SetUserDirectory(String directory);
|
||||
|
||||
/**
|
||||
* Returns the current working user directory
|
||||
*/
|
||||
public static native String GetUserDirectory();
|
||||
|
||||
// Create the config.ini file.
|
||||
public static native void CreateConfigFile();
|
||||
|
||||
public static native int DefaultCPUCore();
|
||||
|
||||
/**
|
||||
* Begins emulation.
|
||||
*/
|
||||
public static native void Run(String path);
|
||||
|
||||
/**
|
||||
* Begins emulation from the specified savestate.
|
||||
*/
|
||||
public static native void Run(String path, String savestatePath, boolean deleteSavestate);
|
||||
|
||||
public static native void ChangeDisc(String path);
|
||||
|
||||
// Surface Handling
|
||||
public static native void SurfaceChanged(Surface surf);
|
||||
|
||||
public static native void SurfaceDestroyed();
|
||||
|
||||
/**
|
||||
* Unpauses emulation from a paused state.
|
||||
*/
|
||||
public static native void UnPauseEmulation();
|
||||
|
||||
/**
|
||||
* Pauses emulation.
|
||||
*/
|
||||
public static native void PauseEmulation();
|
||||
|
||||
/**
|
||||
* Stops emulation.
|
||||
*/
|
||||
public static native void StopEmulation();
|
||||
|
||||
/**
|
||||
* Returns true if emulation is running (or is paused).
|
||||
*/
|
||||
public static native boolean IsRunning();
|
||||
|
||||
/**
|
||||
* Enables or disables CPU block profiling
|
||||
*
|
||||
* @param enable
|
||||
*/
|
||||
public static native void SetProfiling(boolean enable);
|
||||
|
||||
/**
|
||||
* Writes out the block profile results
|
||||
*/
|
||||
public static native void WriteProfileResults();
|
||||
|
||||
/**
|
||||
* Native EGL functions not exposed by Java bindings
|
||||
**/
|
||||
public static native void eglBindAPI(int api);
|
||||
|
||||
/**
|
||||
* Provides a way to refresh the connections on Wiimotes
|
||||
*/
|
||||
public static native void RefreshWiimotes();
|
||||
|
||||
/**
|
||||
* Returns the performance stats for the current game
|
||||
**/
|
||||
public static native double[] GetPerfStats();
|
||||
|
||||
/**
|
||||
* The methods C++ uses to find references to Java classes and methods
|
||||
* are really expensive. Rather than calling them every time we want to
|
||||
* run them, do it once when we load the native library.
|
||||
*/
|
||||
private static native void CacheClassesAndMethods();
|
||||
|
||||
/**
|
||||
* Switches the screen layout.
|
||||
*/
|
||||
public static native void SwitchScreenLayout();
|
||||
|
||||
/**
|
||||
* Swaps the top and bottom screens.
|
||||
*/
|
||||
public static native void SwapScreens();
|
||||
|
||||
public static boolean displayAlertMsg(final String caption, final String text,
|
||||
final boolean yesNo) {
|
||||
Log.error("[NativeLibrary] Alert: " + text);
|
||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
||||
boolean result = false;
|
||||
if (emulationActivity == null) {
|
||||
Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert.");
|
||||
} else {
|
||||
// Create object used for waiting.
|
||||
final Object lock = new Object();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
|
||||
.setTitle(caption)
|
||||
.setMessage(text);
|
||||
|
||||
// If not yes/no dialog just have one button that dismisses modal,
|
||||
// otherwise have a yes and no button that sets alertResult accordingly.
|
||||
if (!yesNo) {
|
||||
builder
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("OK", (dialog, whichButton) ->
|
||||
{
|
||||
dialog.dismiss();
|
||||
synchronized (lock) {
|
||||
lock.notify();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
alertResult = false;
|
||||
|
||||
builder
|
||||
.setPositiveButton("Yes", (dialog, whichButton) ->
|
||||
{
|
||||
alertResult = true;
|
||||
dialog.dismiss();
|
||||
synchronized (lock) {
|
||||
lock.notify();
|
||||
}
|
||||
})
|
||||
.setNegativeButton("No", (dialog, whichButton) ->
|
||||
{
|
||||
alertResult = false;
|
||||
dialog.dismiss();
|
||||
synchronized (lock) {
|
||||
lock.notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Show the AlertDialog on the main thread.
|
||||
emulationActivity.runOnUiThread(() -> builder.show());
|
||||
|
||||
// Wait for the lock to notify that it is complete.
|
||||
synchronized (lock) {
|
||||
try {
|
||||
lock.wait();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (yesNo)
|
||||
result = alertResult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void setEmulationActivity(EmulationActivity emulationActivity) {
|
||||
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
|
||||
sEmulationActivity = new WeakReference<>(emulationActivity);
|
||||
}
|
||||
|
||||
public static void clearEmulationActivity() {
|
||||
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.");
|
||||
|
||||
sEmulationActivity.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Button type for use in onTouchEvent
|
||||
*/
|
||||
public static final class ButtonType {
|
||||
public static final int BUTTON_A = 700;
|
||||
public static final int BUTTON_B = 701;
|
||||
public static final int BUTTON_X = 702;
|
||||
public static final int BUTTON_Y = 703;
|
||||
public static final int BUTTON_START = 704;
|
||||
public static final int BUTTON_SELECT = 705;
|
||||
public static final int BUTTON_HOME = 706;
|
||||
public static final int BUTTON_ZL = 707;
|
||||
public static final int BUTTON_ZR = 708;
|
||||
public static final int DPAD_UP = 709;
|
||||
public static final int DPAD_DOWN = 710;
|
||||
public static final int DPAD_LEFT = 711;
|
||||
public static final int DPAD_RIGHT = 712;
|
||||
public static final int STICK_LEFT = 713;
|
||||
public static final int STICK_LEFT_UP = 714;
|
||||
public static final int STICK_LEFT_DOWN = 715;
|
||||
public static final int STICK_LEFT_LEFT = 716;
|
||||
public static final int STICK_LEFT_RIGHT = 717;
|
||||
public static final int STICK_C = 718;
|
||||
public static final int STICK_C_UP = 719;
|
||||
public static final int STICK_C_DOWN = 720;
|
||||
public static final int STICK_C_LEFT = 771;
|
||||
public static final int STICK_C_RIGHT = 772;
|
||||
public static final int TRIGGER_L = 773;
|
||||
public static final int TRIGGER_R = 774;
|
||||
}
|
||||
|
||||
/**
|
||||
* Button states
|
||||
*/
|
||||
public static final class ButtonState {
|
||||
public static final int RELEASED = 0;
|
||||
public static final int PRESSED = 1;
|
||||
}
|
||||
}
|
||||
|
@ -10,20 +10,17 @@ import org.citra.citra_android.fragments.CustomFilePickerFragment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class CustomFilePickerActivity extends FilePickerActivity
|
||||
|
||||
{
|
||||
@Override
|
||||
protected AbstractFilePickerFragment<File> getFragment(
|
||||
@Nullable final String startPath, final int mode, final boolean allowMultiple,
|
||||
final boolean allowCreateDir, final boolean allowExistingFile,
|
||||
final boolean singleClick)
|
||||
{
|
||||
AbstractFilePickerFragment<File> fragment = new CustomFilePickerFragment();
|
||||
// startPath is allowed to be null. In that case, default folder should be SD-card and not "/"
|
||||
fragment.setArgs(
|
||||
startPath != null ? startPath : Environment.getExternalStorageDirectory().getPath(),
|
||||
mode, allowMultiple, allowCreateDir, allowExistingFile, singleClick);
|
||||
return fragment;
|
||||
}
|
||||
public class CustomFilePickerActivity extends FilePickerActivity {
|
||||
@Override
|
||||
protected AbstractFilePickerFragment<File> getFragment(
|
||||
@Nullable final String startPath, final int mode, final boolean allowMultiple,
|
||||
final boolean allowCreateDir, final boolean allowExistingFile,
|
||||
final boolean singleClick) {
|
||||
AbstractFilePickerFragment<File> fragment = new CustomFilePickerFragment();
|
||||
// startPath is allowed to be null. In that case, default folder should be SD-card and not "/"
|
||||
fragment.setArgs(
|
||||
startPath != null ? startPath : Environment.getExternalStorageDirectory().getPath(),
|
||||
mode, allowMultiple, allowCreateDir, allowExistingFile, singleClick);
|
||||
return fragment;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,230 +22,200 @@ import org.citra.citra_android.viewholders.GameViewHolder;
|
||||
* large dataset.
|
||||
*/
|
||||
public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> implements
|
||||
View.OnClickListener
|
||||
{
|
||||
private Cursor mCursor;
|
||||
private GameDataSetObserver mObserver;
|
||||
View.OnClickListener {
|
||||
private Cursor mCursor;
|
||||
private GameDataSetObserver mObserver;
|
||||
|
||||
private boolean mDatasetValid;
|
||||
private boolean mDatasetValid;
|
||||
|
||||
/**
|
||||
* Initializes the adapter's observer, which watches for changes to the dataset. The adapter will
|
||||
* display no data until a Cursor is supplied by a CursorLoader.
|
||||
*/
|
||||
public GameAdapter()
|
||||
{
|
||||
mDatasetValid = false;
|
||||
mObserver = new GameDataSetObserver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the LayoutManager when it is necessary to create a new view.
|
||||
*
|
||||
* @param parent The RecyclerView (I think?) the created view will be thrown into.
|
||||
* @param viewType Not used here, but useful when more than one type of child will be used in the RecyclerView.
|
||||
* @return The created ViewHolder with references to all the child view's members.
|
||||
*/
|
||||
@Override
|
||||
public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
|
||||
{
|
||||
// Create a new view.
|
||||
View gameCard = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.card_game, parent, false);
|
||||
|
||||
gameCard.setOnClickListener(this);
|
||||
|
||||
// Use that view to create a ViewHolder.
|
||||
return new GameViewHolder(gameCard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the LayoutManager when a new view is not necessary because we can recycle
|
||||
* an existing one (for example, if a view just scrolled onto the screen from the bottom, we
|
||||
* can use the view that just scrolled off the top instead of inflating a new one.)
|
||||
*
|
||||
* @param holder A ViewHolder representing the view we're recycling.
|
||||
* @param position The position of the 'new' view in the dataset.
|
||||
*/
|
||||
@Override
|
||||
public void onBindViewHolder(GameViewHolder holder, int position)
|
||||
{
|
||||
if (mDatasetValid)
|
||||
{
|
||||
if (mCursor.moveToPosition(position))
|
||||
{
|
||||
String screenPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH);
|
||||
PicassoUtils.loadGameBanner(holder.imageScreenshot, screenPath,
|
||||
mCursor.getString(GameDatabase.GAME_COLUMN_PATH));
|
||||
|
||||
holder.textGameTitle.setText(mCursor.getString(GameDatabase.GAME_COLUMN_TITLE));
|
||||
holder.textCompany.setText(mCursor.getString(GameDatabase.GAME_COLUMN_COMPANY));
|
||||
|
||||
// TODO These shouldn't be necessary once the move to a DB-based model is complete.
|
||||
holder.gameId = mCursor.getString(GameDatabase.GAME_COLUMN_GAME_ID);
|
||||
holder.path = mCursor.getString(GameDatabase.GAME_COLUMN_PATH);
|
||||
holder.title = mCursor.getString(GameDatabase.GAME_COLUMN_TITLE);
|
||||
holder.description = mCursor.getString(GameDatabase.GAME_COLUMN_DESCRIPTION);
|
||||
holder.country = mCursor.getInt(GameDatabase.GAME_COLUMN_COUNTRY);
|
||||
holder.company = mCursor.getString(GameDatabase.GAME_COLUMN_COMPANY);
|
||||
holder.screenshotPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error("[GameAdapter] Can't bind view; Cursor is not valid.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error("[GameAdapter] Can't bind view; dataset is not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the LayoutManager to find out how much data we have.
|
||||
*
|
||||
* @return Size of the dataset.
|
||||
*/
|
||||
@Override
|
||||
public int getItemCount()
|
||||
{
|
||||
if (mDatasetValid && mCursor != null)
|
||||
{
|
||||
return mCursor.getCount();
|
||||
}
|
||||
Log.error("[GameAdapter] Dataset is not valid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contents of the _id column for a given row.
|
||||
*
|
||||
* @param position The row for which Android wants an ID.
|
||||
* @return A valid ID from the database, or 0 if not available.
|
||||
*/
|
||||
@Override
|
||||
public long getItemId(int position)
|
||||
{
|
||||
if (mDatasetValid && mCursor != null)
|
||||
{
|
||||
if (mCursor.moveToPosition(position))
|
||||
{
|
||||
return mCursor.getLong(GameDatabase.COLUMN_DB_ID);
|
||||
}
|
||||
}
|
||||
|
||||
Log.error("[GameAdapter] Dataset is not valid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell Android whether or not each item in the dataset has a stable identifier.
|
||||
* Which it does, because it's a database, so always tell Android 'true'.
|
||||
*
|
||||
* @param hasStableIds ignored.
|
||||
*/
|
||||
@Override
|
||||
public void setHasStableIds(boolean hasStableIds)
|
||||
{
|
||||
super.setHasStableIds(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a load is finished, call this to replace the existing data with the newly-loaded
|
||||
* data.
|
||||
*
|
||||
* @param cursor The newly-loaded Cursor.
|
||||
*/
|
||||
public void swapCursor(Cursor cursor)
|
||||
{
|
||||
// Sanity check.
|
||||
if (cursor == mCursor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Before getting rid of the old cursor, disassociate it from the Observer.
|
||||
final Cursor oldCursor = mCursor;
|
||||
if (oldCursor != null && mObserver != null)
|
||||
{
|
||||
oldCursor.unregisterDataSetObserver(mObserver);
|
||||
}
|
||||
|
||||
mCursor = cursor;
|
||||
if (mCursor != null)
|
||||
{
|
||||
// Attempt to associate the new Cursor with the Observer.
|
||||
if (mObserver != null)
|
||||
{
|
||||
mCursor.registerDataSetObserver(mObserver);
|
||||
}
|
||||
|
||||
mDatasetValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
mDatasetValid = false;
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the game that was clicked on.
|
||||
*
|
||||
* @param view The card representing the game the user wants to play.
|
||||
*/
|
||||
@Override
|
||||
public void onClick(View view)
|
||||
{
|
||||
GameViewHolder holder = (GameViewHolder) view.getTag();
|
||||
|
||||
EmulationActivity.launch((FragmentActivity) view.getContext(),
|
||||
holder.path,
|
||||
holder.title,
|
||||
holder.screenshotPath,
|
||||
holder.getAdapterPosition(),
|
||||
holder.imageScreenshot);
|
||||
}
|
||||
|
||||
public static class SpacesItemDecoration extends RecyclerView.ItemDecoration
|
||||
{
|
||||
private int space;
|
||||
|
||||
public SpacesItemDecoration(int space)
|
||||
{
|
||||
this.space = space;
|
||||
/**
|
||||
* Initializes the adapter's observer, which watches for changes to the dataset. The adapter will
|
||||
* display no data until a Cursor is supplied by a CursorLoader.
|
||||
*/
|
||||
public GameAdapter() {
|
||||
mDatasetValid = false;
|
||||
mObserver = new GameDataSetObserver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the LayoutManager when it is necessary to create a new view.
|
||||
*
|
||||
* @param parent The RecyclerView (I think?) the created view will be thrown into.
|
||||
* @param viewType Not used here, but useful when more than one type of child will be used in the RecyclerView.
|
||||
* @return The created ViewHolder with references to all the child view's members.
|
||||
*/
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||
RecyclerView.State state)
|
||||
{
|
||||
outRect.left = space;
|
||||
outRect.right = space;
|
||||
outRect.bottom = space;
|
||||
outRect.top = space;
|
||||
}
|
||||
}
|
||||
public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
// Create a new view.
|
||||
View gameCard = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.card_game, parent, false);
|
||||
|
||||
private final class GameDataSetObserver extends DataSetObserver
|
||||
{
|
||||
gameCard.setOnClickListener(this);
|
||||
|
||||
// Use that view to create a ViewHolder.
|
||||
return new GameViewHolder(gameCard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the LayoutManager when a new view is not necessary because we can recycle
|
||||
* an existing one (for example, if a view just scrolled onto the screen from the bottom, we
|
||||
* can use the view that just scrolled off the top instead of inflating a new one.)
|
||||
*
|
||||
* @param holder A ViewHolder representing the view we're recycling.
|
||||
* @param position The position of the 'new' view in the dataset.
|
||||
*/
|
||||
@Override
|
||||
public void onChanged()
|
||||
{
|
||||
super.onChanged();
|
||||
public void onBindViewHolder(GameViewHolder holder, int position) {
|
||||
if (mDatasetValid) {
|
||||
if (mCursor.moveToPosition(position)) {
|
||||
String screenPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH);
|
||||
PicassoUtils.loadGameBanner(holder.imageScreenshot, screenPath,
|
||||
mCursor.getString(GameDatabase.GAME_COLUMN_PATH));
|
||||
|
||||
mDatasetValid = true;
|
||||
notifyDataSetChanged();
|
||||
holder.textGameTitle.setText(mCursor.getString(GameDatabase.GAME_COLUMN_TITLE));
|
||||
holder.textCompany.setText(mCursor.getString(GameDatabase.GAME_COLUMN_COMPANY));
|
||||
|
||||
// TODO These shouldn't be necessary once the move to a DB-based model is complete.
|
||||
holder.gameId = mCursor.getString(GameDatabase.GAME_COLUMN_GAME_ID);
|
||||
holder.path = mCursor.getString(GameDatabase.GAME_COLUMN_PATH);
|
||||
holder.title = mCursor.getString(GameDatabase.GAME_COLUMN_TITLE);
|
||||
holder.description = mCursor.getString(GameDatabase.GAME_COLUMN_DESCRIPTION);
|
||||
holder.country = mCursor.getInt(GameDatabase.GAME_COLUMN_COUNTRY);
|
||||
holder.company = mCursor.getString(GameDatabase.GAME_COLUMN_COMPANY);
|
||||
holder.screenshotPath = mCursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH);
|
||||
} else {
|
||||
Log.error("[GameAdapter] Can't bind view; Cursor is not valid.");
|
||||
}
|
||||
} else {
|
||||
Log.error("[GameAdapter] Can't bind view; dataset is not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the LayoutManager to find out how much data we have.
|
||||
*
|
||||
* @return Size of the dataset.
|
||||
*/
|
||||
@Override
|
||||
public void onInvalidated()
|
||||
{
|
||||
super.onInvalidated();
|
||||
|
||||
mDatasetValid = false;
|
||||
notifyDataSetChanged();
|
||||
public int getItemCount() {
|
||||
if (mDatasetValid && mCursor != null) {
|
||||
return mCursor.getCount();
|
||||
}
|
||||
Log.error("[GameAdapter] Dataset is not valid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the contents of the _id column for a given row.
|
||||
*
|
||||
* @param position The row for which Android wants an ID.
|
||||
* @return A valid ID from the database, or 0 if not available.
|
||||
*/
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
if (mDatasetValid && mCursor != null) {
|
||||
if (mCursor.moveToPosition(position)) {
|
||||
return mCursor.getLong(GameDatabase.COLUMN_DB_ID);
|
||||
}
|
||||
}
|
||||
|
||||
Log.error("[GameAdapter] Dataset is not valid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell Android whether or not each item in the dataset has a stable identifier.
|
||||
* Which it does, because it's a database, so always tell Android 'true'.
|
||||
*
|
||||
* @param hasStableIds ignored.
|
||||
*/
|
||||
@Override
|
||||
public void setHasStableIds(boolean hasStableIds) {
|
||||
super.setHasStableIds(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a load is finished, call this to replace the existing data with the newly-loaded
|
||||
* data.
|
||||
*
|
||||
* @param cursor The newly-loaded Cursor.
|
||||
*/
|
||||
public void swapCursor(Cursor cursor) {
|
||||
// Sanity check.
|
||||
if (cursor == mCursor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Before getting rid of the old cursor, disassociate it from the Observer.
|
||||
final Cursor oldCursor = mCursor;
|
||||
if (oldCursor != null && mObserver != null) {
|
||||
oldCursor.unregisterDataSetObserver(mObserver);
|
||||
}
|
||||
|
||||
mCursor = cursor;
|
||||
if (mCursor != null) {
|
||||
// Attempt to associate the new Cursor with the Observer.
|
||||
if (mObserver != null) {
|
||||
mCursor.registerDataSetObserver(mObserver);
|
||||
}
|
||||
|
||||
mDatasetValid = true;
|
||||
} else {
|
||||
mDatasetValid = false;
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches the game that was clicked on.
|
||||
*
|
||||
* @param view The card representing the game the user wants to play.
|
||||
*/
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
GameViewHolder holder = (GameViewHolder) view.getTag();
|
||||
|
||||
EmulationActivity.launch((FragmentActivity) view.getContext(),
|
||||
holder.path,
|
||||
holder.title,
|
||||
holder.screenshotPath,
|
||||
holder.getAdapterPosition(),
|
||||
holder.imageScreenshot);
|
||||
}
|
||||
|
||||
public static class SpacesItemDecoration extends RecyclerView.ItemDecoration {
|
||||
private int space;
|
||||
|
||||
public SpacesItemDecoration(int space) {
|
||||
this.space = space;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||
RecyclerView.State state) {
|
||||
outRect.left = space;
|
||||
outRect.right = space;
|
||||
outRect.bottom = space;
|
||||
outRect.top = space;
|
||||
}
|
||||
}
|
||||
|
||||
private final class GameDataSetObserver extends DataSetObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
|
||||
mDatasetValid = true;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
super.onInvalidated();
|
||||
|
||||
mDatasetValid = false;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,57 +17,53 @@ import org.citra.citra_android.viewholders.TvGameViewHolder;
|
||||
* The Leanback library / docs call this a Presenter, but it works very
|
||||
* similarly to a RecyclerView.Adapter.
|
||||
*/
|
||||
public final class GameRowPresenter extends Presenter
|
||||
{
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent)
|
||||
{
|
||||
// Create a new view.
|
||||
ImageCardView gameCard = new ImageCardView(parent.getContext());
|
||||
public final class GameRowPresenter extends Presenter {
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
// Create a new view.
|
||||
ImageCardView gameCard = new ImageCardView(parent.getContext());
|
||||
|
||||
gameCard.setMainImageAdjustViewBounds(true);
|
||||
gameCard.setMainImageDimensions(48, 48);
|
||||
gameCard.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
gameCard.setMainImageAdjustViewBounds(true);
|
||||
gameCard.setMainImageDimensions(48, 48);
|
||||
gameCard.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
|
||||
gameCard.setFocusable(true);
|
||||
gameCard.setFocusableInTouchMode(true);
|
||||
gameCard.setFocusable(true);
|
||||
gameCard.setFocusableInTouchMode(true);
|
||||
|
||||
// Use that view to create a ViewHolder.
|
||||
return new TvGameViewHolder(gameCard);
|
||||
}
|
||||
// Use that view to create a ViewHolder.
|
||||
return new TvGameViewHolder(gameCard);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder viewHolder, Object item)
|
||||
{
|
||||
TvGameViewHolder holder = (TvGameViewHolder) viewHolder;
|
||||
Game game = (Game) item;
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder viewHolder, Object item) {
|
||||
TvGameViewHolder holder = (TvGameViewHolder) viewHolder;
|
||||
Game game = (Game) item;
|
||||
|
||||
String screenPath = game.getScreenshotPath();
|
||||
String screenPath = game.getScreenshotPath();
|
||||
|
||||
holder.imageScreenshot.setImageDrawable(null);
|
||||
PicassoUtils.loadGameBanner(holder.imageScreenshot, screenPath, game.getPath());
|
||||
holder.imageScreenshot.setImageDrawable(null);
|
||||
PicassoUtils.loadGameBanner(holder.imageScreenshot, screenPath, game.getPath());
|
||||
|
||||
holder.cardParent.setTitleText(game.getTitle());
|
||||
holder.cardParent.setContentText(game.getCompany());
|
||||
holder.cardParent.setTitleText(game.getTitle());
|
||||
holder.cardParent.setContentText(game.getCompany());
|
||||
|
||||
// TODO These shouldn't be necessary once the move to a DB-based model is complete.
|
||||
holder.gameId = game.getGameId();
|
||||
holder.path = game.getPath();
|
||||
holder.title = game.getTitle();
|
||||
holder.description = game.getDescription();
|
||||
holder.country = game.getCountry();
|
||||
holder.company = game.getCompany();
|
||||
holder.screenshotPath = game.getScreenshotPath();
|
||||
// TODO These shouldn't be necessary once the move to a DB-based model is complete.
|
||||
holder.gameId = game.getGameId();
|
||||
holder.path = game.getPath();
|
||||
holder.title = game.getTitle();
|
||||
holder.description = game.getDescription();
|
||||
holder.country = game.getCountry();
|
||||
holder.company = game.getCompany();
|
||||
holder.screenshotPath = game.getScreenshotPath();
|
||||
|
||||
// Set the platform-dependent background color of the card
|
||||
Context context = holder.cardParent.getContext();
|
||||
Drawable background = ContextCompat.getDrawable(context, R.drawable.tv_card_background_gamecube);
|
||||
holder.cardParent.setInfoAreaBackground(background);
|
||||
}
|
||||
// Set the platform-dependent background color of the card
|
||||
Context context = holder.cardParent.getContext();
|
||||
Drawable background = ContextCompat.getDrawable(context, R.drawable.tv_card_background_gamecube);
|
||||
holder.cardParent.setInfoAreaBackground(background);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnbindViewHolder(ViewHolder viewHolder)
|
||||
{
|
||||
// no op
|
||||
}
|
||||
@Override
|
||||
public void onUnbindViewHolder(ViewHolder viewHolder) {
|
||||
// no op
|
||||
}
|
||||
}
|
||||
|
@ -8,39 +8,35 @@ import android.view.ViewGroup;
|
||||
import org.citra.citra_android.model.TvSettingsItem;
|
||||
import org.citra.citra_android.viewholders.TvSettingsViewHolder;
|
||||
|
||||
public final class SettingsRowPresenter extends Presenter
|
||||
{
|
||||
public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent)
|
||||
{
|
||||
// Create a new view.
|
||||
ImageCardView settingsCard = new ImageCardView(parent.getContext());
|
||||
public final class SettingsRowPresenter extends Presenter {
|
||||
public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
// Create a new view.
|
||||
ImageCardView settingsCard = new ImageCardView(parent.getContext());
|
||||
|
||||
settingsCard.setMainImageAdjustViewBounds(true);
|
||||
settingsCard.setMainImageDimensions(192, 160);
|
||||
settingsCard.setMainImageAdjustViewBounds(true);
|
||||
settingsCard.setMainImageDimensions(192, 160);
|
||||
|
||||
|
||||
settingsCard.setFocusable(true);
|
||||
settingsCard.setFocusableInTouchMode(true);
|
||||
settingsCard.setFocusable(true);
|
||||
settingsCard.setFocusableInTouchMode(true);
|
||||
|
||||
// Use that view to create a ViewHolder.
|
||||
return new TvSettingsViewHolder(settingsCard);
|
||||
}
|
||||
// Use that view to create a ViewHolder.
|
||||
return new TvSettingsViewHolder(settingsCard);
|
||||
}
|
||||
|
||||
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item)
|
||||
{
|
||||
TvSettingsViewHolder holder = (TvSettingsViewHolder) viewHolder;
|
||||
TvSettingsItem settingsItem = (TvSettingsItem) item;
|
||||
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
|
||||
TvSettingsViewHolder holder = (TvSettingsViewHolder) viewHolder;
|
||||
TvSettingsItem settingsItem = (TvSettingsItem) item;
|
||||
|
||||
Resources resources = holder.cardParent.getResources();
|
||||
Resources resources = holder.cardParent.getResources();
|
||||
|
||||
holder.itemId = settingsItem.getItemId();
|
||||
holder.itemId = settingsItem.getItemId();
|
||||
|
||||
holder.cardParent.setTitleText(resources.getString(settingsItem.getLabelId()));
|
||||
holder.cardParent.setMainImage(resources.getDrawable(settingsItem.getIconId(), null));
|
||||
}
|
||||
holder.cardParent.setTitleText(resources.getString(settingsItem.getLabelId()));
|
||||
holder.cardParent.setMainImage(resources.getDrawable(settingsItem.getIconId(), null));
|
||||
}
|
||||
|
||||
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder)
|
||||
{
|
||||
// no op
|
||||
}
|
||||
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
|
||||
// no op
|
||||
}
|
||||
}
|
||||
|
@ -16,82 +16,79 @@ import org.citra.citra_android.activities.EmulationActivity;
|
||||
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
|
||||
public final class GameDetailsDialog extends DialogFragment
|
||||
{
|
||||
private static final String ARG_GAME_TITLE = "game_title";
|
||||
private static final String ARG_GAME_DESCRIPTION = "game_description";
|
||||
private static final String ARG_GAME_COUNTRY = "game_country";
|
||||
private static final String ARG_GAME_DATE = "game_date";
|
||||
private static final String ARG_GAME_PATH = "game_path";
|
||||
private static final String ARG_GAME_SCREENSHOT_PATH = "game_screenshot_path";
|
||||
public final class GameDetailsDialog extends DialogFragment {
|
||||
private static final String ARG_GAME_TITLE = "game_title";
|
||||
private static final String ARG_GAME_DESCRIPTION = "game_description";
|
||||
private static final String ARG_GAME_COUNTRY = "game_country";
|
||||
private static final String ARG_GAME_DATE = "game_date";
|
||||
private static final String ARG_GAME_PATH = "game_path";
|
||||
private static final String ARG_GAME_SCREENSHOT_PATH = "game_screenshot_path";
|
||||
|
||||
// TODO Add all of this to the Loader in GameActivity.java
|
||||
public static GameDetailsDialog newInstance(String title, String description, int country,
|
||||
String company, String path, String screenshotPath)
|
||||
{
|
||||
GameDetailsDialog fragment = new GameDetailsDialog();
|
||||
// TODO Add all of this to the Loader in GameActivity.java
|
||||
public static GameDetailsDialog newInstance(String title, String description, int country,
|
||||
String company, String path, String screenshotPath) {
|
||||
GameDetailsDialog fragment = new GameDetailsDialog();
|
||||
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putString(ARG_GAME_TITLE, title);
|
||||
arguments.putString(ARG_GAME_DESCRIPTION, description);
|
||||
arguments.putInt(ARG_GAME_COUNTRY, country);
|
||||
arguments.putString(ARG_GAME_DATE, company);
|
||||
arguments.putString(ARG_GAME_PATH, path);
|
||||
arguments.putString(ARG_GAME_SCREENSHOT_PATH, screenshotPath);
|
||||
fragment.setArguments(arguments);
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putString(ARG_GAME_TITLE, title);
|
||||
arguments.putString(ARG_GAME_DESCRIPTION, description);
|
||||
arguments.putInt(ARG_GAME_COUNTRY, country);
|
||||
arguments.putString(ARG_GAME_DATE, company);
|
||||
arguments.putString(ARG_GAME_PATH, path);
|
||||
arguments.putString(ARG_GAME_SCREENSHOT_PATH, screenshotPath);
|
||||
fragment.setArguments(arguments);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState)
|
||||
{
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater()
|
||||
.inflate(R.layout.dialog_game_details, null);
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater()
|
||||
.inflate(R.layout.dialog_game_details, null);
|
||||
|
||||
final ImageView imageGameScreen = contents.findViewById(R.id.image_game_screen);
|
||||
CircleImageView circleBanner = contents.findViewById(R.id.circle_banner);
|
||||
final ImageView imageGameScreen = contents.findViewById(R.id.image_game_screen);
|
||||
CircleImageView circleBanner = contents.findViewById(R.id.circle_banner);
|
||||
|
||||
TextView textTitle = contents.findViewById(R.id.text_game_title);
|
||||
TextView textDescription = contents.findViewById(R.id.text_company);
|
||||
TextView textTitle = contents.findViewById(R.id.text_game_title);
|
||||
TextView textDescription = contents.findViewById(R.id.text_company);
|
||||
|
||||
TextView textCountry = contents.findViewById(R.id.text_country);
|
||||
TextView textDate = contents.findViewById(R.id.text_date);
|
||||
TextView textCountry = contents.findViewById(R.id.text_country);
|
||||
TextView textDate = contents.findViewById(R.id.text_date);
|
||||
|
||||
FloatingActionButton buttonLaunch = contents.findViewById(R.id.button_launch);
|
||||
FloatingActionButton buttonLaunch = contents.findViewById(R.id.button_launch);
|
||||
|
||||
int countryIndex = getArguments().getInt(ARG_GAME_COUNTRY);
|
||||
String country = getResources().getStringArray(R.array.countryNames)[countryIndex];
|
||||
int countryIndex = getArguments().getInt(ARG_GAME_COUNTRY);
|
||||
String country = getResources().getStringArray(R.array.countryNames)[countryIndex];
|
||||
|
||||
textTitle.setText(getArguments().getString(ARG_GAME_TITLE));
|
||||
textDescription.setText(getArguments().getString(ARG_GAME_DESCRIPTION));
|
||||
textCountry.setText(country);
|
||||
textDate.setText(getArguments().getString(ARG_GAME_DATE));
|
||||
textTitle.setText(getArguments().getString(ARG_GAME_TITLE));
|
||||
textDescription.setText(getArguments().getString(ARG_GAME_DESCRIPTION));
|
||||
textCountry.setText(country);
|
||||
textDate.setText(getArguments().getString(ARG_GAME_DATE));
|
||||
|
||||
buttonLaunch.setOnClickListener(view ->
|
||||
{
|
||||
// Start the emulation activity and send the path of the clicked ROM to it.
|
||||
EmulationActivity.launch(getActivity(),
|
||||
getArguments().getString(ARG_GAME_PATH),
|
||||
getArguments().getString(ARG_GAME_TITLE),
|
||||
getArguments().getString(ARG_GAME_SCREENSHOT_PATH),
|
||||
-1,
|
||||
imageGameScreen);
|
||||
});
|
||||
buttonLaunch.setOnClickListener(view ->
|
||||
{
|
||||
// Start the emulation activity and send the path of the clicked ROM to it.
|
||||
EmulationActivity.launch(getActivity(),
|
||||
getArguments().getString(ARG_GAME_PATH),
|
||||
getArguments().getString(ARG_GAME_TITLE),
|
||||
getArguments().getString(ARG_GAME_SCREENSHOT_PATH),
|
||||
-1,
|
||||
imageGameScreen);
|
||||
});
|
||||
|
||||
// Fill in the view contents.
|
||||
Picasso.with(imageGameScreen.getContext())
|
||||
.load(getArguments().getString(ARG_GAME_SCREENSHOT_PATH))
|
||||
.fit()
|
||||
.centerCrop()
|
||||
.noFade()
|
||||
.noPlaceholder()
|
||||
.into(imageGameScreen);
|
||||
// Fill in the view contents.
|
||||
Picasso.with(imageGameScreen.getContext())
|
||||
.load(getArguments().getString(ARG_GAME_SCREENSHOT_PATH))
|
||||
.fit()
|
||||
.centerCrop()
|
||||
.noFade()
|
||||
.noPlaceholder()
|
||||
.into(imageGameScreen);
|
||||
|
||||
circleBanner.setImageResource(R.drawable.no_banner);
|
||||
circleBanner.setImageResource(R.drawable.no_banner);
|
||||
|
||||
builder.setView(contents);
|
||||
return builder.create();
|
||||
}
|
||||
builder.setView(contents);
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
|
@ -18,157 +18,141 @@ import java.util.List;
|
||||
* {@link AlertDialog} derivative that listens for
|
||||
* motion events from controllers and joysticks.
|
||||
*/
|
||||
public final class MotionAlertDialog extends AlertDialog
|
||||
{
|
||||
// The selected input preference
|
||||
private final InputBindingSetting setting;
|
||||
private final ControllerMappingHelper mControllerMappingHelper;
|
||||
private boolean mWaitingForEvent = true;
|
||||
public final class MotionAlertDialog extends AlertDialog {
|
||||
// The selected input preference
|
||||
private final InputBindingSetting setting;
|
||||
private final ControllerMappingHelper mControllerMappingHelper;
|
||||
private boolean mWaitingForEvent = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param setting The Preference to show this dialog for.
|
||||
*/
|
||||
public MotionAlertDialog(Context context, InputBindingSetting setting)
|
||||
{
|
||||
super(context);
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current {@link Context}.
|
||||
* @param setting The Preference to show this dialog for.
|
||||
*/
|
||||
public MotionAlertDialog(Context context, InputBindingSetting setting) {
|
||||
super(context);
|
||||
|
||||
this.setting = setting;
|
||||
this.mControllerMappingHelper = new ControllerMappingHelper();
|
||||
}
|
||||
this.setting = setting;
|
||||
this.mControllerMappingHelper = new ControllerMappingHelper();
|
||||
}
|
||||
|
||||
public boolean onKeyEvent(int keyCode, KeyEvent event)
|
||||
{
|
||||
Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
|
||||
switch (event.getAction())
|
||||
{
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
if (!mControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode))
|
||||
{
|
||||
saveKeyInput(event);
|
||||
public boolean onKeyEvent(int keyCode, KeyEvent event) {
|
||||
Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
|
||||
switch (event.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
if (!mControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode)) {
|
||||
saveKeyInput(event);
|
||||
}
|
||||
// Even if we ignore the key, we still consume it. Thus return true regardless.
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
// Even if we ignore the key, we still consume it. Thus return true regardless.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
// Handle this key if we care about it, otherwise pass it down the framework
|
||||
return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event) {
|
||||
// Handle this event if we care about it, otherwise pass it down the framework
|
||||
return onMotionEvent(event) || super.dispatchGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
private boolean onMotionEvent(MotionEvent event) {
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
|
||||
return false;
|
||||
if (event.getAction() != MotionEvent.ACTION_MOVE)
|
||||
return false;
|
||||
|
||||
InputDevice input = event.getDevice();
|
||||
|
||||
List<InputDevice.MotionRange> motionRanges = input.getMotionRanges();
|
||||
|
||||
int numMovedAxis = 0;
|
||||
float axisMoveValue = 0.0f;
|
||||
InputDevice.MotionRange lastMovedRange = null;
|
||||
char lastMovedDir = '?';
|
||||
if (mWaitingForEvent) {
|
||||
// Get only the axis that seem to have moved (more than .5)
|
||||
for (InputDevice.MotionRange range : motionRanges) {
|
||||
int axis = range.getAxis();
|
||||
float origValue = event.getAxisValue(axis);
|
||||
float value = mControllerMappingHelper.scaleAxis(input, axis, origValue);
|
||||
if (Math.abs(value) > 0.5f) {
|
||||
// It is common to have multiple axis with the same physical input. For example,
|
||||
// shoulder butters are provided as both AXIS_LTRIGGER and AXIS_BRAKE.
|
||||
// To handle this, we ignore an axis motion that's the exact same as a motion
|
||||
// we already saw. This way, we ignore axis with two names, but catch the case
|
||||
// where a joystick is moved in two directions.
|
||||
// ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html
|
||||
if (value != axisMoveValue) {
|
||||
axisMoveValue = value;
|
||||
numMovedAxis++;
|
||||
lastMovedRange = range;
|
||||
lastMovedDir = value < 0.0f ? '-' : '+';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If only one axis moved, that's the winner.
|
||||
if (numMovedAxis == 1) {
|
||||
mWaitingForEvent = false;
|
||||
saveMotionInput(input, lastMovedRange, lastMovedDir);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event)
|
||||
{
|
||||
// Handle this key if we care about it, otherwise pass it down the framework
|
||||
return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchGenericMotionEvent(MotionEvent event)
|
||||
{
|
||||
// Handle this event if we care about it, otherwise pass it down the framework
|
||||
return onMotionEvent(event) || super.dispatchGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
private boolean onMotionEvent(MotionEvent event)
|
||||
{
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
|
||||
return false;
|
||||
if (event.getAction() != MotionEvent.ACTION_MOVE)
|
||||
return false;
|
||||
|
||||
InputDevice input = event.getDevice();
|
||||
|
||||
List<InputDevice.MotionRange> motionRanges = input.getMotionRanges();
|
||||
|
||||
int numMovedAxis = 0;
|
||||
float axisMoveValue = 0.0f;
|
||||
InputDevice.MotionRange lastMovedRange = null;
|
||||
char lastMovedDir = '?';
|
||||
if (mWaitingForEvent)
|
||||
{
|
||||
// Get only the axis that seem to have moved (more than .5)
|
||||
for (InputDevice.MotionRange range : motionRanges)
|
||||
{
|
||||
int axis = range.getAxis();
|
||||
float origValue = event.getAxisValue(axis);
|
||||
float value = mControllerMappingHelper.scaleAxis(input, axis, origValue);
|
||||
if (Math.abs(value) > 0.5f)
|
||||
{
|
||||
// It is common to have multiple axis with the same physical input. For example,
|
||||
// shoulder butters are provided as both AXIS_LTRIGGER and AXIS_BRAKE.
|
||||
// To handle this, we ignore an axis motion that's the exact same as a motion
|
||||
// we already saw. This way, we ignore axis with two names, but catch the case
|
||||
// where a joystick is moved in two directions.
|
||||
// ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html
|
||||
if (value != axisMoveValue)
|
||||
{
|
||||
axisMoveValue = value;
|
||||
numMovedAxis++;
|
||||
lastMovedRange = range;
|
||||
lastMovedDir = value < 0.0f ? '-' : '+';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If only one axis moved, that's the winner.
|
||||
if (numMovedAxis == 1)
|
||||
{
|
||||
mWaitingForEvent = false;
|
||||
saveMotionInput(input, lastMovedRange, lastMovedDir);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Saves the provided key input setting both to the INI file (so native code can use it) and as
|
||||
* an Android preference (so it persists correctly and is human-readable.)
|
||||
*
|
||||
* @param keyEvent KeyEvent of this key press.
|
||||
*/
|
||||
private void saveKeyInput(KeyEvent keyEvent) {
|
||||
InputDevice device = keyEvent.getDevice();
|
||||
String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode();
|
||||
String uiString = device.getName() + ": Button " + keyEvent.getKeyCode();
|
||||
|
||||
/**
|
||||
* Saves the provided key input setting both to the INI file (so native code can use it) and as
|
||||
* an Android preference (so it persists correctly and is human-readable.)
|
||||
*
|
||||
* @param keyEvent KeyEvent of this key press.
|
||||
*/
|
||||
private void saveKeyInput(KeyEvent keyEvent)
|
||||
{
|
||||
InputDevice device = keyEvent.getDevice();
|
||||
String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode();
|
||||
String uiString = device.getName() + ": Button " + keyEvent.getKeyCode();
|
||||
saveInput(bindStr, uiString);
|
||||
}
|
||||
|
||||
saveInput(bindStr, uiString);
|
||||
}
|
||||
/**
|
||||
* Saves the provided motion input setting both to the INI file (so native code can use it) and as
|
||||
* an Android preference (so it persists correctly and is human-readable.)
|
||||
*
|
||||
* @param device InputDevice from which the input event originated.
|
||||
* @param motionRange MotionRange of the movement
|
||||
* @param axisDir Either '-' or '+'
|
||||
*/
|
||||
private void saveMotionInput(InputDevice device, InputDevice.MotionRange motionRange,
|
||||
char axisDir) {
|
||||
String bindStr =
|
||||
"Device '" + device.getDescriptor() + "'-Axis " + motionRange.getAxis() + axisDir;
|
||||
String uiString = device.getName() + ": Axis " + motionRange.getAxis() + axisDir;
|
||||
|
||||
/**
|
||||
* Saves the provided motion input setting both to the INI file (so native code can use it) and as
|
||||
* an Android preference (so it persists correctly and is human-readable.)
|
||||
*
|
||||
* @param device InputDevice from which the input event originated.
|
||||
* @param motionRange MotionRange of the movement
|
||||
* @param axisDir Either '-' or '+'
|
||||
*/
|
||||
private void saveMotionInput(InputDevice device, InputDevice.MotionRange motionRange,
|
||||
char axisDir)
|
||||
{
|
||||
String bindStr =
|
||||
"Device '" + device.getDescriptor() + "'-Axis " + motionRange.getAxis() + axisDir;
|
||||
String uiString = device.getName() + ": Axis " + motionRange.getAxis() + axisDir;
|
||||
saveInput(bindStr, uiString);
|
||||
}
|
||||
|
||||
saveInput(bindStr, uiString);
|
||||
}
|
||||
/**
|
||||
* Save the input string to settings and SharedPreferences, then dismiss this Dialog.
|
||||
*/
|
||||
private void saveInput(String bind, String ui) {
|
||||
setting.setValue(bind);
|
||||
|
||||
/**
|
||||
* Save the input string to settings and SharedPreferences, then dismiss this Dialog.
|
||||
*/
|
||||
private void saveInput(String bind, String ui)
|
||||
{
|
||||
setting.setValue(bind);
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString(setting.getKey(), ui);
|
||||
editor.apply();
|
||||
|
||||
editor.putString(setting.getKey(), ui);
|
||||
editor.apply();
|
||||
|
||||
dismiss();
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
@ -8,15 +8,13 @@ import com.nononsenseapps.filepicker.FilePickerFragment;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class CustomFilePickerFragment extends FilePickerFragment
|
||||
{
|
||||
@NonNull
|
||||
@Override
|
||||
public Uri toUri(@NonNull final File file)
|
||||
{
|
||||
return FileProvider
|
||||
.getUriForFile(getContext(),
|
||||
getContext().getApplicationContext().getPackageName() + ".filesprovider",
|
||||
file);
|
||||
}
|
||||
public class CustomFilePickerFragment extends FilePickerFragment {
|
||||
@NonNull
|
||||
@Override
|
||||
public Uri toUri(@NonNull final File file) {
|
||||
return FileProvider
|
||||
.getUriForFile(getContext(),
|
||||
getContext().getApplicationContext().getPackageName() + ".filesprovider",
|
||||
file);
|
||||
}
|
||||
}
|
||||
|
@ -27,465 +27,378 @@ import org.citra.citra_android.services.DirectoryInitializationService.Directory
|
||||
import org.citra.citra_android.utils.DirectoryStateReceiver;
|
||||
import org.citra.citra_android.utils.Log;
|
||||
|
||||
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
||||
{
|
||||
private static final String KEY_GAMEPATH = "gamepath";
|
||||
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback {
|
||||
private static final String KEY_GAMEPATH = "gamepath";
|
||||
|
||||
private static final Handler perfStatsUpdateHandler = new Handler();
|
||||
private static final Handler perfStatsUpdateHandler = new Handler();
|
||||
|
||||
private SharedPreferences mPreferences;
|
||||
private SharedPreferences mPreferences;
|
||||
|
||||
private InputOverlay mInputOverlay;
|
||||
private InputOverlay mInputOverlay;
|
||||
|
||||
private EmulationState mEmulationState;
|
||||
private EmulationState mEmulationState;
|
||||
|
||||
private DirectoryStateReceiver directoryStateReceiver;
|
||||
private DirectoryStateReceiver directoryStateReceiver;
|
||||
|
||||
private EmulationActivity activity;
|
||||
private EmulationActivity activity;
|
||||
|
||||
private TextView mPerfStats;
|
||||
private TextView mPerfStats;
|
||||
|
||||
private Runnable perfStatsUpdater;
|
||||
private Runnable perfStatsUpdater;
|
||||
|
||||
public static EmulationFragment newInstance(String gamePath)
|
||||
{
|
||||
public static EmulationFragment newInstance(String gamePath) {
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KEY_GAMEPATH, gamePath);
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KEY_GAMEPATH, gamePath);
|
||||
|
||||
EmulationFragment fragment = new EmulationFragment();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context)
|
||||
{
|
||||
super.onAttach(context);
|
||||
|
||||
if (context instanceof EmulationActivity)
|
||||
{
|
||||
activity = (EmulationActivity) context;
|
||||
NativeLibrary.setEmulationActivity((EmulationActivity) context);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException("EmulationFragment must have EmulationActivity parent");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize anything that doesn't depend on the layout / views in here.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||
setRetainInstance(true);
|
||||
|
||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
String gamePath = getArguments().getString(KEY_GAMEPATH);
|
||||
mEmulationState = new EmulationState(gamePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the UI and start emulation in here.
|
||||
*/
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
|
||||
|
||||
SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation);
|
||||
surfaceView.getHolder().addCallback(this);
|
||||
|
||||
mInputOverlay = contents.findViewById(R.id.surface_input_overlay);
|
||||
if (mInputOverlay != null)
|
||||
{
|
||||
// If the input overlay was previously disabled, then don't show it.
|
||||
if (!mPreferences.getBoolean("showInputOverlay", true))
|
||||
{
|
||||
mInputOverlay.setVisibility(View.GONE);
|
||||
}
|
||||
EmulationFragment fragment = new EmulationFragment();
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
Button doneButton = contents.findViewById(R.id.done_control_config);
|
||||
if (doneButton != null)
|
||||
{
|
||||
doneButton.setOnClickListener(v -> stopConfiguringControls());
|
||||
}
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
|
||||
mPerfStats = contents.findViewById(R.id.perf_stats_text);
|
||||
if (mPerfStats != null)
|
||||
{
|
||||
// If the overlay was previously disabled, then don't show it.
|
||||
if (!mPreferences.getBoolean("showPerfStats", true))
|
||||
{
|
||||
mPerfStats.setVisibility(View.GONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
updatePerfStats();
|
||||
}
|
||||
}
|
||||
|
||||
// The new Surface created here will get passed to the native code via onSurfaceChanged.
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
if (DirectoryInitializationService.areDolphinDirectoriesReady())
|
||||
{
|
||||
mEmulationState.run(activity.isActivityRecreated());
|
||||
}
|
||||
else
|
||||
{
|
||||
setupDolphinDirectoriesThenStartEmulation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
if (directoryStateReceiver != null)
|
||||
{
|
||||
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
|
||||
directoryStateReceiver = null;
|
||||
}
|
||||
|
||||
mEmulationState.pause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach()
|
||||
{
|
||||
NativeLibrary.clearEmulationActivity();
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
private void setupDolphinDirectoriesThenStartEmulation()
|
||||
{
|
||||
IntentFilter statusIntentFilter = new IntentFilter(
|
||||
DirectoryInitializationService.BROADCAST_ACTION);
|
||||
|
||||
directoryStateReceiver =
|
||||
new DirectoryStateReceiver(directoryInitializationState ->
|
||||
{
|
||||
if (directoryInitializationState ==
|
||||
DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
||||
{
|
||||
mEmulationState.run(activity.isActivityRecreated());
|
||||
}
|
||||
else if (directoryInitializationState ==
|
||||
DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
||||
{
|
||||
Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
else if (directoryInitializationState ==
|
||||
DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
|
||||
{
|
||||
Toast.makeText(getContext(), R.string.external_storage_not_mounted,
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
|
||||
// Registers the DirectoryStateReceiver and its intent filters
|
||||
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
|
||||
directoryStateReceiver,
|
||||
statusIntentFilter);
|
||||
DirectoryInitializationService.startService(getActivity());
|
||||
}
|
||||
|
||||
public void toggleInputOverlayVisibility()
|
||||
{
|
||||
SharedPreferences.Editor editor = mPreferences.edit();
|
||||
|
||||
// If the overlay is currently set to INVISIBLE
|
||||
if (!mPreferences.getBoolean("showInputOverlay", false))
|
||||
{
|
||||
// Set it to VISIBLE
|
||||
mInputOverlay.setVisibility(View.VISIBLE);
|
||||
editor.putBoolean("showInputOverlay", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set it to INVISIBLE
|
||||
mInputOverlay.setVisibility(View.GONE);
|
||||
editor.putBoolean("showInputOverlay", false);
|
||||
}
|
||||
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public void refreshInputOverlay()
|
||||
{
|
||||
mInputOverlay.refreshControls();
|
||||
}
|
||||
|
||||
public void resetInputOverlay()
|
||||
{
|
||||
mInputOverlay.resetButtonPlacement();
|
||||
}
|
||||
|
||||
public void togglePerfStatsVisibility()
|
||||
{
|
||||
SharedPreferences.Editor editor = mPreferences.edit();
|
||||
|
||||
// If the overlay is currently set to INVISIBLE
|
||||
if (!mPreferences.getBoolean("showPerfStats", false))
|
||||
{
|
||||
updatePerfStats();
|
||||
// Set it to VISIBLE
|
||||
mPerfStats.setVisibility(View.VISIBLE);
|
||||
editor.putBoolean("showPerfStats", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
stopPerfStatsUpdates();
|
||||
// Set it to INVISIBLE
|
||||
mPerfStats.setVisibility(View.GONE);
|
||||
editor.putBoolean("showPerfStats", false);
|
||||
}
|
||||
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private void updatePerfStats()
|
||||
{
|
||||
final int SYSTEM_FPS = 0;
|
||||
final int FPS = 1;
|
||||
final int FRAMETIME = 2;
|
||||
final int SPEED = 3;
|
||||
|
||||
perfStatsUpdater = () ->
|
||||
{
|
||||
double perfStats[] = NativeLibrary.GetPerfStats();
|
||||
mPerfStats
|
||||
.setText(String.format("FPS: %.5s\nFrametime: %.7sms\nSpeed: %.4s%%", perfStats[FPS],
|
||||
perfStats[FRAMETIME] * 1000.0, perfStats[SPEED] * 100.0));
|
||||
|
||||
perfStatsUpdateHandler.postDelayed(perfStatsUpdater, 3000 /* 3s */);
|
||||
};
|
||||
perfStatsUpdateHandler.post(perfStatsUpdater);
|
||||
}
|
||||
|
||||
private void stopPerfStatsUpdates()
|
||||
{
|
||||
if (perfStatsUpdater != null)
|
||||
{
|
||||
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder)
|
||||
{
|
||||
// We purposely don't do anything here.
|
||||
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||
{
|
||||
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
|
||||
mEmulationState.newSurface(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder)
|
||||
{
|
||||
mEmulationState.clearSurface();
|
||||
}
|
||||
|
||||
public void stopEmulation()
|
||||
{
|
||||
mEmulationState.stop();
|
||||
}
|
||||
|
||||
public void startConfiguringControls()
|
||||
{
|
||||
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
|
||||
mInputOverlay.setIsInEditMode(true);
|
||||
}
|
||||
|
||||
public void stopConfiguringControls()
|
||||
{
|
||||
getView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
|
||||
mInputOverlay.setIsInEditMode(false);
|
||||
}
|
||||
|
||||
public boolean isConfiguringControls()
|
||||
{
|
||||
return mInputOverlay.isInEditMode();
|
||||
}
|
||||
|
||||
private static class EmulationState
|
||||
{
|
||||
private enum State
|
||||
{
|
||||
STOPPED, RUNNING, PAUSED
|
||||
}
|
||||
|
||||
private final String mGamePath;
|
||||
private Thread mEmulationThread;
|
||||
private State state;
|
||||
private Surface mSurface;
|
||||
private boolean mRunWhenSurfaceIsValid;
|
||||
|
||||
EmulationState(String gamePath)
|
||||
{
|
||||
mGamePath = gamePath;
|
||||
// Starting state is stopped.
|
||||
state = State.STOPPED;
|
||||
}
|
||||
|
||||
// Getters for the current state
|
||||
|
||||
public synchronized boolean isStopped()
|
||||
{
|
||||
return state == State.STOPPED;
|
||||
}
|
||||
|
||||
public synchronized boolean isPaused()
|
||||
{
|
||||
return state == State.PAUSED;
|
||||
}
|
||||
|
||||
public synchronized boolean isRunning()
|
||||
{
|
||||
return state == State.RUNNING;
|
||||
}
|
||||
|
||||
// State changing methods
|
||||
|
||||
public synchronized void stop()
|
||||
{
|
||||
if (state != State.STOPPED)
|
||||
{
|
||||
Log.debug("[EmulationFragment] Stopping emulation.");
|
||||
state = State.STOPPED;
|
||||
NativeLibrary.StopEmulation();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.warning("[EmulationFragment] Stop called while already stopped.");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void pause()
|
||||
{
|
||||
if (state != State.PAUSED)
|
||||
{
|
||||
state = State.PAUSED;
|
||||
Log.debug("[EmulationFragment] Pausing emulation.");
|
||||
|
||||
// Release the surface before pausing, since emulation has to be running for that.
|
||||
NativeLibrary.SurfaceDestroyed();
|
||||
NativeLibrary.PauseEmulation();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.warning("[EmulationFragment] Pause called while already paused.");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void run(boolean isActivityRecreated)
|
||||
{
|
||||
if (isActivityRecreated)
|
||||
{
|
||||
if (NativeLibrary.IsRunning())
|
||||
{
|
||||
state = State.PAUSED;
|
||||
if (context instanceof EmulationActivity) {
|
||||
activity = (EmulationActivity) context;
|
||||
NativeLibrary.setEmulationActivity((EmulationActivity) context);
|
||||
} else {
|
||||
throw new IllegalStateException("EmulationFragment must have EmulationActivity parent");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.debug("[EmulationFragment] activity resumed or fresh start");
|
||||
}
|
||||
|
||||
// If the surface is set, run now. Otherwise, wait for it to get set.
|
||||
if (mSurface != null)
|
||||
{
|
||||
runWithValidSurface();
|
||||
}
|
||||
else
|
||||
{
|
||||
mRunWhenSurfaceIsValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Surface callbacks
|
||||
public synchronized void newSurface(Surface surface)
|
||||
{
|
||||
mSurface = surface;
|
||||
if (mRunWhenSurfaceIsValid)
|
||||
{
|
||||
runWithValidSurface();
|
||||
}
|
||||
/**
|
||||
* Initialize anything that doesn't depend on the layout / views in here.
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||
setRetainInstance(true);
|
||||
|
||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
String gamePath = getArguments().getString(KEY_GAMEPATH);
|
||||
mEmulationState = new EmulationState(gamePath);
|
||||
}
|
||||
|
||||
public synchronized void clearSurface()
|
||||
{
|
||||
if (mSurface == null)
|
||||
{
|
||||
Log.warning("[EmulationFragment] clearSurface called, but surface already null.");
|
||||
}
|
||||
else
|
||||
{
|
||||
mSurface = null;
|
||||
Log.debug("[EmulationFragment] Surface destroyed.");
|
||||
/**
|
||||
* Initialize the UI and start emulation in here.
|
||||
*/
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
|
||||
|
||||
if (state == State.RUNNING)
|
||||
{
|
||||
NativeLibrary.SurfaceDestroyed();
|
||||
state = State.PAUSED;
|
||||
SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation);
|
||||
surfaceView.getHolder().addCallback(this);
|
||||
|
||||
mInputOverlay = contents.findViewById(R.id.surface_input_overlay);
|
||||
if (mInputOverlay != null) {
|
||||
// If the input overlay was previously disabled, then don't show it.
|
||||
if (!mPreferences.getBoolean("showInputOverlay", true)) {
|
||||
mInputOverlay.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
else if (state == State.PAUSED)
|
||||
{
|
||||
Log.warning("[EmulationFragment] Surface cleared while emulation paused.");
|
||||
|
||||
Button doneButton = contents.findViewById(R.id.done_control_config);
|
||||
if (doneButton != null) {
|
||||
doneButton.setOnClickListener(v -> stopConfiguringControls());
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.warning("[EmulationFragment] Surface cleared while emulation stopped.");
|
||||
|
||||
mPerfStats = contents.findViewById(R.id.perf_stats_text);
|
||||
if (mPerfStats != null) {
|
||||
// If the overlay was previously disabled, then don't show it.
|
||||
if (!mPreferences.getBoolean("showPerfStats", true)) {
|
||||
mPerfStats.setVisibility(View.GONE);
|
||||
} else {
|
||||
updatePerfStats();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The new Surface created here will get passed to the native code via onSurfaceChanged.
|
||||
|
||||
return contents;
|
||||
}
|
||||
|
||||
private void runWithValidSurface()
|
||||
{
|
||||
mRunWhenSurfaceIsValid = false;
|
||||
if (state == State.STOPPED)
|
||||
{
|
||||
mEmulationThread = new Thread(() ->
|
||||
{
|
||||
NativeLibrary.SurfaceChanged(mSurface);
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.");
|
||||
NativeLibrary.Run(mGamePath);
|
||||
}, "NativeEmulation");
|
||||
mEmulationThread.start();
|
||||
|
||||
}
|
||||
else if (state == State.PAUSED)
|
||||
{
|
||||
Log.debug("[EmulationFragment] Resuming emulation.");
|
||||
NativeLibrary.SurfaceChanged(mSurface);
|
||||
NativeLibrary.UnPauseEmulation();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.debug("[EmulationFragment] Bug, run called while already running.");
|
||||
}
|
||||
state = State.RUNNING;
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (DirectoryInitializationService.areDolphinDirectoriesReady()) {
|
||||
mEmulationState.run(activity.isActivityRecreated());
|
||||
} else {
|
||||
setupDolphinDirectoriesThenStartEmulation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
if (directoryStateReceiver != null) {
|
||||
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
|
||||
directoryStateReceiver = null;
|
||||
}
|
||||
|
||||
mEmulationState.pause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
NativeLibrary.clearEmulationActivity();
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
private void setupDolphinDirectoriesThenStartEmulation() {
|
||||
IntentFilter statusIntentFilter = new IntentFilter(
|
||||
DirectoryInitializationService.BROADCAST_ACTION);
|
||||
|
||||
directoryStateReceiver =
|
||||
new DirectoryStateReceiver(directoryInitializationState ->
|
||||
{
|
||||
if (directoryInitializationState ==
|
||||
DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) {
|
||||
mEmulationState.run(activity.isActivityRecreated());
|
||||
} else if (directoryInitializationState ==
|
||||
DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) {
|
||||
Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
} else if (directoryInitializationState ==
|
||||
DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE) {
|
||||
Toast.makeText(getContext(), R.string.external_storage_not_mounted,
|
||||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
|
||||
// Registers the DirectoryStateReceiver and its intent filters
|
||||
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
|
||||
directoryStateReceiver,
|
||||
statusIntentFilter);
|
||||
DirectoryInitializationService.startService(getActivity());
|
||||
}
|
||||
|
||||
public void toggleInputOverlayVisibility() {
|
||||
SharedPreferences.Editor editor = mPreferences.edit();
|
||||
|
||||
// If the overlay is currently set to INVISIBLE
|
||||
if (!mPreferences.getBoolean("showInputOverlay", false)) {
|
||||
// Set it to VISIBLE
|
||||
mInputOverlay.setVisibility(View.VISIBLE);
|
||||
editor.putBoolean("showInputOverlay", true);
|
||||
} else {
|
||||
// Set it to INVISIBLE
|
||||
mInputOverlay.setVisibility(View.GONE);
|
||||
editor.putBoolean("showInputOverlay", false);
|
||||
}
|
||||
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public void refreshInputOverlay() {
|
||||
mInputOverlay.refreshControls();
|
||||
}
|
||||
|
||||
public void resetInputOverlay() {
|
||||
mInputOverlay.resetButtonPlacement();
|
||||
}
|
||||
|
||||
public void togglePerfStatsVisibility() {
|
||||
SharedPreferences.Editor editor = mPreferences.edit();
|
||||
|
||||
// If the overlay is currently set to INVISIBLE
|
||||
if (!mPreferences.getBoolean("showPerfStats", false)) {
|
||||
updatePerfStats();
|
||||
// Set it to VISIBLE
|
||||
mPerfStats.setVisibility(View.VISIBLE);
|
||||
editor.putBoolean("showPerfStats", true);
|
||||
} else {
|
||||
stopPerfStatsUpdates();
|
||||
// Set it to INVISIBLE
|
||||
mPerfStats.setVisibility(View.GONE);
|
||||
editor.putBoolean("showPerfStats", false);
|
||||
}
|
||||
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
private void updatePerfStats() {
|
||||
final int SYSTEM_FPS = 0;
|
||||
final int FPS = 1;
|
||||
final int FRAMETIME = 2;
|
||||
final int SPEED = 3;
|
||||
|
||||
perfStatsUpdater = () ->
|
||||
{
|
||||
double[] perfStats = NativeLibrary.GetPerfStats();
|
||||
mPerfStats
|
||||
.setText(String.format("FPS: %.5s\nFrametime: %.7sms\nSpeed: %.4s%%", perfStats[FPS],
|
||||
perfStats[FRAMETIME] * 1000.0, perfStats[SPEED] * 100.0));
|
||||
|
||||
perfStatsUpdateHandler.postDelayed(perfStatsUpdater, 3000 /* 3s */);
|
||||
};
|
||||
perfStatsUpdateHandler.post(perfStatsUpdater);
|
||||
}
|
||||
|
||||
private void stopPerfStatsUpdates() {
|
||||
if (perfStatsUpdater != null) {
|
||||
perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
// We purposely don't do anything here.
|
||||
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
|
||||
mEmulationState.newSurface(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||||
mEmulationState.clearSurface();
|
||||
}
|
||||
|
||||
public void stopEmulation() {
|
||||
mEmulationState.stop();
|
||||
}
|
||||
|
||||
public void startConfiguringControls() {
|
||||
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
|
||||
mInputOverlay.setIsInEditMode(true);
|
||||
}
|
||||
|
||||
public void stopConfiguringControls() {
|
||||
getView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
|
||||
mInputOverlay.setIsInEditMode(false);
|
||||
}
|
||||
|
||||
public boolean isConfiguringControls() {
|
||||
return mInputOverlay.isInEditMode();
|
||||
}
|
||||
|
||||
private static class EmulationState {
|
||||
private final String mGamePath;
|
||||
private Thread mEmulationThread;
|
||||
private State state;
|
||||
private Surface mSurface;
|
||||
private boolean mRunWhenSurfaceIsValid;
|
||||
|
||||
EmulationState(String gamePath) {
|
||||
mGamePath = gamePath;
|
||||
// Starting state is stopped.
|
||||
state = State.STOPPED;
|
||||
}
|
||||
|
||||
public synchronized boolean isStopped() {
|
||||
return state == State.STOPPED;
|
||||
}
|
||||
|
||||
// Getters for the current state
|
||||
|
||||
public synchronized boolean isPaused() {
|
||||
return state == State.PAUSED;
|
||||
}
|
||||
|
||||
public synchronized boolean isRunning() {
|
||||
return state == State.RUNNING;
|
||||
}
|
||||
|
||||
public synchronized void stop() {
|
||||
if (state != State.STOPPED) {
|
||||
Log.debug("[EmulationFragment] Stopping emulation.");
|
||||
state = State.STOPPED;
|
||||
NativeLibrary.StopEmulation();
|
||||
} else {
|
||||
Log.warning("[EmulationFragment] Stop called while already stopped.");
|
||||
}
|
||||
}
|
||||
|
||||
// State changing methods
|
||||
|
||||
public synchronized void pause() {
|
||||
if (state != State.PAUSED) {
|
||||
state = State.PAUSED;
|
||||
Log.debug("[EmulationFragment] Pausing emulation.");
|
||||
|
||||
// Release the surface before pausing, since emulation has to be running for that.
|
||||
NativeLibrary.SurfaceDestroyed();
|
||||
NativeLibrary.PauseEmulation();
|
||||
} else {
|
||||
Log.warning("[EmulationFragment] Pause called while already paused.");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void run(boolean isActivityRecreated) {
|
||||
if (isActivityRecreated) {
|
||||
if (NativeLibrary.IsRunning()) {
|
||||
state = State.PAUSED;
|
||||
}
|
||||
} else {
|
||||
Log.debug("[EmulationFragment] activity resumed or fresh start");
|
||||
}
|
||||
|
||||
// If the surface is set, run now. Otherwise, wait for it to get set.
|
||||
if (mSurface != null) {
|
||||
runWithValidSurface();
|
||||
} else {
|
||||
mRunWhenSurfaceIsValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Surface callbacks
|
||||
public synchronized void newSurface(Surface surface) {
|
||||
mSurface = surface;
|
||||
if (mRunWhenSurfaceIsValid) {
|
||||
runWithValidSurface();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void clearSurface() {
|
||||
if (mSurface == null) {
|
||||
Log.warning("[EmulationFragment] clearSurface called, but surface already null.");
|
||||
} else {
|
||||
mSurface = null;
|
||||
Log.debug("[EmulationFragment] Surface destroyed.");
|
||||
|
||||
if (state == State.RUNNING) {
|
||||
NativeLibrary.SurfaceDestroyed();
|
||||
state = State.PAUSED;
|
||||
} else if (state == State.PAUSED) {
|
||||
Log.warning("[EmulationFragment] Surface cleared while emulation paused.");
|
||||
} else {
|
||||
Log.warning("[EmulationFragment] Surface cleared while emulation stopped.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void runWithValidSurface() {
|
||||
mRunWhenSurfaceIsValid = false;
|
||||
if (state == State.STOPPED) {
|
||||
mEmulationThread = new Thread(() ->
|
||||
{
|
||||
NativeLibrary.SurfaceChanged(mSurface);
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.");
|
||||
NativeLibrary.Run(mGamePath);
|
||||
}, "NativeEmulation");
|
||||
mEmulationThread.start();
|
||||
|
||||
} else if (state == State.PAUSED) {
|
||||
Log.debug("[EmulationFragment] Resuming emulation.");
|
||||
NativeLibrary.SurfaceChanged(mSurface);
|
||||
NativeLibrary.UnPauseEmulation();
|
||||
} else {
|
||||
Log.debug("[EmulationFragment] Bug, run called while already running.");
|
||||
}
|
||||
state = State.RUNNING;
|
||||
}
|
||||
|
||||
private enum State {
|
||||
STOPPED, RUNNING, PAUSED
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,65 +14,57 @@ import android.widget.TextView;
|
||||
import org.citra.citra_android.R;
|
||||
import org.citra.citra_android.activities.EmulationActivity;
|
||||
|
||||
public final class MenuFragment extends Fragment implements View.OnClickListener
|
||||
{
|
||||
private static final String KEY_TITLE = "title";
|
||||
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
|
||||
public final class MenuFragment extends Fragment implements View.OnClickListener {
|
||||
private static final String KEY_TITLE = "title";
|
||||
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
|
||||
|
||||
static
|
||||
{
|
||||
buttonsActionsMap.append(R.id.menu_emulation_toggle_perf_stats,
|
||||
EmulationActivity.MENU_ACTION_TOGGLE_PREF_STATS);
|
||||
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
|
||||
buttonsActionsMap.append(R.id.menu_emulation_switch_screen_layout,
|
||||
EmulationActivity.MENU_ACTION_SWITCH_SCREEN_LAYOUT);
|
||||
buttonsActionsMap.append(R.id.menu_emulation_swap_screens,
|
||||
EmulationActivity.MENU_ACTION_SWAP_SCREENS);
|
||||
}
|
||||
|
||||
public static MenuFragment newInstance(String title)
|
||||
{
|
||||
MenuFragment fragment = new MenuFragment();
|
||||
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putSerializable(KEY_TITLE, title);
|
||||
fragment.setArguments(arguments);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false);
|
||||
|
||||
LinearLayout options = rootView.findViewById(R.id.layout_options);
|
||||
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++)
|
||||
{
|
||||
Button button = (Button) options.getChildAt(childIndex);
|
||||
|
||||
button.setOnClickListener(this);
|
||||
static {
|
||||
buttonsActionsMap.append(R.id.menu_emulation_toggle_perf_stats,
|
||||
EmulationActivity.MENU_ACTION_TOGGLE_PREF_STATS);
|
||||
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
|
||||
buttonsActionsMap.append(R.id.menu_emulation_switch_screen_layout,
|
||||
EmulationActivity.MENU_ACTION_SWITCH_SCREEN_LAYOUT);
|
||||
buttonsActionsMap.append(R.id.menu_emulation_swap_screens,
|
||||
EmulationActivity.MENU_ACTION_SWAP_SCREENS);
|
||||
}
|
||||
|
||||
TextView titleText = rootView.findViewById(R.id.text_game_title);
|
||||
String title = getArguments().getString(KEY_TITLE);
|
||||
if (title != null)
|
||||
{
|
||||
titleText.setText(title);
|
||||
public static MenuFragment newInstance(String title) {
|
||||
MenuFragment fragment = new MenuFragment();
|
||||
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putSerializable(KEY_TITLE, title);
|
||||
fragment.setArguments(arguments);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
return rootView;
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false);
|
||||
|
||||
@SuppressWarnings("WrongConstant")
|
||||
@Override
|
||||
public void onClick(View button)
|
||||
{
|
||||
int action = buttonsActionsMap.get(button.getId());
|
||||
if (action >= 0)
|
||||
{
|
||||
((EmulationActivity) getActivity()).handleMenuAction(action);
|
||||
LinearLayout options = rootView.findViewById(R.id.layout_options);
|
||||
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++) {
|
||||
Button button = (Button) options.getChildAt(childIndex);
|
||||
|
||||
button.setOnClickListener(this);
|
||||
}
|
||||
|
||||
TextView titleText = rootView.findViewById(R.id.text_game_title);
|
||||
String title = getArguments().getString(KEY_TITLE);
|
||||
if (title != null) {
|
||||
titleText.setText(title);
|
||||
}
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WrongConstant")
|
||||
@Override
|
||||
public void onClick(View button) {
|
||||
int action = buttonsActionsMap.get(button.getId());
|
||||
if (action >= 0) {
|
||||
((EmulationActivity) getActivity()).handleMenuAction(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,93 +4,82 @@ import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.os.Environment;
|
||||
|
||||
public final class Game
|
||||
{
|
||||
private static final String PATH_SCREENSHOT_FOLDER =
|
||||
"file://" + Environment.getExternalStorageDirectory().getPath() + "/citra-emu/ScreenShots/";
|
||||
public final class Game {
|
||||
private static final String PATH_SCREENSHOT_FOLDER =
|
||||
"file://" + Environment.getExternalStorageDirectory().getPath() + "/citra-emu/ScreenShots/";
|
||||
|
||||
private String mTitle;
|
||||
private String mDescription;
|
||||
private String mPath;
|
||||
private String mGameId;
|
||||
private String mScreenshotPath;
|
||||
private String mCompany;
|
||||
private String mTitle;
|
||||
private String mDescription;
|
||||
private String mPath;
|
||||
private String mGameId;
|
||||
private String mScreenshotPath;
|
||||
private String mCompany;
|
||||
|
||||
private int mCountry;
|
||||
private int mCountry;
|
||||
|
||||
public Game(String title, String description, int country, String path,
|
||||
String gameId, String company, String screenshotPath)
|
||||
{
|
||||
mTitle = title;
|
||||
mDescription = description;
|
||||
mCountry = country;
|
||||
mPath = path;
|
||||
mGameId = gameId;
|
||||
mCompany = company;
|
||||
mScreenshotPath = screenshotPath;
|
||||
}
|
||||
public Game(String title, String description, int country, String path,
|
||||
String gameId, String company, String screenshotPath) {
|
||||
mTitle = title;
|
||||
mDescription = description;
|
||||
mCountry = country;
|
||||
mPath = path;
|
||||
mGameId = gameId;
|
||||
mCompany = company;
|
||||
mScreenshotPath = screenshotPath;
|
||||
}
|
||||
|
||||
public String getTitle()
|
||||
{
|
||||
return mTitle;
|
||||
}
|
||||
public static ContentValues asContentValues(String title, String description,
|
||||
int country, String path, String gameId, String company) {
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
public String getDescription()
|
||||
{
|
||||
return mDescription;
|
||||
}
|
||||
String screenPath = PATH_SCREENSHOT_FOLDER + gameId + "/" + gameId + "-1.png";
|
||||
|
||||
public String getCompany()
|
||||
{
|
||||
return mCompany;
|
||||
}
|
||||
values.put(GameDatabase.KEY_GAME_TITLE, title);
|
||||
values.put(GameDatabase.KEY_GAME_DESCRIPTION, description);
|
||||
values.put(GameDatabase.KEY_GAME_COUNTRY, country);
|
||||
values.put(GameDatabase.KEY_GAME_PATH, path);
|
||||
values.put(GameDatabase.KEY_GAME_ID, gameId);
|
||||
values.put(GameDatabase.KEY_GAME_COMPANY, company);
|
||||
values.put(GameDatabase.KEY_GAME_SCREENSHOT_PATH, screenPath);
|
||||
|
||||
public int getCountry()
|
||||
{
|
||||
return mCountry;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
public String getPath()
|
||||
{
|
||||
return mPath;
|
||||
}
|
||||
public static Game fromCursor(Cursor cursor) {
|
||||
return new Game(cursor.getString(GameDatabase.GAME_COLUMN_TITLE),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_DESCRIPTION),
|
||||
cursor.getInt(GameDatabase.GAME_COLUMN_COUNTRY),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_PATH),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_GAME_ID),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_COMPANY),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH));
|
||||
}
|
||||
|
||||
public String getGameId()
|
||||
{
|
||||
return mGameId;
|
||||
}
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public String getScreenshotPath()
|
||||
{
|
||||
return mScreenshotPath;
|
||||
}
|
||||
public String getDescription() {
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
public static ContentValues asContentValues(String title, String description,
|
||||
int country, String path, String gameId, String company)
|
||||
{
|
||||
ContentValues values = new ContentValues();
|
||||
public String getCompany() {
|
||||
return mCompany;
|
||||
}
|
||||
|
||||
String screenPath = PATH_SCREENSHOT_FOLDER + gameId + "/" + gameId + "-1.png";
|
||||
public int getCountry() {
|
||||
return mCountry;
|
||||
}
|
||||
|
||||
values.put(GameDatabase.KEY_GAME_TITLE, title);
|
||||
values.put(GameDatabase.KEY_GAME_DESCRIPTION, description);
|
||||
values.put(GameDatabase.KEY_GAME_COUNTRY, country);
|
||||
values.put(GameDatabase.KEY_GAME_PATH, path);
|
||||
values.put(GameDatabase.KEY_GAME_ID, gameId);
|
||||
values.put(GameDatabase.KEY_GAME_COMPANY, company);
|
||||
values.put(GameDatabase.KEY_GAME_SCREENSHOT_PATH, screenPath);
|
||||
public String getPath() {
|
||||
return mPath;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
public String getGameId() {
|
||||
return mGameId;
|
||||
}
|
||||
|
||||
public static Game fromCursor(Cursor cursor)
|
||||
{
|
||||
return new Game(cursor.getString(GameDatabase.GAME_COLUMN_TITLE),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_DESCRIPTION),
|
||||
cursor.getInt(GameDatabase.GAME_COLUMN_COUNTRY),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_PATH),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_GAME_ID),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_COMPANY),
|
||||
cursor.getString(GameDatabase.GAME_COLUMN_SCREENSHOT_PATH));
|
||||
}
|
||||
public String getScreenshotPath() {
|
||||
return mScreenshotPath;
|
||||
}
|
||||
}
|
||||
|
@ -20,273 +20,241 @@ import rx.Observable;
|
||||
* A helper class that provides several utilities simplifying interaction with
|
||||
* the SQLite database.
|
||||
*/
|
||||
public final class GameDatabase extends SQLiteOpenHelper
|
||||
{
|
||||
private static final int DB_VERSION = 1;
|
||||
public final class GameDatabase extends SQLiteOpenHelper {
|
||||
public static final int COLUMN_DB_ID = 0;
|
||||
public static final int GAME_COLUMN_PATH = 1;
|
||||
public static final int GAME_COLUMN_TITLE = 2;
|
||||
public static final int GAME_COLUMN_DESCRIPTION = 3;
|
||||
public static final int GAME_COLUMN_COUNTRY = 4;
|
||||
public static final int GAME_COLUMN_GAME_ID = 5;
|
||||
public static final int GAME_COLUMN_COMPANY = 6;
|
||||
public static final int GAME_COLUMN_SCREENSHOT_PATH = 7;
|
||||
public static final int FOLDER_COLUMN_PATH = 1;
|
||||
public static final String KEY_DB_ID = "_id";
|
||||
public static final String KEY_GAME_PATH = "path";
|
||||
public static final String KEY_GAME_TITLE = "title";
|
||||
public static final String KEY_GAME_DESCRIPTION = "description";
|
||||
public static final String KEY_GAME_COUNTRY = "country";
|
||||
public static final String KEY_GAME_ID = "game_id";
|
||||
public static final String KEY_GAME_COMPANY = "company";
|
||||
public static final String KEY_GAME_SCREENSHOT_PATH = "screenshot_path";
|
||||
public static final String KEY_FOLDER_PATH = "path";
|
||||
public static final String TABLE_NAME_FOLDERS = "folders";
|
||||
public static final String TABLE_NAME_GAMES = "games";
|
||||
private static final int DB_VERSION = 1;
|
||||
private static final String TYPE_PRIMARY = " INTEGER PRIMARY KEY";
|
||||
private static final String TYPE_INTEGER = " INTEGER";
|
||||
private static final String TYPE_STRING = " TEXT";
|
||||
|
||||
public static final int COLUMN_DB_ID = 0;
|
||||
private static final String CONSTRAINT_UNIQUE = " UNIQUE";
|
||||
|
||||
public static final int GAME_COLUMN_PATH = 1;
|
||||
public static final int GAME_COLUMN_TITLE = 2;
|
||||
public static final int GAME_COLUMN_DESCRIPTION = 3;
|
||||
public static final int GAME_COLUMN_COUNTRY = 4;
|
||||
public static final int GAME_COLUMN_GAME_ID = 5;
|
||||
public static final int GAME_COLUMN_COMPANY = 6;
|
||||
public static final int GAME_COLUMN_SCREENSHOT_PATH = 7;
|
||||
private static final String SEPARATOR = ", ";
|
||||
|
||||
public static final int FOLDER_COLUMN_PATH = 1;
|
||||
private static final String SQL_CREATE_GAMES = "CREATE TABLE " + TABLE_NAME_GAMES + "("
|
||||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR
|
||||
+ KEY_GAME_PATH + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_TITLE + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_DESCRIPTION + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_COUNTRY + TYPE_INTEGER + SEPARATOR
|
||||
+ KEY_GAME_ID + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_COMPANY + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_SCREENSHOT_PATH + TYPE_STRING + ")";
|
||||
|
||||
public static final String KEY_DB_ID = "_id";
|
||||
private static final String SQL_CREATE_FOLDERS = "CREATE TABLE " + TABLE_NAME_FOLDERS + "("
|
||||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR
|
||||
+ KEY_FOLDER_PATH + TYPE_STRING + CONSTRAINT_UNIQUE + ")";
|
||||
|
||||
public static final String KEY_GAME_PATH = "path";
|
||||
public static final String KEY_GAME_TITLE = "title";
|
||||
public static final String KEY_GAME_DESCRIPTION = "description";
|
||||
public static final String KEY_GAME_COUNTRY = "country";
|
||||
public static final String KEY_GAME_ID = "game_id";
|
||||
public static final String KEY_GAME_COMPANY = "company";
|
||||
public static final String KEY_GAME_SCREENSHOT_PATH = "screenshot_path";
|
||||
private static final String SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS " + TABLE_NAME_FOLDERS;
|
||||
private static final String SQL_DELETE_GAMES = "DROP TABLE IF EXISTS " + TABLE_NAME_GAMES;
|
||||
|
||||
public static final String KEY_FOLDER_PATH = "path";
|
||||
|
||||
public static final String TABLE_NAME_FOLDERS = "folders";
|
||||
public static final String TABLE_NAME_GAMES = "games";
|
||||
|
||||
private static final String TYPE_PRIMARY = " INTEGER PRIMARY KEY";
|
||||
private static final String TYPE_INTEGER = " INTEGER";
|
||||
private static final String TYPE_STRING = " TEXT";
|
||||
|
||||
private static final String CONSTRAINT_UNIQUE = " UNIQUE";
|
||||
|
||||
private static final String SEPARATOR = ", ";
|
||||
|
||||
private static final String SQL_CREATE_GAMES = "CREATE TABLE " + TABLE_NAME_GAMES + "("
|
||||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR
|
||||
+ KEY_GAME_PATH + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_TITLE + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_DESCRIPTION + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_COUNTRY + TYPE_INTEGER + SEPARATOR
|
||||
+ KEY_GAME_ID + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_COMPANY + TYPE_STRING + SEPARATOR
|
||||
+ KEY_GAME_SCREENSHOT_PATH + TYPE_STRING + ")";
|
||||
|
||||
private static final String SQL_CREATE_FOLDERS = "CREATE TABLE " + TABLE_NAME_FOLDERS + "("
|
||||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR
|
||||
+ KEY_FOLDER_PATH + TYPE_STRING + CONSTRAINT_UNIQUE + ")";
|
||||
|
||||
private static final String SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS " + TABLE_NAME_FOLDERS;
|
||||
private static final String SQL_DELETE_GAMES = "DROP TABLE IF EXISTS " + TABLE_NAME_GAMES;
|
||||
|
||||
public GameDatabase(Context context)
|
||||
{
|
||||
// Superclass constructor builds a database or uses an existing one.
|
||||
super(context, "games.db", null, DB_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase database)
|
||||
{
|
||||
Log.debug("[GameDatabase] GameDatabase - Creating database...");
|
||||
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
||||
execSqlAndLog(database, SQL_CREATE_FOLDERS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion)
|
||||
{
|
||||
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases..");
|
||||
execSqlAndLog(database, SQL_DELETE_FOLDERS);
|
||||
execSqlAndLog(database, SQL_CREATE_FOLDERS);
|
||||
|
||||
execSqlAndLog(database, SQL_DELETE_GAMES);
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion)
|
||||
{
|
||||
Log.info("[GameDatabase] Upgrading database from schema version " + oldVersion + " to " +
|
||||
newVersion);
|
||||
|
||||
// Delete all the games
|
||||
execSqlAndLog(database, SQL_DELETE_GAMES);
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
||||
|
||||
Log.verbose("[GameDatabase] Re-scanning library with new schema.");
|
||||
scanLibrary(database);
|
||||
}
|
||||
|
||||
public void scanLibrary(SQLiteDatabase database)
|
||||
{
|
||||
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing.
|
||||
Cursor fileCursor = database.query(TABLE_NAME_GAMES,
|
||||
null, // Get all columns.
|
||||
null, // Get all rows.
|
||||
null,
|
||||
null, // No grouping.
|
||||
null,
|
||||
null); // Order of games is irrelevant.
|
||||
|
||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
||||
fileCursor.moveToPosition(-1);
|
||||
|
||||
while (fileCursor.moveToNext())
|
||||
{
|
||||
String gamePath = fileCursor.getString(GAME_COLUMN_PATH);
|
||||
File game = new File(gamePath);
|
||||
|
||||
if (!game.exists())
|
||||
{
|
||||
Log.error("[GameDatabase] Game file no longer exists. Removing from the library: " +
|
||||
gamePath);
|
||||
database.delete(TABLE_NAME_GAMES,
|
||||
KEY_DB_ID + " = ?",
|
||||
new String[]{Long.toString(fileCursor.getLong(COLUMN_DB_ID))});
|
||||
}
|
||||
public GameDatabase(Context context) {
|
||||
// Superclass constructor builds a database or uses an existing one.
|
||||
super(context, "games.db", null, DB_VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase database) {
|
||||
Log.debug("[GameDatabase] GameDatabase - Creating database...");
|
||||
|
||||
// Get a cursor listing all the folders the user has added to the library.
|
||||
Cursor folderCursor = database.query(TABLE_NAME_FOLDERS,
|
||||
null, // Get all columns.
|
||||
null, // Get all rows.
|
||||
null,
|
||||
null, // No grouping.
|
||||
null,
|
||||
null); // Order of folders is irrelevant.
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
||||
execSqlAndLog(database, SQL_CREATE_FOLDERS);
|
||||
}
|
||||
|
||||
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(
|
||||
".3ds", ".3ds", ".3dsx", ".elf", ".axf", ".cci", ".cxi", ".app"));
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) {
|
||||
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases..");
|
||||
execSqlAndLog(database, SQL_DELETE_FOLDERS);
|
||||
execSqlAndLog(database, SQL_CREATE_FOLDERS);
|
||||
|
||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
||||
folderCursor.moveToPosition(-1);
|
||||
execSqlAndLog(database, SQL_DELETE_GAMES);
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
||||
}
|
||||
|
||||
// Iterate through all results of the DB query (i.e. all folders in the library.)
|
||||
while (folderCursor.moveToNext())
|
||||
{
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
|
||||
Log.info("[GameDatabase] Upgrading database from schema version " + oldVersion + " to " +
|
||||
newVersion);
|
||||
|
||||
String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH);
|
||||
File folder = new File(folderPath);
|
||||
// Delete all the games
|
||||
execSqlAndLog(database, SQL_DELETE_GAMES);
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES);
|
||||
|
||||
Log.info("[GameDatabase] Reading files from library folder: " + folderPath);
|
||||
Log.verbose("[GameDatabase] Re-scanning library with new schema.");
|
||||
scanLibrary(database);
|
||||
}
|
||||
|
||||
// Iterate through every file in the folder.
|
||||
File[] children = folder.listFiles();
|
||||
public void scanLibrary(SQLiteDatabase database) {
|
||||
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing.
|
||||
Cursor fileCursor = database.query(TABLE_NAME_GAMES,
|
||||
null, // Get all columns.
|
||||
null, // Get all rows.
|
||||
null,
|
||||
null, // No grouping.
|
||||
null,
|
||||
null); // Order of games is irrelevant.
|
||||
|
||||
if (children != null)
|
||||
{
|
||||
for (File file : children)
|
||||
{
|
||||
if (!file.isHidden() && !file.isDirectory())
|
||||
{
|
||||
String filePath = file.getPath();
|
||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
||||
fileCursor.moveToPosition(-1);
|
||||
|
||||
int extensionStart = filePath.lastIndexOf('.');
|
||||
if (extensionStart > 0)
|
||||
{
|
||||
String fileExtension = filePath.substring(extensionStart);
|
||||
while (fileCursor.moveToNext()) {
|
||||
String gamePath = fileCursor.getString(GAME_COLUMN_PATH);
|
||||
File game = new File(gamePath);
|
||||
|
||||
// Check that the file has an extension we care about before trying to read out of it.
|
||||
if (allowedExtensions.contains(fileExtension.toLowerCase()))
|
||||
{
|
||||
String name = NativeLibrary.GetTitle(filePath);
|
||||
|
||||
// If the game's title field is empty, use the filename.
|
||||
if (name.isEmpty())
|
||||
{
|
||||
name = filePath.substring(filePath.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
String gameId = NativeLibrary.GetGameId(filePath);
|
||||
|
||||
// If the game's ID field is empty, use the filename without extension.
|
||||
if (gameId.isEmpty())
|
||||
{
|
||||
gameId = filePath.substring(filePath.lastIndexOf("/") + 1,
|
||||
filePath.lastIndexOf("."));
|
||||
}
|
||||
|
||||
ContentValues game = Game.asContentValues(name,
|
||||
NativeLibrary.GetDescription(filePath).replace("\n", " "),
|
||||
NativeLibrary.GetCountry(filePath),
|
||||
filePath,
|
||||
gameId,
|
||||
NativeLibrary.GetCompany(filePath));
|
||||
|
||||
// Try to update an existing game first.
|
||||
int rowsMatched = database.update(TABLE_NAME_GAMES, // Which table to update.
|
||||
game,
|
||||
// The values to fill the row with.
|
||||
KEY_GAME_ID + " = ?",
|
||||
// The WHERE clause used to find the right row.
|
||||
new String[]{game.getAsString(
|
||||
KEY_GAME_ID)}); // The ? in WHERE clause is replaced with this,
|
||||
// which is provided as an array because there
|
||||
// could potentially be more than one argument.
|
||||
|
||||
// If update fails, insert a new game instead.
|
||||
if (rowsMatched == 0)
|
||||
{
|
||||
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE));
|
||||
database.insert(TABLE_NAME_GAMES, null, game);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE));
|
||||
}
|
||||
}
|
||||
if (!game.exists()) {
|
||||
Log.error("[GameDatabase] Game file no longer exists. Removing from the library: " +
|
||||
gamePath);
|
||||
database.delete(TABLE_NAME_GAMES,
|
||||
KEY_DB_ID + " = ?",
|
||||
new String[]{Long.toString(fileCursor.getLong(COLUMN_DB_ID))});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the folder is empty because it no longer exists, remove it from the library.
|
||||
else if (!folder.exists())
|
||||
{
|
||||
Log.error(
|
||||
"[GameDatabase] Folder no longer exists. Removing from the library: " + folderPath);
|
||||
database.delete(TABLE_NAME_FOLDERS,
|
||||
KEY_DB_ID + " = ?",
|
||||
new String[]{Long.toString(folderCursor.getLong(COLUMN_DB_ID))});
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error("[GameDatabase] Folder contains no games: " + folderPath);
|
||||
}
|
||||
|
||||
|
||||
// Get a cursor listing all the folders the user has added to the library.
|
||||
Cursor folderCursor = database.query(TABLE_NAME_FOLDERS,
|
||||
null, // Get all columns.
|
||||
null, // Get all rows.
|
||||
null,
|
||||
null, // No grouping.
|
||||
null,
|
||||
null); // Order of folders is irrelevant.
|
||||
|
||||
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList(
|
||||
".3ds", ".3ds", ".3dsx", ".elf", ".axf", ".cci", ".cxi", ".app"));
|
||||
|
||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row.
|
||||
folderCursor.moveToPosition(-1);
|
||||
|
||||
// Iterate through all results of the DB query (i.e. all folders in the library.)
|
||||
while (folderCursor.moveToNext()) {
|
||||
|
||||
String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH);
|
||||
File folder = new File(folderPath);
|
||||
|
||||
Log.info("[GameDatabase] Reading files from library folder: " + folderPath);
|
||||
|
||||
// Iterate through every file in the folder.
|
||||
File[] children = folder.listFiles();
|
||||
|
||||
if (children != null) {
|
||||
for (File file : children) {
|
||||
if (!file.isHidden() && !file.isDirectory()) {
|
||||
String filePath = file.getPath();
|
||||
|
||||
int extensionStart = filePath.lastIndexOf('.');
|
||||
if (extensionStart > 0) {
|
||||
String fileExtension = filePath.substring(extensionStart);
|
||||
|
||||
// Check that the file has an extension we care about before trying to read out of it.
|
||||
if (allowedExtensions.contains(fileExtension.toLowerCase())) {
|
||||
String name = NativeLibrary.GetTitle(filePath);
|
||||
|
||||
// If the game's title field is empty, use the filename.
|
||||
if (name.isEmpty()) {
|
||||
name = filePath.substring(filePath.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
String gameId = NativeLibrary.GetGameId(filePath);
|
||||
|
||||
// If the game's ID field is empty, use the filename without extension.
|
||||
if (gameId.isEmpty()) {
|
||||
gameId = filePath.substring(filePath.lastIndexOf("/") + 1,
|
||||
filePath.lastIndexOf("."));
|
||||
}
|
||||
|
||||
ContentValues game = Game.asContentValues(name,
|
||||
NativeLibrary.GetDescription(filePath).replace("\n", " "),
|
||||
NativeLibrary.GetCountry(filePath),
|
||||
filePath,
|
||||
gameId,
|
||||
NativeLibrary.GetCompany(filePath));
|
||||
|
||||
// Try to update an existing game first.
|
||||
int rowsMatched = database.update(TABLE_NAME_GAMES, // Which table to update.
|
||||
game,
|
||||
// The values to fill the row with.
|
||||
KEY_GAME_ID + " = ?",
|
||||
// The WHERE clause used to find the right row.
|
||||
new String[]{game.getAsString(
|
||||
KEY_GAME_ID)}); // The ? in WHERE clause is replaced with this,
|
||||
// which is provided as an array because there
|
||||
// could potentially be more than one argument.
|
||||
|
||||
// If update fails, insert a new game instead.
|
||||
if (rowsMatched == 0) {
|
||||
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE));
|
||||
database.insert(TABLE_NAME_GAMES, null, game);
|
||||
} else {
|
||||
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the folder is empty because it no longer exists, remove it from the library.
|
||||
else if (!folder.exists()) {
|
||||
Log.error(
|
||||
"[GameDatabase] Folder no longer exists. Removing from the library: " + folderPath);
|
||||
database.delete(TABLE_NAME_FOLDERS,
|
||||
KEY_DB_ID + " = ?",
|
||||
new String[]{Long.toString(folderCursor.getLong(COLUMN_DB_ID))});
|
||||
} else {
|
||||
Log.error("[GameDatabase] Folder contains no games: " + folderPath);
|
||||
}
|
||||
}
|
||||
|
||||
fileCursor.close();
|
||||
folderCursor.close();
|
||||
database.close();
|
||||
}
|
||||
|
||||
fileCursor.close();
|
||||
folderCursor.close();
|
||||
database.close();
|
||||
}
|
||||
public Observable<Cursor> getGames() {
|
||||
return Observable.create(subscriber ->
|
||||
{
|
||||
Log.info("[GameDatabase] Reading games list...");
|
||||
|
||||
public Observable<Cursor> getGames()
|
||||
{
|
||||
return Observable.create(subscriber ->
|
||||
{
|
||||
Log.info("[GameDatabase] Reading games list...");
|
||||
SQLiteDatabase database = getReadableDatabase();
|
||||
Cursor resultCursor = database.query(
|
||||
TABLE_NAME_GAMES,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
KEY_GAME_TITLE + " ASC"
|
||||
);
|
||||
|
||||
SQLiteDatabase database = getReadableDatabase();
|
||||
Cursor resultCursor = database.query(
|
||||
TABLE_NAME_GAMES,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
KEY_GAME_TITLE + " ASC"
|
||||
);
|
||||
// Pass the result cursor to the consumer.
|
||||
subscriber.onNext(resultCursor);
|
||||
|
||||
// Pass the result cursor to the consumer.
|
||||
subscriber.onNext(resultCursor);
|
||||
// Tell the consumer we're done; it will unsubscribe implicitly.
|
||||
subscriber.onCompleted();
|
||||
});
|
||||
}
|
||||
|
||||
// Tell the consumer we're done; it will unsubscribe implicitly.
|
||||
subscriber.onCompleted();
|
||||
});
|
||||
}
|
||||
|
||||
private void execSqlAndLog(SQLiteDatabase database, String sql)
|
||||
{
|
||||
Log.verbose("[GameDatabase] Executing SQL: " + sql);
|
||||
database.execSQL(sql);
|
||||
}
|
||||
private void execSqlAndLog(SQLiteDatabase database, String sql) {
|
||||
Log.verbose("[GameDatabase] Executing SQL: " + sql);
|
||||
database.execSQL(sql);
|
||||
}
|
||||
}
|
||||
|
@ -14,142 +14,122 @@ import org.citra.citra_android.utils.Log;
|
||||
* Provides an interface allowing Activities to interact with the SQLite database.
|
||||
* CRUD methods in this class can be called by Activities using getContentResolver().
|
||||
*/
|
||||
public final class GameProvider extends ContentProvider
|
||||
{
|
||||
public static final String REFRESH_LIBRARY = "refresh";
|
||||
public final class GameProvider extends ContentProvider {
|
||||
public static final String REFRESH_LIBRARY = "refresh";
|
||||
|
||||
public static final String AUTHORITY = "content://" + BuildConfig.APPLICATION_ID + ".provider";
|
||||
public static final Uri URI_FOLDER =
|
||||
Uri.parse(AUTHORITY + "/" + GameDatabase.TABLE_NAME_FOLDERS + "/");
|
||||
public static final Uri URI_GAME =
|
||||
Uri.parse(AUTHORITY + "/" + GameDatabase.TABLE_NAME_GAMES + "/");
|
||||
public static final Uri URI_REFRESH = Uri.parse(AUTHORITY + "/" + REFRESH_LIBRARY + "/");
|
||||
public static final String AUTHORITY = "content://" + BuildConfig.APPLICATION_ID + ".provider";
|
||||
public static final Uri URI_FOLDER =
|
||||
Uri.parse(AUTHORITY + "/" + GameDatabase.TABLE_NAME_FOLDERS + "/");
|
||||
public static final Uri URI_GAME =
|
||||
Uri.parse(AUTHORITY + "/" + GameDatabase.TABLE_NAME_GAMES + "/");
|
||||
public static final Uri URI_REFRESH = Uri.parse(AUTHORITY + "/" + REFRESH_LIBRARY + "/");
|
||||
|
||||
public static final String MIME_TYPE_FOLDER = "vnd.android.cursor.item/vnd.dolphin.folder";
|
||||
public static final String MIME_TYPE_GAME = "vnd.android.cursor.item/vnd.dolphin.game";
|
||||
public static final String MIME_TYPE_FOLDER = "vnd.android.cursor.item/vnd.dolphin.folder";
|
||||
public static final String MIME_TYPE_GAME = "vnd.android.cursor.item/vnd.dolphin.game";
|
||||
|
||||
|
||||
private GameDatabase mDbHelper;
|
||||
private GameDatabase mDbHelper;
|
||||
|
||||
@Override
|
||||
public boolean onCreate()
|
||||
{
|
||||
Log.info("[GameProvider] Creating Content Provider...");
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
Log.info("[GameProvider] Creating Content Provider...");
|
||||
|
||||
mDbHelper = new GameDatabase(getContext());
|
||||
mDbHelper = new GameDatabase(getContext());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
|
||||
String[] selectionArgs, String sortOrder)
|
||||
{
|
||||
Log.info("[GameProvider] Querying URI: " + uri);
|
||||
|
||||
SQLiteDatabase db = mDbHelper.getReadableDatabase();
|
||||
|
||||
String table = uri.getLastPathSegment();
|
||||
|
||||
if (table == null)
|
||||
{
|
||||
Log.error("[GameProvider] Badly formatted URI: " + uri);
|
||||
return null;
|
||||
return true;
|
||||
}
|
||||
|
||||
Cursor cursor = db.query(table, projection, selection, selectionArgs, null, null, sortOrder);
|
||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
@Override
|
||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection,
|
||||
String[] selectionArgs, String sortOrder) {
|
||||
Log.info("[GameProvider] Querying URI: " + uri);
|
||||
|
||||
return cursor;
|
||||
}
|
||||
SQLiteDatabase db = mDbHelper.getReadableDatabase();
|
||||
|
||||
@Override
|
||||
public String getType(@NonNull Uri uri)
|
||||
{
|
||||
Log.verbose("[GameProvider] Getting MIME type for URI: " + uri);
|
||||
String lastSegment = uri.getLastPathSegment();
|
||||
String table = uri.getLastPathSegment();
|
||||
|
||||
if (lastSegment == null)
|
||||
{
|
||||
Log.error("[GameProvider] Badly formatted URI: " + uri);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (lastSegment.equals(GameDatabase.TABLE_NAME_FOLDERS))
|
||||
{
|
||||
return MIME_TYPE_FOLDER;
|
||||
}
|
||||
else if (lastSegment.equals(GameDatabase.TABLE_NAME_GAMES))
|
||||
{
|
||||
return MIME_TYPE_GAME;
|
||||
}
|
||||
|
||||
Log.error("[GameProvider] Unknown MIME type for URI: " + uri);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(@NonNull Uri uri, ContentValues values)
|
||||
{
|
||||
Log.info("[GameProvider] Inserting row at URI: " + uri);
|
||||
|
||||
SQLiteDatabase database = mDbHelper.getWritableDatabase();
|
||||
String table = uri.getLastPathSegment();
|
||||
|
||||
long id = -1;
|
||||
|
||||
if (table != null)
|
||||
{
|
||||
if (table.equals(REFRESH_LIBRARY))
|
||||
{
|
||||
Log.info(
|
||||
"[GameProvider] URI specified table REFRESH_LIBRARY. No insertion necessary; refreshing library contents...");
|
||||
mDbHelper.scanLibrary(database);
|
||||
return uri;
|
||||
}
|
||||
|
||||
id = database.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
|
||||
// If insertion was successful...
|
||||
if (id > 0)
|
||||
{
|
||||
// If we just added a folder, add its contents to the game list.
|
||||
if (table.equals(GameDatabase.TABLE_NAME_FOLDERS))
|
||||
{
|
||||
mDbHelper.scanLibrary(database);
|
||||
if (table == null) {
|
||||
Log.error("[GameProvider] Badly formatted URI: " + uri);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Notify the UI that its contents should be refreshed.
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
uri = Uri.withAppendedPath(uri, Long.toString(id));
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error("[GameProvider] Row already exists: " + uri + " id: " + id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error("[GameProvider] Badly formatted URI: " + uri);
|
||||
Cursor cursor = db.query(table, projection, selection, selectionArgs, null, null, sortOrder);
|
||||
cursor.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
database.close();
|
||||
@Override
|
||||
public String getType(@NonNull Uri uri) {
|
||||
Log.verbose("[GameProvider] Getting MIME type for URI: " + uri);
|
||||
String lastSegment = uri.getLastPathSegment();
|
||||
|
||||
return uri;
|
||||
}
|
||||
if (lastSegment == null) {
|
||||
Log.error("[GameProvider] Badly formatted URI: " + uri);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs)
|
||||
{
|
||||
Log.error("[GameProvider] Delete operations unsupported. URI: " + uri);
|
||||
return 0;
|
||||
}
|
||||
if (lastSegment.equals(GameDatabase.TABLE_NAME_FOLDERS)) {
|
||||
return MIME_TYPE_FOLDER;
|
||||
} else if (lastSegment.equals(GameDatabase.TABLE_NAME_GAMES)) {
|
||||
return MIME_TYPE_GAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(@NonNull Uri uri, ContentValues values, String selection,
|
||||
String[] selectionArgs)
|
||||
{
|
||||
Log.error("[GameProvider] Update operations unsupported. URI: " + uri);
|
||||
return 0;
|
||||
}
|
||||
Log.error("[GameProvider] Unknown MIME type for URI: " + uri);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri insert(@NonNull Uri uri, ContentValues values) {
|
||||
Log.info("[GameProvider] Inserting row at URI: " + uri);
|
||||
|
||||
SQLiteDatabase database = mDbHelper.getWritableDatabase();
|
||||
String table = uri.getLastPathSegment();
|
||||
|
||||
long id = -1;
|
||||
|
||||
if (table != null) {
|
||||
if (table.equals(REFRESH_LIBRARY)) {
|
||||
Log.info(
|
||||
"[GameProvider] URI specified table REFRESH_LIBRARY. No insertion necessary; refreshing library contents...");
|
||||
mDbHelper.scanLibrary(database);
|
||||
return uri;
|
||||
}
|
||||
|
||||
id = database.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_IGNORE);
|
||||
|
||||
// If insertion was successful...
|
||||
if (id > 0) {
|
||||
// If we just added a folder, add its contents to the game list.
|
||||
if (table.equals(GameDatabase.TABLE_NAME_FOLDERS)) {
|
||||
mDbHelper.scanLibrary(database);
|
||||
}
|
||||
|
||||
// Notify the UI that its contents should be refreshed.
|
||||
getContext().getContentResolver().notifyChange(uri, null);
|
||||
uri = Uri.withAppendedPath(uri, Long.toString(id));
|
||||
} else {
|
||||
Log.error("[GameProvider] Row already exists: " + uri + " id: " + id);
|
||||
}
|
||||
} else {
|
||||
Log.error("[GameProvider] Badly formatted URI: " + uri);
|
||||
}
|
||||
|
||||
database.close();
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
|
||||
Log.error("[GameProvider] Delete operations unsupported. URI: " + uri);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(@NonNull Uri uri, ContentValues values, String selection,
|
||||
String[] selectionArgs) {
|
||||
Log.error("[GameProvider] Update operations unsupported. URI: " + uri);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +1,25 @@
|
||||
package org.citra.citra_android.model;
|
||||
|
||||
public final class TvSettingsItem
|
||||
{
|
||||
private final int mItemId;
|
||||
private final int mIconId;
|
||||
private final int mLabelId;
|
||||
public final class TvSettingsItem {
|
||||
private final int mItemId;
|
||||
private final int mIconId;
|
||||
private final int mLabelId;
|
||||
|
||||
public TvSettingsItem(int itemId, int iconId, int labelId)
|
||||
{
|
||||
mItemId = itemId;
|
||||
mIconId = iconId;
|
||||
mLabelId = labelId;
|
||||
}
|
||||
public TvSettingsItem(int itemId, int iconId, int labelId) {
|
||||
mItemId = itemId;
|
||||
mIconId = iconId;
|
||||
mLabelId = labelId;
|
||||
}
|
||||
|
||||
public int getItemId()
|
||||
{
|
||||
return mItemId;
|
||||
}
|
||||
public int getItemId() {
|
||||
return mItemId;
|
||||
}
|
||||
|
||||
public int getIconId()
|
||||
{
|
||||
return mIconId;
|
||||
}
|
||||
public int getIconId() {
|
||||
return mIconId;
|
||||
}
|
||||
|
||||
public int getLabelId()
|
||||
{
|
||||
return mLabelId;
|
||||
}
|
||||
public int getLabelId() {
|
||||
return mLabelId;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
package org.citra.citra_android.model.settings;
|
||||
|
||||
public final class BooleanSetting extends Setting {
|
||||
private boolean mValue;
|
||||
|
||||
public BooleanSetting(String key, String section, int file, boolean value) {
|
||||
super(key, section, file);
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public boolean getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(boolean value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAsString() {
|
||||
return mValue ? "True" : "False";
|
||||
}
|
||||
}
|
@ -1,28 +1,23 @@
|
||||
package org.citra.citra_android.model.settings;
|
||||
|
||||
public final class FloatSetting extends Setting
|
||||
{
|
||||
private float mValue;
|
||||
public final class FloatSetting extends Setting {
|
||||
private float mValue;
|
||||
|
||||
public FloatSetting(String key, String section, int file, float value)
|
||||
{
|
||||
super(key, section, file);
|
||||
mValue = value;
|
||||
}
|
||||
public FloatSetting(String key, String section, int file, float value) {
|
||||
super(key, section, file);
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public float getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
public float getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(float value)
|
||||
{
|
||||
mValue = value;
|
||||
}
|
||||
public void setValue(float value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAsString()
|
||||
{
|
||||
return Float.toString(mValue);
|
||||
}
|
||||
@Override
|
||||
public String getValueAsString() {
|
||||
return Float.toString(mValue);
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,23 @@
|
||||
package org.citra.citra_android.model.settings;
|
||||
|
||||
public final class IntSetting extends Setting
|
||||
{
|
||||
private int mValue;
|
||||
public final class IntSetting extends Setting {
|
||||
private int mValue;
|
||||
|
||||
public IntSetting(String key, String section, int file, int value)
|
||||
{
|
||||
super(key, section, file);
|
||||
mValue = value;
|
||||
}
|
||||
public IntSetting(String key, String section, int file, int value) {
|
||||
super(key, section, file);
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public int getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
public int getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(int value)
|
||||
{
|
||||
mValue = value;
|
||||
}
|
||||
public void setValue(int value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAsString()
|
||||
{
|
||||
return Integer.toString(mValue);
|
||||
}
|
||||
@Override
|
||||
public String getValueAsString() {
|
||||
return Integer.toString(mValue);
|
||||
}
|
||||
}
|
||||
|
@ -6,52 +6,47 @@ package org.citra.citra_android.model.settings;
|
||||
* must be inferred at read-time. The type of value determines which child of this class is used
|
||||
* to represent the Setting.
|
||||
*/
|
||||
public abstract class Setting
|
||||
{
|
||||
private String mKey;
|
||||
private String mSection;
|
||||
private int mFile;
|
||||
public abstract class Setting {
|
||||
private String mKey;
|
||||
private String mSection;
|
||||
private int mFile;
|
||||
|
||||
/**
|
||||
* Base constructor.
|
||||
*
|
||||
* @param key Everything to the left of the = in a line from the ini file.
|
||||
* @param section The corresponding recent section header; e.g. [Core] or [Enhancements] without the brackets.
|
||||
* @param file The ini file the Setting is stored in.
|
||||
*/
|
||||
public Setting(String key, String section, int file)
|
||||
{
|
||||
mKey = key;
|
||||
mSection = section;
|
||||
mFile = file;
|
||||
}
|
||||
/**
|
||||
* Base constructor.
|
||||
*
|
||||
* @param key Everything to the left of the = in a line from the ini file.
|
||||
* @param section The corresponding recent section header; e.g. [Core] or [Enhancements] without the brackets.
|
||||
* @param file The ini file the Setting is stored in.
|
||||
*/
|
||||
public Setting(String key, String section, int file) {
|
||||
mKey = key;
|
||||
mSection = section;
|
||||
mFile = file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The identifier used to write this setting to the ini file.
|
||||
*/
|
||||
public String getKey()
|
||||
{
|
||||
return mKey;
|
||||
}
|
||||
/**
|
||||
* @return The identifier used to write this setting to the ini file.
|
||||
*/
|
||||
public String getKey() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The name of the header under which this Setting should be written in the ini file.
|
||||
*/
|
||||
public String getSection()
|
||||
{
|
||||
return mSection;
|
||||
}
|
||||
/**
|
||||
* @return The name of the header under which this Setting should be written in the ini file.
|
||||
*/
|
||||
public String getSection() {
|
||||
return mSection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The ini file the Setting is stored in.
|
||||
*/
|
||||
public int getFile()
|
||||
{
|
||||
return mFile;
|
||||
}
|
||||
/**
|
||||
* @return The ini file the Setting is stored in.
|
||||
*/
|
||||
public int getFile() {
|
||||
return mFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A representation of this Setting's backing value converted to a String (e.g. for serialization).
|
||||
*/
|
||||
public abstract String getValueAsString();
|
||||
/**
|
||||
* @return A representation of this Setting's backing value converted to a String (e.g. for serialization).
|
||||
*/
|
||||
public abstract String getValueAsString();
|
||||
}
|
||||
|
@ -6,50 +6,44 @@ import java.util.HashMap;
|
||||
* A semantically-related group of Settings objects. These Settings are
|
||||
* internally stored as a HashMap.
|
||||
*/
|
||||
public final class SettingSection
|
||||
{
|
||||
private String mName;
|
||||
public final class SettingSection {
|
||||
private String mName;
|
||||
|
||||
private HashMap<String, Setting> mSettings = new HashMap<>();
|
||||
private HashMap<String, Setting> mSettings = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create a new SettingSection with no Settings in it.
|
||||
*
|
||||
* @param name The header of this section; e.g. [Core] or [Enhancements] without the brackets.
|
||||
*/
|
||||
public SettingSection(String name)
|
||||
{
|
||||
mName = name;
|
||||
}
|
||||
/**
|
||||
* Create a new SettingSection with no Settings in it.
|
||||
*
|
||||
* @param name The header of this section; e.g. [Core] or [Enhancements] without the brackets.
|
||||
*/
|
||||
public SettingSection(String name) {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method; inserts a value directly into the backing HashMap.
|
||||
*
|
||||
* @param setting The Setting to be inserted.
|
||||
*/
|
||||
public void putSetting(Setting setting)
|
||||
{
|
||||
mSettings.put(setting.getKey(), setting);
|
||||
}
|
||||
/**
|
||||
* Convenience method; inserts a value directly into the backing HashMap.
|
||||
*
|
||||
* @param setting The Setting to be inserted.
|
||||
*/
|
||||
public void putSetting(Setting setting) {
|
||||
mSettings.put(setting.getKey(), setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method; gets a value directly from the backing HashMap.
|
||||
*
|
||||
* @param key Used to retrieve the Setting.
|
||||
* @return A Setting object (you should probably cast this before using)
|
||||
*/
|
||||
public Setting getSetting(String key)
|
||||
{
|
||||
return mSettings.get(key);
|
||||
}
|
||||
/**
|
||||
* Convenience method; gets a value directly from the backing HashMap.
|
||||
*
|
||||
* @param key Used to retrieve the Setting.
|
||||
* @return A Setting object (you should probably cast this before using)
|
||||
*/
|
||||
public Setting getSetting(String key) {
|
||||
return mSettings.get(key);
|
||||
}
|
||||
|
||||
public HashMap<String, Setting> getSettings()
|
||||
{
|
||||
return mSettings;
|
||||
}
|
||||
public HashMap<String, Setting> getSettings() {
|
||||
return mSettings;
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,23 @@
|
||||
package org.citra.citra_android.model.settings;
|
||||
|
||||
public final class StringSetting extends Setting
|
||||
{
|
||||
private String mValue;
|
||||
public final class StringSetting extends Setting {
|
||||
private String mValue;
|
||||
|
||||
public StringSetting(String key, String section, int file, String value)
|
||||
{
|
||||
super(key, section, file);
|
||||
mValue = value;
|
||||
}
|
||||
public StringSetting(String key, String section, int file, String value) {
|
||||
super(key, section, file);
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
public String getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(String value)
|
||||
{
|
||||
mValue = value;
|
||||
}
|
||||
public void setValue(String value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAsString()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
@Override
|
||||
public String getValueAsString() {
|
||||
return mValue;
|
||||
}
|
||||
}
|
||||
|
@ -3,54 +3,45 @@ package org.citra.citra_android.model.settings.view;
|
||||
import org.citra.citra_android.model.settings.IntSetting;
|
||||
import org.citra.citra_android.model.settings.Setting;
|
||||
|
||||
public final class CheckBoxSetting extends SettingsItem
|
||||
{
|
||||
private boolean mDefaultValue;
|
||||
public final class CheckBoxSetting extends SettingsItem {
|
||||
private boolean mDefaultValue;
|
||||
|
||||
public CheckBoxSetting(String key, String section, int file, int titleId, int descriptionId,
|
||||
boolean defaultValue, Setting setting)
|
||||
{
|
||||
super(key, section, file, setting, titleId, descriptionId);
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public boolean isChecked()
|
||||
{
|
||||
if (getSetting() == null)
|
||||
{
|
||||
return mDefaultValue;
|
||||
public CheckBoxSetting(String key, String section, int file, int titleId, int descriptionId,
|
||||
boolean defaultValue, Setting setting) {
|
||||
super(key, section, file, setting, titleId, descriptionId);
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
return setting.getValue() == 1;
|
||||
}
|
||||
public boolean isChecked() {
|
||||
if (getSetting() == null) {
|
||||
return mDefaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the backing boolean. If that boolean was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param checked Pretty self explanatory.
|
||||
* @return null if overwritten successfully; otherwise, a newly created BooleanSetting.
|
||||
*/
|
||||
public IntSetting setChecked(boolean checked)
|
||||
{
|
||||
if (getSetting() == null)
|
||||
{
|
||||
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), checked ? 1 : 0);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
return setting.getValue() == 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
setting.setValue(checked ? 1 : 0);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType()
|
||||
{
|
||||
return TYPE_CHECKBOX;
|
||||
}
|
||||
/**
|
||||
* Write a value to the backing boolean. If that boolean was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param checked Pretty self explanatory.
|
||||
* @return null if overwritten successfully; otherwise, a newly created BooleanSetting.
|
||||
*/
|
||||
public IntSetting setChecked(boolean checked) {
|
||||
if (getSetting() == null) {
|
||||
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), checked ? 1 : 0);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
} else {
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
setting.setValue(checked ? 1 : 0);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return TYPE_CHECKBOX;
|
||||
}
|
||||
}
|
||||
|
@ -3,39 +3,32 @@ package org.citra.citra_android.model.settings.view;
|
||||
import org.citra.citra_android.model.settings.Setting;
|
||||
import org.citra.citra_android.model.settings.StringSetting;
|
||||
|
||||
public final class DateTimeSetting extends SettingsItem
|
||||
{
|
||||
public final class DateTimeSetting extends SettingsItem {
|
||||
private String mDefaultValue;
|
||||
|
||||
public DateTimeSetting(String key, String section, int file, int titleId, int descriptionId,
|
||||
String defaultValue, Setting setting)
|
||||
{
|
||||
String defaultValue, Setting setting) {
|
||||
super(key, section, file, setting, titleId, descriptionId);
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
if (getSetting() != null)
|
||||
{
|
||||
public String getValue() {
|
||||
if (getSetting() != null) {
|
||||
StringSetting setting = (StringSetting) getSetting();
|
||||
return setting.getValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return mDefaultValue;
|
||||
}
|
||||
}
|
||||
public StringSetting setSelectedValue(String datetime)
|
||||
{
|
||||
|
||||
public StringSetting setSelectedValue(String datetime) {
|
||||
StringSetting setting = new StringSetting(getKey(), getSection(), getFile(), datetime);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType()
|
||||
{
|
||||
public int getType() {
|
||||
return TYPE_DATETIME_SETTING;
|
||||
}
|
||||
}
|
@ -2,16 +2,13 @@ package org.citra.citra_android.model.settings.view;
|
||||
|
||||
import org.citra.citra_android.model.settings.Setting;
|
||||
|
||||
public final class HeaderSetting extends SettingsItem
|
||||
{
|
||||
public HeaderSetting(String key, Setting setting, int titleId, int descriptionId)
|
||||
{
|
||||
super(key, null, 0, setting, titleId, descriptionId);
|
||||
}
|
||||
public final class HeaderSetting extends SettingsItem {
|
||||
public HeaderSetting(String key, Setting setting, int titleId, int descriptionId) {
|
||||
super(key, null, 0, setting, titleId, descriptionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType()
|
||||
{
|
||||
return SettingsItem.TYPE_HEADER;
|
||||
}
|
||||
@Override
|
||||
public int getType() {
|
||||
return SettingsItem.TYPE_HEADER;
|
||||
}
|
||||
}
|
||||
|
@ -3,50 +3,41 @@ package org.citra.citra_android.model.settings.view;
|
||||
import org.citra.citra_android.model.settings.Setting;
|
||||
import org.citra.citra_android.model.settings.StringSetting;
|
||||
|
||||
public final class InputBindingSetting extends SettingsItem
|
||||
{
|
||||
public InputBindingSetting(String key, String section, int file, int titleId, Setting setting)
|
||||
{
|
||||
super(key, section, file, setting, titleId, 0);
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
if (getSetting() == null)
|
||||
{
|
||||
return "";
|
||||
public final class InputBindingSetting extends SettingsItem {
|
||||
public InputBindingSetting(String key, String section, int file, int titleId, Setting setting) {
|
||||
super(key, section, file, setting, titleId, 0);
|
||||
}
|
||||
|
||||
StringSetting setting = (StringSetting) getSetting();
|
||||
return setting.getValue();
|
||||
}
|
||||
public String getValue() {
|
||||
if (getSetting() == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the backing string. If that string was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param bind The input that will be bound
|
||||
* @return null if overwritten successfully; otherwise, a newly created StringSetting.
|
||||
*/
|
||||
public StringSetting setValue(String bind)
|
||||
{
|
||||
if (getSetting() == null)
|
||||
{
|
||||
StringSetting setting = new StringSetting(getKey(), getSection(), getFile(), bind);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
StringSetting setting = (StringSetting) getSetting();
|
||||
return setting.getValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
StringSetting setting = (StringSetting) getSetting();
|
||||
setting.setValue(bind);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType()
|
||||
{
|
||||
return TYPE_INPUT_BINDING;
|
||||
}
|
||||
/**
|
||||
* Write a value to the backing string. If that string was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param bind The input that will be bound
|
||||
* @return null if overwritten successfully; otherwise, a newly created StringSetting.
|
||||
*/
|
||||
public StringSetting setValue(String bind) {
|
||||
if (getSetting() == null) {
|
||||
StringSetting setting = new StringSetting(getKey(), getSection(), getFile(), bind);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
} else {
|
||||
StringSetting setting = (StringSetting) getSetting();
|
||||
setting.setValue(bind);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return TYPE_INPUT_BINDING;
|
||||
}
|
||||
}
|
||||
|
@ -9,107 +9,98 @@ import org.citra.citra_android.model.settings.Setting;
|
||||
* and a few with none (Headers, for example, do not correspond to anything in the ini
|
||||
* file.)
|
||||
*/
|
||||
public abstract class SettingsItem
|
||||
{
|
||||
public static final int TYPE_HEADER = 0;
|
||||
public static final int TYPE_CHECKBOX = 1;
|
||||
public static final int TYPE_SINGLE_CHOICE = 2;
|
||||
public static final int TYPE_SLIDER = 3;
|
||||
public static final int TYPE_SUBMENU = 4;
|
||||
public static final int TYPE_INPUT_BINDING = 5;
|
||||
public static final int TYPE_DATETIME_SETTING = 6;
|
||||
public abstract class SettingsItem {
|
||||
public static final int TYPE_HEADER = 0;
|
||||
public static final int TYPE_CHECKBOX = 1;
|
||||
public static final int TYPE_SINGLE_CHOICE = 2;
|
||||
public static final int TYPE_SLIDER = 3;
|
||||
public static final int TYPE_SUBMENU = 4;
|
||||
public static final int TYPE_INPUT_BINDING = 5;
|
||||
public static final int TYPE_DATETIME_SETTING = 6;
|
||||
|
||||
private String mKey;
|
||||
private String mSection;
|
||||
private int mFile;
|
||||
private String mKey;
|
||||
private String mSection;
|
||||
private int mFile;
|
||||
|
||||
private Setting mSetting;
|
||||
private Setting mSetting;
|
||||
|
||||
private int mNameId;
|
||||
private int mDescriptionId;
|
||||
private int mNameId;
|
||||
private int mDescriptionId;
|
||||
|
||||
/**
|
||||
* Base constructor. Takes a key / section name in case the third parameter, the Setting,
|
||||
* is null; in which case, one can be constructed and saved using the key / section.
|
||||
*
|
||||
* @param key Identifier for the Setting represented by this Item.
|
||||
* @param section Section to which the Setting belongs.
|
||||
* @param setting A possibly-null backing Setting, to be modified on UI events.
|
||||
* @param nameId Resource ID for a text string to be displayed as this setting's name.
|
||||
* @param descriptionId Resource ID for a text string to be displayed as this setting's description.
|
||||
*/
|
||||
public SettingsItem(String key, String section, int file, Setting setting, int nameId,
|
||||
int descriptionId)
|
||||
{
|
||||
mKey = key;
|
||||
mSection = section;
|
||||
mFile = file;
|
||||
mSetting = setting;
|
||||
mNameId = nameId;
|
||||
mDescriptionId = descriptionId;
|
||||
}
|
||||
/**
|
||||
* Base constructor. Takes a key / section name in case the third parameter, the Setting,
|
||||
* is null; in which case, one can be constructed and saved using the key / section.
|
||||
*
|
||||
* @param key Identifier for the Setting represented by this Item.
|
||||
* @param section Section to which the Setting belongs.
|
||||
* @param setting A possibly-null backing Setting, to be modified on UI events.
|
||||
* @param nameId Resource ID for a text string to be displayed as this setting's name.
|
||||
* @param descriptionId Resource ID for a text string to be displayed as this setting's description.
|
||||
*/
|
||||
public SettingsItem(String key, String section, int file, Setting setting, int nameId,
|
||||
int descriptionId) {
|
||||
mKey = key;
|
||||
mSection = section;
|
||||
mFile = file;
|
||||
mSetting = setting;
|
||||
mNameId = nameId;
|
||||
mDescriptionId = descriptionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The identifier for the backing Setting.
|
||||
*/
|
||||
public String getKey()
|
||||
{
|
||||
return mKey;
|
||||
}
|
||||
/**
|
||||
* @return The identifier for the backing Setting.
|
||||
*/
|
||||
public String getKey() {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The header under which the backing Setting belongs.
|
||||
*/
|
||||
public String getSection()
|
||||
{
|
||||
return mSection;
|
||||
}
|
||||
/**
|
||||
* @return The header under which the backing Setting belongs.
|
||||
*/
|
||||
public String getSection() {
|
||||
return mSection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The file the backing Setting is saved to.
|
||||
*/
|
||||
public int getFile()
|
||||
{
|
||||
return mFile;
|
||||
}
|
||||
/**
|
||||
* @return The file the backing Setting is saved to.
|
||||
*/
|
||||
public int getFile() {
|
||||
return mFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The backing Setting, possibly null.
|
||||
*/
|
||||
public Setting getSetting()
|
||||
{
|
||||
return mSetting;
|
||||
}
|
||||
/**
|
||||
* @return The backing Setting, possibly null.
|
||||
*/
|
||||
public Setting getSetting() {
|
||||
return mSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the backing setting with a new one. Generally used in cases where
|
||||
* the backing setting is null.
|
||||
*
|
||||
* @param setting A non-null Setting.
|
||||
*/
|
||||
public void setSetting(Setting setting)
|
||||
{
|
||||
mSetting = setting;
|
||||
}
|
||||
/**
|
||||
* Replace the backing setting with a new one. Generally used in cases where
|
||||
* the backing setting is null.
|
||||
*
|
||||
* @param setting A non-null Setting.
|
||||
*/
|
||||
public void setSetting(Setting setting) {
|
||||
mSetting = setting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A resource ID for a text string representing this Setting's name.
|
||||
*/
|
||||
public int getNameId()
|
||||
{
|
||||
return mNameId;
|
||||
}
|
||||
/**
|
||||
* @return A resource ID for a text string representing this Setting's name.
|
||||
*/
|
||||
public int getNameId() {
|
||||
return mNameId;
|
||||
}
|
||||
|
||||
public int getDescriptionId()
|
||||
{
|
||||
return mDescriptionId;
|
||||
}
|
||||
public int getDescriptionId() {
|
||||
return mDescriptionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by {@link org.citra.citra_android.ui.settings.SettingsAdapter}'s onCreateViewHolder()
|
||||
* method to determine which type of ViewHolder should be created.
|
||||
*
|
||||
* @return An integer (ideally, one of the constants defined in this file)
|
||||
*/
|
||||
public abstract int getType();
|
||||
/**
|
||||
* Used by {@link org.citra.citra_android.ui.settings.SettingsAdapter}'s onCreateViewHolder()
|
||||
* method to determine which type of ViewHolder should be created.
|
||||
*
|
||||
* @return An integer (ideally, one of the constants defined in this file)
|
||||
*/
|
||||
public abstract int getType();
|
||||
}
|
||||
|
@ -3,71 +3,58 @@ package org.citra.citra_android.model.settings.view;
|
||||
import org.citra.citra_android.model.settings.IntSetting;
|
||||
import org.citra.citra_android.model.settings.Setting;
|
||||
|
||||
public final class SingleChoiceSetting extends SettingsItem
|
||||
{
|
||||
private int mDefaultValue;
|
||||
public final class SingleChoiceSetting extends SettingsItem {
|
||||
private int mDefaultValue;
|
||||
|
||||
private int mChoicesId;
|
||||
private int mValuesId;
|
||||
private int mChoicesId;
|
||||
private int mValuesId;
|
||||
|
||||
public SingleChoiceSetting(String key, String section, int file, int titleId, int descriptionId,
|
||||
int choicesId, int valuesId, int defaultValue, Setting setting)
|
||||
{
|
||||
super(key, section, file, setting, titleId, descriptionId);
|
||||
mValuesId = valuesId;
|
||||
mChoicesId = choicesId;
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public int getChoicesId()
|
||||
{
|
||||
return mChoicesId;
|
||||
}
|
||||
|
||||
public int getValuesId()
|
||||
{
|
||||
return mValuesId;
|
||||
}
|
||||
|
||||
public int getSelectedValue()
|
||||
{
|
||||
if (getSetting() != null)
|
||||
{
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
return setting.getValue();
|
||||
public SingleChoiceSetting(String key, String section, int file, int titleId, int descriptionId,
|
||||
int choicesId, int valuesId, int defaultValue, Setting setting) {
|
||||
super(key, section, file, setting, titleId, descriptionId);
|
||||
mValuesId = valuesId;
|
||||
mChoicesId = choicesId;
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mDefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the backing int. If that int was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param selection New value of the int.
|
||||
* @return null if overwritten successfully otherwise; a newly created IntSetting.
|
||||
*/
|
||||
public IntSetting setSelectedValue(int selection)
|
||||
{
|
||||
if (getSetting() == null)
|
||||
{
|
||||
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), selection);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
public int getChoicesId() {
|
||||
return mChoicesId;
|
||||
}
|
||||
else
|
||||
{
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
setting.setValue(selection);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType()
|
||||
{
|
||||
return TYPE_SINGLE_CHOICE;
|
||||
}
|
||||
public int getValuesId() {
|
||||
return mValuesId;
|
||||
}
|
||||
|
||||
public int getSelectedValue() {
|
||||
if (getSetting() != null) {
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
return setting.getValue();
|
||||
} else {
|
||||
return mDefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the backing int. If that int was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param selection New value of the int.
|
||||
* @return null if overwritten successfully otherwise; a newly created IntSetting.
|
||||
*/
|
||||
public IntSetting setSelectedValue(int selection) {
|
||||
if (getSetting() == null) {
|
||||
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), selection);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
} else {
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
setting.setValue(selection);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return TYPE_SINGLE_CHOICE;
|
||||
}
|
||||
}
|
||||
|
@ -6,114 +6,91 @@ import org.citra.citra_android.model.settings.Setting;
|
||||
import org.citra.citra_android.utils.Log;
|
||||
import org.citra.citra_android.utils.SettingsFile;
|
||||
|
||||
public final class SliderSetting extends SettingsItem
|
||||
{
|
||||
private int mMax;
|
||||
private int mDefaultValue;
|
||||
public final class SliderSetting extends SettingsItem {
|
||||
private int mMax;
|
||||
private int mDefaultValue;
|
||||
|
||||
private String mUnits;
|
||||
private String mUnits;
|
||||
|
||||
public SliderSetting(String key, String section, int file, int titleId, int descriptionId,
|
||||
int max, String units, int defaultValue, Setting setting)
|
||||
{
|
||||
super(key, section, file, setting, titleId, descriptionId);
|
||||
mMax = max;
|
||||
mUnits = units;
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public int getMax()
|
||||
{
|
||||
return mMax;
|
||||
}
|
||||
|
||||
public int getSelectedValue()
|
||||
{
|
||||
Setting setting = getSetting();
|
||||
|
||||
if (setting == null)
|
||||
{
|
||||
return mDefaultValue;
|
||||
public SliderSetting(String key, String section, int file, int titleId, int descriptionId,
|
||||
int max, String units, int defaultValue, Setting setting) {
|
||||
super(key, section, file, setting, titleId, descriptionId);
|
||||
mMax = max;
|
||||
mUnits = units;
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
if (setting instanceof IntSetting)
|
||||
{
|
||||
IntSetting intSetting = (IntSetting) setting;
|
||||
return intSetting.getValue();
|
||||
public int getMax() {
|
||||
return mMax;
|
||||
}
|
||||
else if (setting instanceof FloatSetting)
|
||||
{
|
||||
FloatSetting floatSetting = (FloatSetting) setting;
|
||||
if (floatSetting.getKey().equals(SettingsFile.KEY_FRAME_LIMIT))
|
||||
{
|
||||
return Math.round(floatSetting.getValue() * 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Math.round(floatSetting.getValue());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error("[SliderSetting] Error casting setting type.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the backing int. If that int was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param selection New value of the int.
|
||||
* @return null if overwritten successfully otherwise; a newly created IntSetting.
|
||||
*/
|
||||
public IntSetting setSelectedValue(int selection)
|
||||
{
|
||||
if (getSetting() == null)
|
||||
{
|
||||
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), selection);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
}
|
||||
else
|
||||
{
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
setting.setValue(selection);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public int getSelectedValue() {
|
||||
Setting setting = getSetting();
|
||||
|
||||
/**
|
||||
* Write a value to the backing float. If that float was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param selection New value of the float.
|
||||
* @return null if overwritten successfully otherwise; a newly created FloatSetting.
|
||||
*/
|
||||
public FloatSetting setSelectedValue(float selection)
|
||||
{
|
||||
if (getSetting() == null)
|
||||
{
|
||||
FloatSetting setting = new FloatSetting(getKey(), getSection(), getFile(), selection);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatSetting setting = (FloatSetting) getSetting();
|
||||
setting.setValue(selection);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (setting == null) {
|
||||
return mDefaultValue;
|
||||
}
|
||||
|
||||
public String getUnits()
|
||||
{
|
||||
return mUnits;
|
||||
}
|
||||
if (setting instanceof IntSetting) {
|
||||
IntSetting intSetting = (IntSetting) setting;
|
||||
return intSetting.getValue();
|
||||
} else if (setting instanceof FloatSetting) {
|
||||
FloatSetting floatSetting = (FloatSetting) setting;
|
||||
if (floatSetting.getKey().equals(SettingsFile.KEY_FRAME_LIMIT)) {
|
||||
return Math.round(floatSetting.getValue() * 100);
|
||||
} else {
|
||||
return Math.round(floatSetting.getValue());
|
||||
}
|
||||
} else {
|
||||
Log.error("[SliderSetting] Error casting setting type.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType()
|
||||
{
|
||||
return TYPE_SLIDER;
|
||||
}
|
||||
/**
|
||||
* Write a value to the backing int. If that int was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param selection New value of the int.
|
||||
* @return null if overwritten successfully otherwise; a newly created IntSetting.
|
||||
*/
|
||||
public IntSetting setSelectedValue(int selection) {
|
||||
if (getSetting() == null) {
|
||||
IntSetting setting = new IntSetting(getKey(), getSection(), getFile(), selection);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
} else {
|
||||
IntSetting setting = (IntSetting) getSetting();
|
||||
setting.setValue(selection);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a value to the backing float. If that float was previously null,
|
||||
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||
*
|
||||
* @param selection New value of the float.
|
||||
* @return null if overwritten successfully otherwise; a newly created FloatSetting.
|
||||
*/
|
||||
public FloatSetting setSelectedValue(float selection) {
|
||||
if (getSetting() == null) {
|
||||
FloatSetting setting = new FloatSetting(getKey(), getSection(), getFile(), selection);
|
||||
setSetting(setting);
|
||||
return setting;
|
||||
} else {
|
||||
FloatSetting setting = (FloatSetting) getSetting();
|
||||
setting.setValue(selection);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String getUnits() {
|
||||
return mUnits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return TYPE_SLIDER;
|
||||
}
|
||||
}
|
||||
|
@ -2,24 +2,20 @@ package org.citra.citra_android.model.settings.view;
|
||||
|
||||
import org.citra.citra_android.model.settings.Setting;
|
||||
|
||||
public final class SubmenuSetting extends SettingsItem
|
||||
{
|
||||
private String mMenuKey;
|
||||
public final class SubmenuSetting extends SettingsItem {
|
||||
private String mMenuKey;
|
||||
|
||||
public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, String menuKey)
|
||||
{
|
||||
super(key, null, 0, setting, titleId, descriptionId);
|
||||
mMenuKey = menuKey;
|
||||
}
|
||||
public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, String menuKey) {
|
||||
super(key, null, 0, setting, titleId, descriptionId);
|
||||
mMenuKey = menuKey;
|
||||
}
|
||||
|
||||
public String getMenuKey()
|
||||
{
|
||||
return mMenuKey;
|
||||
}
|
||||
public String getMenuKey() {
|
||||
return mMenuKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType()
|
||||
{
|
||||
return TYPE_SUBMENU;
|
||||
}
|
||||
@Override
|
||||
public int getType() {
|
||||
return TYPE_SUBMENU;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,121 +17,106 @@ import android.view.MotionEvent;
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
* of storing it's own ID.
|
||||
*/
|
||||
public final class InputOverlayDrawableButton
|
||||
{
|
||||
// The ID identifying what type of button this Drawable represents.
|
||||
private int mButtonType;
|
||||
private int mTrackId;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private BitmapDrawable mDefaultStateBitmap;
|
||||
private BitmapDrawable mPressedStateBitmap;
|
||||
private boolean mPressedState = false;
|
||||
public final class InputOverlayDrawableButton {
|
||||
// The ID identifying what type of button this Drawable represents.
|
||||
private int mButtonType;
|
||||
private int mTrackId;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private BitmapDrawable mDefaultStateBitmap;
|
||||
private BitmapDrawable mPressedStateBitmap;
|
||||
private boolean mPressedState = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param defaultStateBitmap {@link Bitmap} to use with the default state Drawable.
|
||||
* @param pressedStateBitmap {@link Bitmap} to use with the pressed state Drawable.
|
||||
* @param buttonType Identifier for this type of button.
|
||||
*/
|
||||
public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap,
|
||||
Bitmap pressedStateBitmap, int buttonType)
|
||||
{
|
||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||
mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap);
|
||||
mButtonType = buttonType;
|
||||
|
||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this InputOverlayDrawableButton's button ID.
|
||||
*
|
||||
* @return this InputOverlayDrawableButton's button ID.
|
||||
*/
|
||||
public int getId()
|
||||
{
|
||||
return mButtonType;
|
||||
}
|
||||
|
||||
public void setTrackId(int trackId)
|
||||
{
|
||||
mTrackId = trackId;
|
||||
}
|
||||
|
||||
public int getTrackId()
|
||||
{
|
||||
return mTrackId;
|
||||
}
|
||||
|
||||
public boolean onConfigureTouch(MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
||||
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
||||
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX,
|
||||
getHeight() + mControlPositionY);
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param defaultStateBitmap {@link Bitmap} to use with the default state Drawable.
|
||||
* @param pressedStateBitmap {@link Bitmap} to use with the pressed state Drawable.
|
||||
* @param buttonType Identifier for this type of button.
|
||||
*/
|
||||
public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap,
|
||||
Bitmap pressedStateBitmap, int buttonType) {
|
||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||
mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap);
|
||||
mButtonType = buttonType;
|
||||
|
||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y)
|
||||
{
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
/**
|
||||
* Gets this InputOverlayDrawableButton's button ID.
|
||||
*
|
||||
* @return this InputOverlayDrawableButton's button ID.
|
||||
*/
|
||||
public int getId() {
|
||||
return mButtonType;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
getCurrentStateBitmapDrawable().draw(canvas);
|
||||
}
|
||||
public int getTrackId() {
|
||||
return mTrackId;
|
||||
}
|
||||
|
||||
private BitmapDrawable getCurrentStateBitmapDrawable()
|
||||
{
|
||||
return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap;
|
||||
}
|
||||
public void setTrackId(int trackId) {
|
||||
mTrackId = trackId;
|
||||
}
|
||||
|
||||
public void setBounds(int left, int top, int right, int bottom)
|
||||
{
|
||||
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedStateBitmap.setBounds(left, top, right, bottom);
|
||||
}
|
||||
public boolean onConfigureTouch(MotionEvent event) {
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
||||
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
||||
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX,
|
||||
getHeight() + mControlPositionY);
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
|
||||
public Rect getBounds()
|
||||
{
|
||||
return mDefaultStateBitmap.getBounds();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
public void setPosition(int x, int y) {
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
public void draw(Canvas canvas) {
|
||||
getCurrentStateBitmapDrawable().draw(canvas);
|
||||
}
|
||||
|
||||
public void setPressedState(boolean isPressed)
|
||||
{
|
||||
mPressedState = isPressed;
|
||||
}
|
||||
private BitmapDrawable getCurrentStateBitmapDrawable() {
|
||||
return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap;
|
||||
}
|
||||
|
||||
public void setBounds(int left, int top, int right, int bottom) {
|
||||
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedStateBitmap.setBounds(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public Rect getBounds() {
|
||||
return mDefaultStateBitmap.getBounds();
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public void setPressedState(boolean isPressed) {
|
||||
mPressedState = isPressed;
|
||||
}
|
||||
}
|
||||
|
@ -17,190 +17,174 @@ import android.view.MotionEvent;
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
* of storing it's own ID.
|
||||
*/
|
||||
public final class InputOverlayDrawableDpad
|
||||
{
|
||||
// The ID identifying what type of button this Drawable represents.
|
||||
private int[] mButtonType = new int[4];
|
||||
private int mTrackId;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private BitmapDrawable mDefaultStateBitmap;
|
||||
private BitmapDrawable mPressedOneDirectionStateBitmap;
|
||||
private BitmapDrawable mPressedTwoDirectionsStateBitmap;
|
||||
private int mPressState = STATE_DEFAULT;
|
||||
public final class InputOverlayDrawableDpad {
|
||||
public static final int STATE_DEFAULT = 0;
|
||||
public static final int STATE_PRESSED_UP = 1;
|
||||
public static final int STATE_PRESSED_DOWN = 2;
|
||||
public static final int STATE_PRESSED_LEFT = 3;
|
||||
public static final int STATE_PRESSED_RIGHT = 4;
|
||||
public static final int STATE_PRESSED_UP_LEFT = 5;
|
||||
public static final int STATE_PRESSED_UP_RIGHT = 6;
|
||||
public static final int STATE_PRESSED_DOWN_LEFT = 7;
|
||||
public static final int STATE_PRESSED_DOWN_RIGHT = 8;
|
||||
// The ID identifying what type of button this Drawable represents.
|
||||
private int[] mButtonType = new int[4];
|
||||
private int mTrackId;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private BitmapDrawable mDefaultStateBitmap;
|
||||
private BitmapDrawable mPressedOneDirectionStateBitmap;
|
||||
private BitmapDrawable mPressedTwoDirectionsStateBitmap;
|
||||
private int mPressState = STATE_DEFAULT;
|
||||
|
||||
public static final int STATE_DEFAULT = 0;
|
||||
public static final int STATE_PRESSED_UP = 1;
|
||||
public static final int STATE_PRESSED_DOWN = 2;
|
||||
public static final int STATE_PRESSED_LEFT = 3;
|
||||
public static final int STATE_PRESSED_RIGHT = 4;
|
||||
public static final int STATE_PRESSED_UP_LEFT = 5;
|
||||
public static final int STATE_PRESSED_UP_RIGHT = 6;
|
||||
public static final int STATE_PRESSED_DOWN_LEFT = 7;
|
||||
public static final int STATE_PRESSED_DOWN_RIGHT = 8;
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param defaultStateBitmap {@link Bitmap} of the default state.
|
||||
* @param pressedOneDirectionStateBitmap {@link Bitmap} of the pressed state in one direction.
|
||||
* @param pressedTwoDirectionsStateBitmap {@link Bitmap} of the pressed state in two direction.
|
||||
* @param buttonUp Identifier for the up button.
|
||||
* @param buttonDown Identifier for the down button.
|
||||
* @param buttonLeft Identifier for the left button.
|
||||
* @param buttonRight Identifier for the right button.
|
||||
*/
|
||||
public InputOverlayDrawableDpad(Resources res,
|
||||
Bitmap defaultStateBitmap,
|
||||
Bitmap pressedOneDirectionStateBitmap,
|
||||
Bitmap pressedTwoDirectionsStateBitmap,
|
||||
int buttonUp, int buttonDown,
|
||||
int buttonLeft, int buttonRight) {
|
||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||
mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap);
|
||||
mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param defaultStateBitmap {@link Bitmap} of the default state.
|
||||
* @param pressedOneDirectionStateBitmap {@link Bitmap} of the pressed state in one direction.
|
||||
* @param pressedTwoDirectionsStateBitmap {@link Bitmap} of the pressed state in two direction.
|
||||
* @param buttonUp Identifier for the up button.
|
||||
* @param buttonDown Identifier for the down button.
|
||||
* @param buttonLeft Identifier for the left button.
|
||||
* @param buttonRight Identifier for the right button.
|
||||
*/
|
||||
public InputOverlayDrawableDpad(Resources res,
|
||||
Bitmap defaultStateBitmap,
|
||||
Bitmap pressedOneDirectionStateBitmap,
|
||||
Bitmap pressedTwoDirectionsStateBitmap,
|
||||
int buttonUp, int buttonDown,
|
||||
int buttonLeft, int buttonRight)
|
||||
{
|
||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||
mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap);
|
||||
mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap);
|
||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||
|
||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||
|
||||
mButtonType[0] = buttonUp;
|
||||
mButtonType[1] = buttonDown;
|
||||
mButtonType[2] = buttonLeft;
|
||||
mButtonType[3] = buttonRight;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
int px = mControlPositionX + (getWidth() / 2);
|
||||
int py = mControlPositionY + (getHeight() / 2);
|
||||
switch (mPressState)
|
||||
{
|
||||
case STATE_DEFAULT:
|
||||
mDefaultStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_UP:
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(90, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN:
|
||||
canvas.save();
|
||||
canvas.rotate(180, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_LEFT:
|
||||
canvas.save();
|
||||
canvas.rotate(270, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_UP_LEFT:
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_UP_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(90, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(180, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN_LEFT:
|
||||
canvas.save();
|
||||
canvas.rotate(270, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
mButtonType[0] = buttonUp;
|
||||
mButtonType[1] = buttonDown;
|
||||
mButtonType[2] = buttonLeft;
|
||||
mButtonType[3] = buttonRight;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one of the InputOverlayDrawableDpad's button IDs.
|
||||
*
|
||||
* @return the requested InputOverlayDrawableDpad's button ID.
|
||||
*/
|
||||
public int getId(int direction)
|
||||
{
|
||||
return mButtonType[direction];
|
||||
}
|
||||
|
||||
public void setTrackId(int trackId)
|
||||
{
|
||||
mTrackId = trackId;
|
||||
}
|
||||
|
||||
public int getTrackId()
|
||||
{
|
||||
return mTrackId;
|
||||
}
|
||||
|
||||
public boolean onConfigureTouch(MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
||||
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
||||
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX,
|
||||
getHeight() + mControlPositionY);
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
int px = mControlPositionX + (getWidth() / 2);
|
||||
int py = mControlPositionY + (getHeight() / 2);
|
||||
switch (mPressState) {
|
||||
case STATE_DEFAULT:
|
||||
mDefaultStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_UP:
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(90, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN:
|
||||
canvas.save();
|
||||
canvas.rotate(180, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_LEFT:
|
||||
canvas.save();
|
||||
canvas.rotate(270, px, py);
|
||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_UP_LEFT:
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
break;
|
||||
case STATE_PRESSED_UP_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(90, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN_RIGHT:
|
||||
canvas.save();
|
||||
canvas.rotate(180, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
case STATE_PRESSED_DOWN_LEFT:
|
||||
canvas.save();
|
||||
canvas.rotate(270, px, py);
|
||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y)
|
||||
{
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
/**
|
||||
* Gets one of the InputOverlayDrawableDpad's button IDs.
|
||||
*
|
||||
* @return the requested InputOverlayDrawableDpad's button ID.
|
||||
*/
|
||||
public int getId(int direction) {
|
||||
return mButtonType[direction];
|
||||
}
|
||||
|
||||
public void setBounds(int left, int top, int right, int bottom)
|
||||
{
|
||||
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedOneDirectionStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom);
|
||||
}
|
||||
public int getTrackId() {
|
||||
return mTrackId;
|
||||
}
|
||||
|
||||
public Rect getBounds()
|
||||
{
|
||||
return mDefaultStateBitmap.getBounds();
|
||||
}
|
||||
public void setTrackId(int trackId) {
|
||||
mTrackId = trackId;
|
||||
}
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
public boolean onConfigureTouch(MotionEvent event) {
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
||||
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
||||
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX,
|
||||
getHeight() + mControlPositionY);
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setState(int pressState)
|
||||
{
|
||||
mPressState = pressState;
|
||||
}
|
||||
public void setPosition(int x, int y) {
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
|
||||
public void setBounds(int left, int top, int right, int bottom) {
|
||||
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedOneDirectionStateBitmap.setBounds(left, top, right, bottom);
|
||||
mPressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom);
|
||||
}
|
||||
|
||||
public Rect getBounds() {
|
||||
return mDefaultStateBitmap.getBounds();
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public void setState(int pressState) {
|
||||
mPressState = pressState;
|
||||
}
|
||||
}
|
||||
|
@ -17,248 +17,224 @@ import android.view.MotionEvent;
|
||||
* Custom {@link BitmapDrawable} that is capable
|
||||
* of storing it's own ID.
|
||||
*/
|
||||
public final class InputOverlayDrawableJoystick
|
||||
{
|
||||
private final int[] axisIDs = {0, 0, 0, 0};
|
||||
private final float[] axises = {0f, 0f};
|
||||
private int trackId = -1;
|
||||
private int mJoystickType;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private Rect mVirtBounds;
|
||||
private Rect mOrigBounds;
|
||||
private BitmapDrawable mOuterBitmap;
|
||||
private BitmapDrawable mDefaultStateInnerBitmap;
|
||||
private BitmapDrawable mPressedStateInnerBitmap;
|
||||
private BitmapDrawable mBoundsBoxBitmap;
|
||||
private boolean mPressedState = false;
|
||||
public final class InputOverlayDrawableJoystick {
|
||||
private final int[] axisIDs = {0, 0, 0, 0};
|
||||
private final float[] axises = {0f, 0f};
|
||||
private int trackId = -1;
|
||||
private int mJoystickType;
|
||||
private int mControlPositionX, mControlPositionY;
|
||||
private int mPreviousTouchX, mPreviousTouchY;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private Rect mVirtBounds;
|
||||
private Rect mOrigBounds;
|
||||
private BitmapDrawable mOuterBitmap;
|
||||
private BitmapDrawable mDefaultStateInnerBitmap;
|
||||
private BitmapDrawable mPressedStateInnerBitmap;
|
||||
private BitmapDrawable mBoundsBoxBitmap;
|
||||
private boolean mPressedState = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param bitmapOuter {@link Bitmap} which represents the outer non-movable part of the joystick.
|
||||
* @param bitmapInnerDefault {@link Bitmap} which represents the default inner movable part of the joystick.
|
||||
* @param bitmapInnerPressed {@link Bitmap} which represents the pressed inner movable part of the joystick.
|
||||
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
||||
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
||||
* @param joystick Identifier for which joystick this is.
|
||||
*/
|
||||
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter,
|
||||
Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed,
|
||||
Rect rectOuter, Rect rectInner, int joystick)
|
||||
{
|
||||
axisIDs[0] = joystick + 1; // Up
|
||||
axisIDs[1] = joystick + 2; // Down
|
||||
axisIDs[2] = joystick + 3; // Left
|
||||
axisIDs[3] = joystick + 4; // Right
|
||||
mJoystickType = joystick;
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param res {@link Resources} instance.
|
||||
* @param bitmapOuter {@link Bitmap} which represents the outer non-movable part of the joystick.
|
||||
* @param bitmapInnerDefault {@link Bitmap} which represents the default inner movable part of the joystick.
|
||||
* @param bitmapInnerPressed {@link Bitmap} which represents the pressed inner movable part of the joystick.
|
||||
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
||||
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
||||
* @param joystick Identifier for which joystick this is.
|
||||
*/
|
||||
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter,
|
||||
Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed,
|
||||
Rect rectOuter, Rect rectInner, int joystick) {
|
||||
axisIDs[0] = joystick + 1; // Up
|
||||
axisIDs[1] = joystick + 2; // Down
|
||||
axisIDs[2] = joystick + 3; // Left
|
||||
axisIDs[3] = joystick + 4; // Right
|
||||
mJoystickType = joystick;
|
||||
|
||||
mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||
mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
|
||||
mPressedStateInnerBitmap = new BitmapDrawable(res, bitmapInnerPressed);
|
||||
mBoundsBoxBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||
mWidth = bitmapOuter.getWidth();
|
||||
mHeight = bitmapOuter.getHeight();
|
||||
|
||||
setBounds(rectOuter);
|
||||
mDefaultStateInnerBitmap.setBounds(rectInner);
|
||||
mPressedStateInnerBitmap.setBounds(rectInner);
|
||||
mVirtBounds = getBounds();
|
||||
mOrigBounds = mOuterBitmap.copyBounds();
|
||||
mBoundsBoxBitmap.setAlpha(0);
|
||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
||||
SetInnerBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this InputOverlayDrawableJoystick's button ID.
|
||||
*
|
||||
* @return this InputOverlayDrawableJoystick's button ID.
|
||||
*/
|
||||
public int getId()
|
||||
{
|
||||
return mJoystickType;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas)
|
||||
{
|
||||
mOuterBitmap.draw(canvas);
|
||||
getCurrentStateBitmapDrawable().draw(canvas);
|
||||
mBoundsBoxBitmap.draw(canvas);
|
||||
}
|
||||
|
||||
public void TrackEvent(MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
|
||||
switch (event.getAction() & MotionEvent.ACTION_MASK)
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex)))
|
||||
{
|
||||
mPressedState = true;
|
||||
mOuterBitmap.setAlpha(0);
|
||||
mBoundsBoxBitmap.setAlpha(255);
|
||||
getVirtBounds().offset((int) event.getX(pointerIndex) - getVirtBounds().centerX(),
|
||||
(int) event.getY(pointerIndex) - getVirtBounds().centerY());
|
||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
||||
trackId = event.getPointerId(pointerIndex);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (trackId == event.getPointerId(pointerIndex))
|
||||
{
|
||||
mPressedState = false;
|
||||
axises[0] = axises[1] = 0.0f;
|
||||
mOuterBitmap.setAlpha(255);
|
||||
mBoundsBoxBitmap.setAlpha(0);
|
||||
setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||
mOrigBounds.bottom));
|
||||
setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||
mOrigBounds.bottom));
|
||||
SetInnerBounds();
|
||||
trackId = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (trackId == -1)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < event.getPointerCount(); i++)
|
||||
{
|
||||
if (trackId == event.getPointerId(i))
|
||||
{
|
||||
float touchX = event.getX(i);
|
||||
float touchY = event.getY(i);
|
||||
float maxY = getVirtBounds().bottom;
|
||||
float maxX = getVirtBounds().right;
|
||||
touchX -= getVirtBounds().centerX();
|
||||
maxX -= getVirtBounds().centerX();
|
||||
touchY -= getVirtBounds().centerY();
|
||||
maxY -= getVirtBounds().centerY();
|
||||
final float AxisX = touchX / maxX;
|
||||
final float AxisY = touchY / maxY;
|
||||
axises[0] = AxisX;
|
||||
axises[1] = AxisY;
|
||||
mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||
mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
|
||||
mPressedStateInnerBitmap = new BitmapDrawable(res, bitmapInnerPressed);
|
||||
mBoundsBoxBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||
mWidth = bitmapOuter.getWidth();
|
||||
mHeight = bitmapOuter.getHeight();
|
||||
|
||||
setBounds(rectOuter);
|
||||
mDefaultStateInnerBitmap.setBounds(rectInner);
|
||||
mPressedStateInnerBitmap.setBounds(rectInner);
|
||||
mVirtBounds = getBounds();
|
||||
mOrigBounds = mOuterBitmap.copyBounds();
|
||||
mBoundsBoxBitmap.setAlpha(0);
|
||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
||||
SetInnerBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onConfigureTouch(MotionEvent event)
|
||||
{
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||
switch (event.getAction())
|
||||
{
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int deltaX = fingerPositionX - mPreviousTouchX;
|
||||
int deltaY = fingerPositionY - mPreviousTouchY;
|
||||
mControlPositionX += deltaX;
|
||||
mControlPositionY += deltaY;
|
||||
setBounds(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
||||
setVirtBounds(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
||||
SetInnerBounds();
|
||||
setOrigBounds(new Rect(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY)));
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
/**
|
||||
* Gets this InputOverlayDrawableJoystick's button ID.
|
||||
*
|
||||
* @return this InputOverlayDrawableJoystick's button ID.
|
||||
*/
|
||||
public int getId() {
|
||||
return mJoystickType;
|
||||
}
|
||||
|
||||
public void draw(Canvas canvas) {
|
||||
mOuterBitmap.draw(canvas);
|
||||
getCurrentStateBitmapDrawable().draw(canvas);
|
||||
mBoundsBoxBitmap.draw(canvas);
|
||||
}
|
||||
|
||||
public void TrackEvent(MotionEvent event) {
|
||||
int pointerIndex = event.getActionIndex();
|
||||
|
||||
switch (event.getAction() & MotionEvent.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex))) {
|
||||
mPressedState = true;
|
||||
mOuterBitmap.setAlpha(0);
|
||||
mBoundsBoxBitmap.setAlpha(255);
|
||||
getVirtBounds().offset((int) event.getX(pointerIndex) - getVirtBounds().centerX(),
|
||||
(int) event.getY(pointerIndex) - getVirtBounds().centerY());
|
||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
||||
trackId = event.getPointerId(pointerIndex);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (trackId == event.getPointerId(pointerIndex)) {
|
||||
mPressedState = false;
|
||||
axises[0] = axises[1] = 0.0f;
|
||||
mOuterBitmap.setAlpha(255);
|
||||
mBoundsBoxBitmap.setAlpha(0);
|
||||
setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||
mOrigBounds.bottom));
|
||||
setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||
mOrigBounds.bottom));
|
||||
SetInnerBounds();
|
||||
trackId = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (trackId == -1)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < event.getPointerCount(); i++) {
|
||||
if (trackId == event.getPointerId(i)) {
|
||||
float touchX = event.getX(i);
|
||||
float touchY = event.getY(i);
|
||||
float maxY = getVirtBounds().bottom;
|
||||
float maxX = getVirtBounds().right;
|
||||
touchX -= getVirtBounds().centerX();
|
||||
maxX -= getVirtBounds().centerX();
|
||||
touchY -= getVirtBounds().centerY();
|
||||
maxY -= getVirtBounds().centerY();
|
||||
final float AxisX = touchX / maxX;
|
||||
final float AxisY = touchY / maxY;
|
||||
axises[0] = AxisX;
|
||||
axises[1] = AxisY;
|
||||
|
||||
SetInnerBounds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onConfigureTouch(MotionEvent event) {
|
||||
int pointerIndex = event.getActionIndex();
|
||||
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int deltaX = fingerPositionX - mPreviousTouchX;
|
||||
int deltaY = fingerPositionY - mPreviousTouchY;
|
||||
mControlPositionX += deltaX;
|
||||
mControlPositionY += deltaY;
|
||||
setBounds(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
||||
setVirtBounds(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
||||
SetInnerBounds();
|
||||
setOrigBounds(new Rect(new Rect(mControlPositionX, mControlPositionY,
|
||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY)));
|
||||
mPreviousTouchX = fingerPositionX;
|
||||
mPreviousTouchY = fingerPositionY;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public float[] getAxisValues()
|
||||
{
|
||||
return axises;
|
||||
}
|
||||
public float[] getAxisValues() {
|
||||
return axises;
|
||||
}
|
||||
|
||||
public int[] getAxisIDs()
|
||||
{
|
||||
return axisIDs;
|
||||
}
|
||||
public int[] getAxisIDs() {
|
||||
return axisIDs;
|
||||
}
|
||||
|
||||
private void SetInnerBounds()
|
||||
{
|
||||
int X = getVirtBounds().centerX() + (int) ((axises[0]) * (getVirtBounds().width() / 2));
|
||||
int Y = getVirtBounds().centerY() + (int) ((axises[1]) * (getVirtBounds().height() / 2));
|
||||
private void SetInnerBounds() {
|
||||
int X = getVirtBounds().centerX() + (int) ((axises[0]) * (getVirtBounds().width() / 2));
|
||||
int Y = getVirtBounds().centerY() + (int) ((axises[1]) * (getVirtBounds().height() / 2));
|
||||
|
||||
if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2))
|
||||
X = getVirtBounds().centerX() + (getVirtBounds().width() / 2);
|
||||
if (X < getVirtBounds().centerX() - (getVirtBounds().width() / 2))
|
||||
X = getVirtBounds().centerX() - (getVirtBounds().width() / 2);
|
||||
if (Y > getVirtBounds().centerY() + (getVirtBounds().height() / 2))
|
||||
Y = getVirtBounds().centerY() + (getVirtBounds().height() / 2);
|
||||
if (Y < getVirtBounds().centerY() - (getVirtBounds().height() / 2))
|
||||
Y = getVirtBounds().centerY() - (getVirtBounds().height() / 2);
|
||||
if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2))
|
||||
X = getVirtBounds().centerX() + (getVirtBounds().width() / 2);
|
||||
if (X < getVirtBounds().centerX() - (getVirtBounds().width() / 2))
|
||||
X = getVirtBounds().centerX() - (getVirtBounds().width() / 2);
|
||||
if (Y > getVirtBounds().centerY() + (getVirtBounds().height() / 2))
|
||||
Y = getVirtBounds().centerY() + (getVirtBounds().height() / 2);
|
||||
if (Y < getVirtBounds().centerY() - (getVirtBounds().height() / 2))
|
||||
Y = getVirtBounds().centerY() - (getVirtBounds().height() / 2);
|
||||
|
||||
int width = mPressedStateInnerBitmap.getBounds().width() / 2;
|
||||
int height = mPressedStateInnerBitmap.getBounds().height() / 2;
|
||||
mDefaultStateInnerBitmap.setBounds(X - width, Y - height, X + width, Y + height);
|
||||
mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds());
|
||||
}
|
||||
int width = mPressedStateInnerBitmap.getBounds().width() / 2;
|
||||
int height = mPressedStateInnerBitmap.getBounds().height() / 2;
|
||||
mDefaultStateInnerBitmap.setBounds(X - width, Y - height, X + width, Y + height);
|
||||
mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds());
|
||||
}
|
||||
|
||||
public void setPosition(int x, int y)
|
||||
{
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
public void setPosition(int x, int y) {
|
||||
mControlPositionX = x;
|
||||
mControlPositionY = y;
|
||||
}
|
||||
|
||||
private BitmapDrawable getCurrentStateBitmapDrawable()
|
||||
{
|
||||
return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap;
|
||||
}
|
||||
private BitmapDrawable getCurrentStateBitmapDrawable() {
|
||||
return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap;
|
||||
}
|
||||
|
||||
public void setBounds(Rect bounds)
|
||||
{
|
||||
mOuterBitmap.setBounds(bounds);
|
||||
}
|
||||
public Rect getBounds() {
|
||||
return mOuterBitmap.getBounds();
|
||||
}
|
||||
|
||||
public Rect getBounds()
|
||||
{
|
||||
return mOuterBitmap.getBounds();
|
||||
}
|
||||
public void setBounds(Rect bounds) {
|
||||
mOuterBitmap.setBounds(bounds);
|
||||
}
|
||||
|
||||
private void setVirtBounds(Rect bounds)
|
||||
{
|
||||
mVirtBounds = bounds;
|
||||
}
|
||||
private void setOrigBounds(Rect bounds) {
|
||||
mOrigBounds = bounds;
|
||||
}
|
||||
|
||||
private void setOrigBounds(Rect bounds)
|
||||
{
|
||||
mOrigBounds = bounds;
|
||||
}
|
||||
private Rect getVirtBounds() {
|
||||
return mVirtBounds;
|
||||
}
|
||||
|
||||
private Rect getVirtBounds()
|
||||
{
|
||||
return mVirtBounds;
|
||||
}
|
||||
private void setVirtBounds(Rect bounds) {
|
||||
mVirtBounds = bounds;
|
||||
}
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return mWidth;
|
||||
}
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return mHeight;
|
||||
}
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
}
|
||||
|
@ -30,204 +30,166 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* 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.citra.citra_android.BROADCAST";
|
||||
public final class DirectoryInitializationService extends IntentService {
|
||||
public static final String BROADCAST_ACTION = "org.citra.citra_android.BROADCAST";
|
||||
|
||||
public static final String EXTRA_STATE = "directoryState";
|
||||
private static volatile DirectoryInitializationState directoryState = null;
|
||||
private static String userPath;
|
||||
private static AtomicBoolean isDolphinDirectoryInitializationRunning = new AtomicBoolean(false);
|
||||
public static final String EXTRA_STATE = "directoryState";
|
||||
private static volatile DirectoryInitializationState directoryState = null;
|
||||
private static String userPath;
|
||||
private static AtomicBoolean isDolphinDirectoryInitializationRunning = new AtomicBoolean(false);
|
||||
|
||||
public enum DirectoryInitializationState
|
||||
{
|
||||
DOLPHIN_DIRECTORIES_INITIALIZED,
|
||||
EXTERNAL_STORAGE_PERMISSION_NEEDED,
|
||||
CANT_FIND_EXTERNAL_STORAGE
|
||||
}
|
||||
public DirectoryInitializationService() {
|
||||
// Superclass constructor is called to name the thread on which this service executes.
|
||||
super("DirectoryInitializationService");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static void startService(Context context)
|
||||
{
|
||||
Intent intent = new Intent(context, DirectoryInitializationService.class);
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent)
|
||||
{
|
||||
isDolphinDirectoryInitializationRunning.set(true);
|
||||
|
||||
if (directoryState != DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
||||
{
|
||||
if (PermissionsHandler.hasWriteAccess(this))
|
||||
{
|
||||
if (setDolphinUserDirectory())
|
||||
{
|
||||
initializeInternalStorage();
|
||||
CreateUserDirectories();
|
||||
NativeLibrary.CreateConfigFile();
|
||||
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
|
||||
private static void deleteDirectoryRecursively(File file) {
|
||||
if (file.isDirectory()) {
|
||||
for (File child : file.listFiles())
|
||||
deleteDirectoryRecursively(child);
|
||||
}
|
||||
else
|
||||
{
|
||||
directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE;
|
||||
file.delete();
|
||||
}
|
||||
|
||||
public static boolean areDolphinDirectoriesReady() {
|
||||
return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
|
||||
}
|
||||
|
||||
public static String getUserDirectory() {
|
||||
if (directoryState == null) {
|
||||
throw new IllegalStateException("DirectoryInitializationService has to run at least once!");
|
||||
} else if (isDolphinDirectoryInitializationRunning.get()) {
|
||||
throw new IllegalStateException(
|
||||
"DirectoryInitializationService has to finish running first!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
isDolphinDirectoryInitializationRunning.set(false);
|
||||
sendBroadcastState(directoryState);
|
||||
}
|
||||
|
||||
private boolean setDolphinUserDirectory()
|
||||
{
|
||||
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
|
||||
{
|
||||
File externalPath = Environment.getExternalStorageDirectory();
|
||||
if (externalPath != null)
|
||||
{
|
||||
userPath = externalPath.getAbsolutePath() + "/citra-emu";
|
||||
Log.debug("[DirectoryInitializationService] User Dir: " + userPath);
|
||||
// NativeLibrary.SetUserDirectory(userPath);
|
||||
return true;
|
||||
}
|
||||
return userPath;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private static native void CreateUserDirectories();
|
||||
|
||||
private void initializeInternalStorage()
|
||||
{
|
||||
File sysDirectory = new File(getFilesDir(), "Sys");
|
||||
private static native void SetSysDirectory(String path);
|
||||
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String revision = NativeLibrary.GetGitRevision();
|
||||
if (!preferences.getString("sysDirectoryVersion", "").equals(revision))
|
||||
{
|
||||
// There is no extracted Sys directory, or there is a Sys directory from another
|
||||
// version of Dolphin that might contain outdated files. Let's (re-)extract Sys.
|
||||
deleteDirectoryRecursively(sysDirectory);
|
||||
copyAssetFolder("Sys", sysDirectory, true);
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
isDolphinDirectoryInitializationRunning.set(true);
|
||||
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString("sysDirectoryVersion", revision);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
// Let the native code know where the Sys directory is.
|
||||
SetSysDirectory(sysDirectory.getPath());
|
||||
}
|
||||
|
||||
private static void deleteDirectoryRecursively(File file)
|
||||
{
|
||||
if (file.isDirectory())
|
||||
{
|
||||
for (File child : file.listFiles())
|
||||
deleteDirectoryRecursively(child);
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
|
||||
public static boolean areDolphinDirectoriesReady()
|
||||
{
|
||||
return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
|
||||
}
|
||||
|
||||
public static String getUserDirectory()
|
||||
{
|
||||
if (directoryState == null)
|
||||
{
|
||||
throw new IllegalStateException("DirectoryInitializationService has to run at least once!");
|
||||
}
|
||||
else if (isDolphinDirectoryInitializationRunning.get())
|
||||
{
|
||||
throw new IllegalStateException(
|
||||
"DirectoryInitializationService has to finish running first!");
|
||||
}
|
||||
return userPath;
|
||||
|
||||
}
|
||||
|
||||
private void sendBroadcastState(DirectoryInitializationState state)
|
||||
{
|
||||
Intent localIntent =
|
||||
new Intent(BROADCAST_ACTION)
|
||||
.putExtra(EXTRA_STATE, state);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
|
||||
}
|
||||
|
||||
private void copyAsset(String asset, File output, Boolean overwrite)
|
||||
{
|
||||
Log.verbose("[DirectoryInitializationService] Copying File " + asset + " to " + output);
|
||||
|
||||
try
|
||||
{
|
||||
if (!output.exists() || overwrite)
|
||||
{
|
||||
InputStream in = getAssets().open(asset);
|
||||
OutputStream 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, File outputFolder, Boolean overwrite)
|
||||
{
|
||||
Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " +
|
||||
outputFolder);
|
||||
|
||||
try
|
||||
{
|
||||
boolean createdFolder = false;
|
||||
for (String file : getAssets().list(assetFolder))
|
||||
{
|
||||
if (!createdFolder)
|
||||
{
|
||||
outputFolder.mkdir();
|
||||
createdFolder = true;
|
||||
if (directoryState != DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) {
|
||||
if (PermissionsHandler.hasWriteAccess(this)) {
|
||||
if (setDolphinUserDirectory()) {
|
||||
initializeInternalStorage();
|
||||
CreateUserDirectories();
|
||||
NativeLibrary.CreateConfigFile();
|
||||
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
|
||||
} else {
|
||||
directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE;
|
||||
}
|
||||
} else {
|
||||
directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED;
|
||||
}
|
||||
}
|
||||
copyAssetFolder(assetFolder + File.separator + file, new File(outputFolder, file),
|
||||
overwrite);
|
||||
copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), overwrite);
|
||||
}
|
||||
|
||||
isDolphinDirectoryInitializationRunning.set(false);
|
||||
sendBroadcastState(directoryState);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.error("[DirectoryInitializationService] Failed to copy asset folder: " + assetFolder +
|
||||
e.getMessage());
|
||||
|
||||
private boolean setDolphinUserDirectory() {
|
||||
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
|
||||
File externalPath = Environment.getExternalStorageDirectory();
|
||||
if (externalPath != null) {
|
||||
userPath = externalPath.getAbsolutePath() + "/citra-emu";
|
||||
Log.debug("[DirectoryInitializationService] User Dir: " + userPath);
|
||||
// NativeLibrary.SetUserDirectory(userPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFile(InputStream in, OutputStream out) throws IOException
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
private void initializeInternalStorage() {
|
||||
File sysDirectory = new File(getFilesDir(), "Sys");
|
||||
|
||||
while ((read = in.read(buffer)) != -1)
|
||||
{
|
||||
out.write(buffer, 0, read);
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String revision = NativeLibrary.GetGitRevision();
|
||||
if (!preferences.getString("sysDirectoryVersion", "").equals(revision)) {
|
||||
// There is no extracted Sys directory, or there is a Sys directory from another
|
||||
// version of Dolphin that might contain outdated files. Let's (re-)extract Sys.
|
||||
deleteDirectoryRecursively(sysDirectory);
|
||||
copyAssetFolder("Sys", sysDirectory, true);
|
||||
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString("sysDirectoryVersion", revision);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
// Let the native code know where the Sys directory is.
|
||||
SetSysDirectory(sysDirectory.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private static native void CreateUserDirectories();
|
||||
private void sendBroadcastState(DirectoryInitializationState state) {
|
||||
Intent localIntent =
|
||||
new Intent(BROADCAST_ACTION)
|
||||
.putExtra(EXTRA_STATE, state);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
|
||||
}
|
||||
|
||||
private static native void SetSysDirectory(String path);
|
||||
private void copyAsset(String asset, File output, Boolean overwrite) {
|
||||
Log.verbose("[DirectoryInitializationService] Copying File " + asset + " to " + output);
|
||||
|
||||
try {
|
||||
if (!output.exists() || overwrite) {
|
||||
InputStream in = getAssets().open(asset);
|
||||
OutputStream 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, File outputFolder, Boolean overwrite) {
|
||||
Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " +
|
||||
outputFolder);
|
||||
|
||||
try {
|
||||
boolean createdFolder = false;
|
||||
for (String file : getAssets().list(assetFolder)) {
|
||||
if (!createdFolder) {
|
||||
outputFolder.mkdir();
|
||||
createdFolder = true;
|
||||
}
|
||||
copyAssetFolder(assetFolder + File.separator + file, new File(outputFolder, file),
|
||||
overwrite);
|
||||
copyAsset(assetFolder + File.separator + file, new File(outputFolder, 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);
|
||||
}
|
||||
}
|
||||
|
||||
public enum DirectoryInitializationState {
|
||||
DOLPHIN_DIRECTORIES_INITIALIZED,
|
||||
EXTERNAL_STORAGE_PERMISSION_NEEDED,
|
||||
CANT_FIND_EXTERNAL_STORAGE
|
||||
}
|
||||
}
|
||||
|
@ -3,17 +3,14 @@ package org.citra.citra_android.services;
|
||||
import android.app.IntentService;
|
||||
import android.content.Intent;
|
||||
|
||||
public final class USBPermService extends IntentService
|
||||
{
|
||||
public USBPermService()
|
||||
{
|
||||
super("USBPermService");
|
||||
}
|
||||
public final class USBPermService extends IntentService {
|
||||
public USBPermService() {
|
||||
super("USBPermService");
|
||||
}
|
||||
|
||||
// Needed when extending IntentService.
|
||||
// We don't care about the results of the intent handler for this.
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent)
|
||||
{
|
||||
}
|
||||
// Needed when extending IntentService.
|
||||
// We don't care about the results of the intent handler for this.
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
}
|
||||
}
|
||||
|
@ -14,144 +14,116 @@ import android.view.View;
|
||||
* Implementation from:
|
||||
* https://gist.github.com/lapastillaroja/858caf1a82791b6c1a36
|
||||
*/
|
||||
public final class DividerItemDecoration extends RecyclerView.ItemDecoration
|
||||
{
|
||||
public final class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
|
||||
private Drawable mDivider;
|
||||
private boolean mShowFirstDivider = false;
|
||||
private boolean mShowLastDivider = false;
|
||||
private Drawable mDivider;
|
||||
private boolean mShowFirstDivider = false;
|
||||
private boolean mShowLastDivider = false;
|
||||
|
||||
|
||||
public DividerItemDecoration(Context context, AttributeSet attrs)
|
||||
{
|
||||
final TypedArray a = context
|
||||
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
|
||||
mDivider = a.getDrawable(0);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
|
||||
boolean showLastDivider)
|
||||
{
|
||||
this(context, attrs);
|
||||
mShowFirstDivider = showFirstDivider;
|
||||
mShowLastDivider = showLastDivider;
|
||||
}
|
||||
|
||||
public DividerItemDecoration(Drawable divider)
|
||||
{
|
||||
mDivider = divider;
|
||||
}
|
||||
|
||||
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
|
||||
boolean showLastDivider)
|
||||
{
|
||||
this(divider);
|
||||
mShowFirstDivider = showFirstDivider;
|
||||
mShowLastDivider = showLastDivider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||
RecyclerView.State state)
|
||||
{
|
||||
super.getItemOffsets(outRect, view, parent, state);
|
||||
if (mDivider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (parent.getChildPosition(view) < 1)
|
||||
{
|
||||
return;
|
||||
public DividerItemDecoration(Context context, AttributeSet attrs) {
|
||||
final TypedArray a = context
|
||||
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
|
||||
mDivider = a.getDrawable(0);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
|
||||
{
|
||||
outRect.top = mDivider.getIntrinsicHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
outRect.left = mDivider.getIntrinsicWidth();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state)
|
||||
{
|
||||
if (mDivider == null)
|
||||
{
|
||||
super.onDrawOver(c, parent, state);
|
||||
return;
|
||||
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
|
||||
boolean showLastDivider) {
|
||||
this(context, attrs);
|
||||
mShowFirstDivider = showFirstDivider;
|
||||
mShowLastDivider = showLastDivider;
|
||||
}
|
||||
|
||||
// Initialization needed to avoid compiler warning
|
||||
int left = 0, right = 0, top = 0, bottom = 0, size;
|
||||
int orientation = getOrientation(parent);
|
||||
int childCount = parent.getChildCount();
|
||||
|
||||
if (orientation == LinearLayoutManager.VERTICAL)
|
||||
{
|
||||
size = mDivider.getIntrinsicHeight();
|
||||
left = parent.getPaddingLeft();
|
||||
right = parent.getWidth() - parent.getPaddingRight();
|
||||
}
|
||||
else
|
||||
{ //horizontal
|
||||
size = mDivider.getIntrinsicWidth();
|
||||
top = parent.getPaddingTop();
|
||||
bottom = parent.getHeight() - parent.getPaddingBottom();
|
||||
public DividerItemDecoration(Drawable divider) {
|
||||
mDivider = divider;
|
||||
}
|
||||
|
||||
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++)
|
||||
{
|
||||
View child = parent.getChildAt(i);
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
if (orientation == LinearLayoutManager.VERTICAL)
|
||||
{
|
||||
top = child.getTop() - params.topMargin;
|
||||
bottom = top + size;
|
||||
}
|
||||
else
|
||||
{ //horizontal
|
||||
left = child.getLeft() - params.leftMargin;
|
||||
right = left + size;
|
||||
}
|
||||
mDivider.setBounds(left, top, right, bottom);
|
||||
mDivider.draw(c);
|
||||
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
|
||||
boolean showLastDivider) {
|
||||
this(divider);
|
||||
mShowFirstDivider = showFirstDivider;
|
||||
mShowLastDivider = showLastDivider;
|
||||
}
|
||||
|
||||
// show last divider
|
||||
if (mShowLastDivider && childCount > 0)
|
||||
{
|
||||
View child = parent.getChildAt(childCount - 1);
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
if (orientation == LinearLayoutManager.VERTICAL)
|
||||
{
|
||||
top = child.getBottom() + params.bottomMargin;
|
||||
bottom = top + size;
|
||||
}
|
||||
else
|
||||
{ // horizontal
|
||||
left = child.getRight() + params.rightMargin;
|
||||
right = left + size;
|
||||
}
|
||||
mDivider.setBounds(left, top, right, bottom);
|
||||
mDivider.draw(c);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||
RecyclerView.State state) {
|
||||
super.getItemOffsets(outRect, view, parent, state);
|
||||
if (mDivider == null) {
|
||||
return;
|
||||
}
|
||||
if (parent.getChildPosition(view) < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
private int getOrientation(RecyclerView parent)
|
||||
{
|
||||
if (parent.getLayoutManager() instanceof LinearLayoutManager)
|
||||
{
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
|
||||
return layoutManager.getOrientation();
|
||||
if (getOrientation(parent) == LinearLayoutManager.VERTICAL) {
|
||||
outRect.top = mDivider.getIntrinsicHeight();
|
||||
} else {
|
||||
outRect.left = mDivider.getIntrinsicWidth();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException(
|
||||
"DividerItemDecoration can only be used with a LinearLayoutManager.");
|
||||
|
||||
@Override
|
||||
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||
if (mDivider == null) {
|
||||
super.onDrawOver(c, parent, state);
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialization needed to avoid compiler warning
|
||||
int left = 0, right = 0, top = 0, bottom = 0, size;
|
||||
int orientation = getOrientation(parent);
|
||||
int childCount = parent.getChildCount();
|
||||
|
||||
if (orientation == LinearLayoutManager.VERTICAL) {
|
||||
size = mDivider.getIntrinsicHeight();
|
||||
left = parent.getPaddingLeft();
|
||||
right = parent.getWidth() - parent.getPaddingRight();
|
||||
} else { //horizontal
|
||||
size = mDivider.getIntrinsicWidth();
|
||||
top = parent.getPaddingTop();
|
||||
bottom = parent.getHeight() - parent.getPaddingBottom();
|
||||
}
|
||||
|
||||
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
if (orientation == LinearLayoutManager.VERTICAL) {
|
||||
top = child.getTop() - params.topMargin;
|
||||
bottom = top + size;
|
||||
} else { //horizontal
|
||||
left = child.getLeft() - params.leftMargin;
|
||||
right = left + size;
|
||||
}
|
||||
mDivider.setBounds(left, top, right, bottom);
|
||||
mDivider.draw(c);
|
||||
}
|
||||
|
||||
// show last divider
|
||||
if (mShowLastDivider && childCount > 0) {
|
||||
View child = parent.getChildAt(childCount - 1);
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
if (orientation == LinearLayoutManager.VERTICAL) {
|
||||
top = child.getBottom() + params.bottomMargin;
|
||||
bottom = top + size;
|
||||
} else { // horizontal
|
||||
left = child.getRight() + params.rightMargin;
|
||||
right = left + size;
|
||||
}
|
||||
mDivider.setBounds(left, top, right, bottom);
|
||||
mDivider.draw(c);
|
||||
}
|
||||
}
|
||||
|
||||
private int getOrientation(RecyclerView parent) {
|
||||
if (parent.getLayoutManager() instanceof LinearLayoutManager) {
|
||||
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
|
||||
return layoutManager.getOrientation();
|
||||
} else {
|
||||
throw new IllegalStateException(
|
||||
"DividerItemDecoration can only be used with a LinearLayoutManager.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,11 @@ import android.view.View;
|
||||
/**
|
||||
* Work around a bug with the nVidia Shield.
|
||||
*/
|
||||
public final class NVidiaShieldWorkaroundView extends View
|
||||
{
|
||||
public NVidiaShieldWorkaroundView(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
public final class NVidiaShieldWorkaroundView extends View {
|
||||
public NVidiaShieldWorkaroundView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
// Setting this seems to workaround the bug
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
// Setting this seems to workaround the bug
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.citra.citra_android.ui.input.gamecube;
|
||||
|
||||
|
||||
public class ControllerFragment
|
||||
{
|
||||
public class ControllerFragment {
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.citra.citra_android.ui.input.gamecube;
|
||||
|
||||
|
||||
public class ControllerFragmentPresenter
|
||||
{
|
||||
public class ControllerFragmentPresenter {
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.citra.citra_android.ui.input.gamecube;
|
||||
|
||||
|
||||
public interface ControllerFragmentView
|
||||
{
|
||||
public interface ControllerFragmentView {
|
||||
}
|
||||
|
@ -11,72 +11,59 @@ import android.widget.TextView;
|
||||
|
||||
import org.citra.citra_android.R;
|
||||
|
||||
public class CustomTitleView extends LinearLayout implements TitleViewAdapter.Provider
|
||||
{
|
||||
private final TextView mTitleView;
|
||||
private final View mBadgeView;
|
||||
public class CustomTitleView extends LinearLayout implements TitleViewAdapter.Provider {
|
||||
private final TextView mTitleView;
|
||||
private final View mBadgeView;
|
||||
|
||||
private final TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter()
|
||||
{
|
||||
@Override
|
||||
public View getSearchAffordanceView()
|
||||
{
|
||||
return null;
|
||||
private final TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter() {
|
||||
@Override
|
||||
public View getSearchAffordanceView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence titleText) {
|
||||
CustomTitleView.this.setTitle(titleText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBadgeDrawable(Drawable drawable) {
|
||||
CustomTitleView.this.setBadgeDrawable(drawable);
|
||||
}
|
||||
};
|
||||
|
||||
public CustomTitleView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CustomTitleView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CustomTitleView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
View root = LayoutInflater.from(context).inflate(R.layout.tv_title, this);
|
||||
mTitleView = root.findViewById(R.id.title);
|
||||
mBadgeView = root.findViewById(R.id.badge);
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
if (title != null) {
|
||||
mTitleView.setText(title);
|
||||
mTitleView.setVisibility(View.VISIBLE);
|
||||
mBadgeView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBadgeDrawable(Drawable drawable) {
|
||||
if (drawable != null) {
|
||||
mTitleView.setVisibility(View.GONE);
|
||||
mBadgeView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence titleText)
|
||||
{
|
||||
CustomTitleView.this.setTitle(titleText);
|
||||
public TitleViewAdapter getTitleViewAdapter() {
|
||||
return mTitleViewAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBadgeDrawable(Drawable drawable)
|
||||
{
|
||||
CustomTitleView.this.setBadgeDrawable(drawable);
|
||||
}
|
||||
};
|
||||
|
||||
public CustomTitleView(Context context)
|
||||
{
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public CustomTitleView(Context context, AttributeSet attrs)
|
||||
{
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CustomTitleView(Context context, AttributeSet attrs, int defStyle)
|
||||
{
|
||||
super(context, attrs, defStyle);
|
||||
View root = LayoutInflater.from(context).inflate(R.layout.tv_title, this);
|
||||
mTitleView = root.findViewById(R.id.title);
|
||||
mBadgeView = root.findViewById(R.id.badge);
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title)
|
||||
{
|
||||
if (title != null)
|
||||
{
|
||||
mTitleView.setText(title);
|
||||
mTitleView.setVisibility(View.VISIBLE);
|
||||
mBadgeView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setBadgeDrawable(Drawable drawable)
|
||||
{
|
||||
if (drawable != null)
|
||||
{
|
||||
mTitleView.setVisibility(View.GONE);
|
||||
mBadgeView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TitleViewAdapter getTitleViewAdapter()
|
||||
{
|
||||
return mTitleViewAdapter;
|
||||
}
|
||||
}
|
@ -28,186 +28,161 @@ import org.citra.citra_android.utils.StartupHandler;
|
||||
* The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which
|
||||
* individually display a grid of available games for each Fragment, in a tabbed layout.
|
||||
*/
|
||||
public final class MainActivity extends AppCompatActivity implements MainView
|
||||
{
|
||||
private Toolbar mToolbar;
|
||||
private int mFrameLayoutId;
|
||||
private PlatformGamesFragment mPlatformGamesFragment;
|
||||
private FloatingActionButton mFab;
|
||||
public final class MainActivity extends AppCompatActivity implements MainView {
|
||||
private Toolbar mToolbar;
|
||||
private int mFrameLayoutId;
|
||||
private PlatformGamesFragment mPlatformGamesFragment;
|
||||
private FloatingActionButton mFab;
|
||||
|
||||
private MainPresenter mPresenter = new MainPresenter(this);
|
||||
private MainPresenter mPresenter = new MainPresenter(this);
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
findViews();
|
||||
findViews();
|
||||
|
||||
setSupportActionBar(mToolbar);
|
||||
setSupportActionBar(mToolbar);
|
||||
|
||||
mFrameLayoutId = R.id.games_platform_frame;
|
||||
mFrameLayoutId = R.id.games_platform_frame;
|
||||
|
||||
// Set up the FAB.
|
||||
mFab.setOnClickListener(view -> mPresenter.onFabClick());
|
||||
// Set up the FAB.
|
||||
mFab.setOnClickListener(view -> mPresenter.onFabClick());
|
||||
|
||||
mPresenter.onCreate();
|
||||
mPresenter.onCreate();
|
||||
|
||||
// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
|
||||
if (savedInstanceState == null)
|
||||
StartupHandler.HandleInit(this);
|
||||
// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
|
||||
if (savedInstanceState == null)
|
||||
StartupHandler.HandleInit(this);
|
||||
|
||||
if (PermissionsHandler.hasWriteAccess(this))
|
||||
{
|
||||
mPlatformGamesFragment = new PlatformGamesFragment();
|
||||
getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment)
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
mPresenter.addDirIfNeeded(new AddDirectoryHelper(this));
|
||||
}
|
||||
|
||||
// TODO: Replace with a ButterKnife injection.
|
||||
private void findViews()
|
||||
{
|
||||
mToolbar = findViewById(R.id.toolbar_main);
|
||||
mFab = findViewById(R.id.button_add_directory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_game_grid, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* MainView
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setVersionString(String version)
|
||||
{
|
||||
mToolbar.setSubtitle(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh()
|
||||
{
|
||||
getContentResolver().insert(GameProvider.URI_REFRESH, null);
|
||||
refreshFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshFragmentScreenshot(int fragmentPosition)
|
||||
{
|
||||
// Invalidate Picasso image so that the new screenshot is animated in.
|
||||
PlatformGamesView fragment = getPlatformGamesView();
|
||||
|
||||
if (fragment != null)
|
||||
{
|
||||
fragment.refreshScreenshotAtPosition(fragmentPosition);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchSettingsActivity(String menuTag)
|
||||
{
|
||||
SettingsActivity.launch(this, menuTag, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchFileListActivity()
|
||||
{
|
||||
FileBrowserHelper.openDirectoryPicker(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showGames(Cursor games)
|
||||
{
|
||||
// no-op. Handled by PlatformGamesFragment.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param requestCode An int describing whether the Activity that is returning did so successfully.
|
||||
* @param resultCode An int describing what Activity is giving us this callback.
|
||||
* @param result The information the returning Activity is providing us.
|
||||
*/
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent result)
|
||||
{
|
||||
switch (requestCode)
|
||||
{
|
||||
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
||||
// If the user picked a file, as opposed to just backing out.
|
||||
if (resultCode == MainActivity.RESULT_OK)
|
||||
{
|
||||
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
||||
if (PermissionsHandler.hasWriteAccess(this)) {
|
||||
mPlatformGamesFragment = new PlatformGamesFragment();
|
||||
getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment)
|
||||
.commit();
|
||||
}
|
||||
break;
|
||||
|
||||
case MainPresenter.REQUEST_EMULATE_GAME:
|
||||
mPresenter.refreshFragmentScreenshot(resultCode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
|
||||
{
|
||||
switch (requestCode)
|
||||
{
|
||||
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
DirectoryInitializationService.startService(this);
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mPresenter.addDirIfNeeded(new AddDirectoryHelper(this));
|
||||
}
|
||||
|
||||
mPlatformGamesFragment = new PlatformGamesFragment();
|
||||
getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment)
|
||||
.commit();
|
||||
// TODO: Replace with a ButterKnife injection.
|
||||
private void findViews() {
|
||||
mToolbar = findViewById(R.id.toolbar_main);
|
||||
mFab = findViewById(R.id.button_add_directory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_game_grid, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* MainView
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setVersionString(String version) {
|
||||
mToolbar.setSubtitle(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
getContentResolver().insert(GameProvider.URI_REFRESH, null);
|
||||
refreshFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshFragmentScreenshot(int fragmentPosition) {
|
||||
// Invalidate Picasso image so that the new screenshot is animated in.
|
||||
PlatformGamesView fragment = getPlatformGamesView();
|
||||
|
||||
if (fragment != null) {
|
||||
fragment.refreshScreenshotAtPosition(fragmentPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchSettingsActivity(String menuTag) {
|
||||
SettingsActivity.launch(this, menuTag, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchFileListActivity() {
|
||||
FileBrowserHelper.openDirectoryPicker(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showGames(Cursor games) {
|
||||
// no-op. Handled by PlatformGamesFragment.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param requestCode An int describing whether the Activity that is returning did so successfully.
|
||||
* @param resultCode An int describing what Activity is giving us this callback.
|
||||
* @param result The information the returning Activity is providing us.
|
||||
*/
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
|
||||
switch (requestCode) {
|
||||
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
||||
// If the user picked a file, as opposed to just backing out.
|
||||
if (resultCode == MainActivity.RESULT_OK) {
|
||||
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
||||
}
|
||||
break;
|
||||
|
||||
case MainPresenter.REQUEST_EMULATE_GAME:
|
||||
mPresenter.refreshFragmentScreenshot(resultCode);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the framework whenever any actionbar/toolbar icon is clicked.
|
||||
*
|
||||
* @param item The icon that was clicked on.
|
||||
* @return True if the event was handled, false to bubble it up to the OS.
|
||||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
return mPresenter.handleOptionSelection(item.getItemId());
|
||||
}
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
DirectoryInitializationService.startService(this);
|
||||
|
||||
private void refreshFragment()
|
||||
{
|
||||
if (mPlatformGamesFragment != null)
|
||||
{
|
||||
mPlatformGamesFragment.refresh();
|
||||
mPlatformGamesFragment = new PlatformGamesFragment();
|
||||
getSupportFragmentManager().beginTransaction().add(mFrameLayoutId, mPlatformGamesFragment)
|
||||
.commit();
|
||||
} else {
|
||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PlatformGamesView getPlatformGamesView()
|
||||
{
|
||||
return (PlatformGamesView) getSupportFragmentManager().findFragmentById(mFrameLayoutId);
|
||||
}
|
||||
/**
|
||||
* Called by the framework whenever any actionbar/toolbar icon is clicked.
|
||||
*
|
||||
* @param item The icon that was clicked on.
|
||||
* @return True if the event was handled, false to bubble it up to the OS.
|
||||
*/
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return mPresenter.handleOptionSelection(item.getItemId());
|
||||
}
|
||||
|
||||
private void refreshFragment() {
|
||||
if (mPlatformGamesFragment != null) {
|
||||
mPlatformGamesFragment.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PlatformGamesView getPlatformGamesView() {
|
||||
return (PlatformGamesView) getSupportFragmentManager().findFragmentById(mFrameLayoutId);
|
||||
}
|
||||
}
|
||||
|
@ -11,80 +11,69 @@ import org.citra.citra_android.utils.SettingsFile;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public final class MainPresenter
|
||||
{
|
||||
public static final int REQUEST_ADD_DIRECTORY = 1;
|
||||
public static final int REQUEST_EMULATE_GAME = 2;
|
||||
public final class MainPresenter {
|
||||
public static final int REQUEST_ADD_DIRECTORY = 1;
|
||||
public static final int REQUEST_EMULATE_GAME = 2;
|
||||
|
||||
private final MainView mView;
|
||||
private String mDirToAdd;
|
||||
private final MainView mView;
|
||||
private String mDirToAdd;
|
||||
|
||||
public MainPresenter(MainView view)
|
||||
{
|
||||
mView = view;
|
||||
}
|
||||
public MainPresenter(MainView view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
public void onCreate()
|
||||
{
|
||||
String versionName = BuildConfig.VERSION_NAME;
|
||||
mView.setVersionString(versionName);
|
||||
}
|
||||
public void onCreate() {
|
||||
String versionName = BuildConfig.VERSION_NAME;
|
||||
mView.setVersionString(versionName);
|
||||
}
|
||||
|
||||
public void onFabClick()
|
||||
{
|
||||
mView.launchFileListActivity();
|
||||
}
|
||||
|
||||
public boolean handleOptionSelection(int itemId)
|
||||
{
|
||||
switch (itemId)
|
||||
{
|
||||
case R.id.menu_settings_core:
|
||||
mView.launchSettingsActivity(SettingsFile.FILE_NAME_CONFIG);
|
||||
return true;
|
||||
|
||||
case R.id.menu_refresh:
|
||||
GameDatabase databaseHelper = DolphinApplication.databaseHelper;
|
||||
databaseHelper.scanLibrary(databaseHelper.getWritableDatabase());
|
||||
mView.refresh();
|
||||
return true;
|
||||
|
||||
case R.id.button_add_directory:
|
||||
public void onFabClick() {
|
||||
mView.launchFileListActivity();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public boolean handleOptionSelection(int itemId) {
|
||||
switch (itemId) {
|
||||
case R.id.menu_settings_core:
|
||||
mView.launchSettingsActivity(SettingsFile.FILE_NAME_CONFIG);
|
||||
return true;
|
||||
|
||||
public void addDirIfNeeded(AddDirectoryHelper helper)
|
||||
{
|
||||
if (mDirToAdd != null)
|
||||
{
|
||||
helper.addDirectory(mDirToAdd, mView::refresh);
|
||||
case R.id.menu_refresh:
|
||||
GameDatabase databaseHelper = DolphinApplication.databaseHelper;
|
||||
databaseHelper.scanLibrary(databaseHelper.getWritableDatabase());
|
||||
mView.refresh();
|
||||
return true;
|
||||
|
||||
mDirToAdd = null;
|
||||
case R.id.button_add_directory:
|
||||
mView.launchFileListActivity();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void onDirectorySelected(String dir)
|
||||
{
|
||||
mDirToAdd = dir;
|
||||
}
|
||||
public void addDirIfNeeded(AddDirectoryHelper helper) {
|
||||
if (mDirToAdd != null) {
|
||||
helper.addDirectory(mDirToAdd, mView::refresh);
|
||||
|
||||
public void refreshFragmentScreenshot(int resultCode)
|
||||
{
|
||||
mView.refreshFragmentScreenshot(resultCode);
|
||||
}
|
||||
mDirToAdd = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void onDirectorySelected(String dir) {
|
||||
mDirToAdd = dir;
|
||||
}
|
||||
|
||||
public void refreshFragmentScreenshot(int resultCode) {
|
||||
mView.refreshFragmentScreenshot(resultCode);
|
||||
}
|
||||
|
||||
|
||||
public void loadGames()
|
||||
{
|
||||
GameDatabase databaseHelper = DolphinApplication.databaseHelper;
|
||||
public void loadGames() {
|
||||
GameDatabase databaseHelper = DolphinApplication.databaseHelper;
|
||||
|
||||
databaseHelper.getGames()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(games -> mView.showGames(games));
|
||||
}
|
||||
databaseHelper.getGames()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(games -> mView.showGames(games));
|
||||
}
|
||||
}
|
||||
|
@ -7,39 +7,38 @@ import android.database.Cursor;
|
||||
* Implementations will differ primarily to target touch-screen
|
||||
* or non-touch screen devices.
|
||||
*/
|
||||
public interface MainView
|
||||
{
|
||||
/**
|
||||
* Pass the view the native library's version string. Displaying
|
||||
* it is optional.
|
||||
*
|
||||
* @param version A string pulled from native code.
|
||||
*/
|
||||
void setVersionString(String version);
|
||||
public interface MainView {
|
||||
/**
|
||||
* Pass the view the native library's version string. Displaying
|
||||
* it is optional.
|
||||
*
|
||||
* @param version A string pulled from native code.
|
||||
*/
|
||||
void setVersionString(String version);
|
||||
|
||||
/**
|
||||
* Tell the view to refresh its contents.
|
||||
*/
|
||||
void refresh();
|
||||
/**
|
||||
* Tell the view to refresh its contents.
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
/**
|
||||
* Tell the view to tell the currently displayed {@link android.support.v4.app.Fragment}
|
||||
* to refresh the screenshot at the given position in its list of games.
|
||||
*
|
||||
* @param fragmentPosition An index corresponding to the list or grid of games.
|
||||
*/
|
||||
void refreshFragmentScreenshot(int fragmentPosition);
|
||||
/**
|
||||
* Tell the view to tell the currently displayed {@link android.support.v4.app.Fragment}
|
||||
* to refresh the screenshot at the given position in its list of games.
|
||||
*
|
||||
* @param fragmentPosition An index corresponding to the list or grid of games.
|
||||
*/
|
||||
void refreshFragmentScreenshot(int fragmentPosition);
|
||||
|
||||
|
||||
void launchSettingsActivity(String menuTag);
|
||||
void launchSettingsActivity(String menuTag);
|
||||
|
||||
void launchFileListActivity();
|
||||
void launchFileListActivity();
|
||||
|
||||
/**
|
||||
* To be called when an asynchronous database read completes. Passes the
|
||||
* result, in this case a {@link Cursor} to the view.
|
||||
*
|
||||
* @param games A Cursor containing the games read from the database.
|
||||
*/
|
||||
void showGames(Cursor games);
|
||||
/**
|
||||
* To be called when an asynchronous database read completes. Passes the
|
||||
* result, in this case a {@link Cursor} to the view.
|
||||
*
|
||||
* @param games A Cursor containing the games read from the database.
|
||||
*/
|
||||
void showGames(Cursor games);
|
||||
}
|
||||
|
@ -31,239 +31,208 @@ import org.citra.citra_android.utils.PermissionsHandler;
|
||||
import org.citra.citra_android.utils.StartupHandler;
|
||||
import org.citra.citra_android.viewholders.TvGameViewHolder;
|
||||
|
||||
public final class TvMainActivity extends FragmentActivity implements MainView
|
||||
{
|
||||
private MainPresenter mPresenter = new MainPresenter(this);
|
||||
public final class TvMainActivity extends FragmentActivity implements MainView {
|
||||
private MainPresenter mPresenter = new MainPresenter(this);
|
||||
|
||||
private BrowseSupportFragment mBrowseFragment;
|
||||
private BrowseSupportFragment mBrowseFragment;
|
||||
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
private ArrayObjectAdapter mRowsAdapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_tv_main);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_tv_main);
|
||||
|
||||
setupUI();
|
||||
setupUI();
|
||||
|
||||
mPresenter.onCreate();
|
||||
mPresenter.onCreate();
|
||||
|
||||
// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
|
||||
if (savedInstanceState == null)
|
||||
StartupHandler.HandleInit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
mPresenter.addDirIfNeeded(new AddDirectoryHelper(this));
|
||||
}
|
||||
|
||||
void setupUI()
|
||||
{
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
mBrowseFragment = new BrowseSupportFragment();
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.add(R.id.content, mBrowseFragment, "BrowseFragment")
|
||||
.commit();
|
||||
|
||||
// Set display parameters for the BrowseFragment
|
||||
mBrowseFragment.setHeadersState(BrowseFragment.HEADERS_ENABLED);
|
||||
mBrowseFragment.setBrandColor(ContextCompat.getColor(this, R.color.citra_orange_dark));
|
||||
buildRowsAdapter();
|
||||
|
||||
mBrowseFragment.setOnItemViewClickedListener(
|
||||
(itemViewHolder, item, rowViewHolder, row) ->
|
||||
{
|
||||
// Special case: user clicked on a settings row item.
|
||||
if (item instanceof TvSettingsItem)
|
||||
{
|
||||
TvSettingsItem settingsItem = (TvSettingsItem) item;
|
||||
mPresenter.handleOptionSelection(settingsItem.getItemId());
|
||||
}
|
||||
else
|
||||
{
|
||||
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;
|
||||
|
||||
// Start the emulation activity and send the path of the clicked ISO to it.
|
||||
EmulationActivity.launch(TvMainActivity.this,
|
||||
holder.path,
|
||||
holder.title,
|
||||
holder.screenshotPath,
|
||||
-1,
|
||||
holder.imageScreenshot);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* MainView
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setVersionString(String version)
|
||||
{
|
||||
mBrowseFragment.setTitle(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh()
|
||||
{
|
||||
recreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshFragmentScreenshot(int fragmentPosition)
|
||||
{
|
||||
mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchSettingsActivity(String menuTag)
|
||||
{
|
||||
SettingsActivity.launch(this, menuTag, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchFileListActivity()
|
||||
{
|
||||
FileBrowserHelper.openDirectoryPicker(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showGames(Cursor games)
|
||||
{
|
||||
ListRow row = buildGamesRow(games);
|
||||
|
||||
// Add row to the adapter only if it is not empty.
|
||||
if (row != null)
|
||||
{
|
||||
mRowsAdapter.add(games);
|
||||
// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
|
||||
if (savedInstanceState == null)
|
||||
StartupHandler.HandleInit(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity.
|
||||
*
|
||||
* @param requestCode An int describing whether the Activity that is returning did so successfully.
|
||||
* @param resultCode An int describing what Activity is giving us this callback.
|
||||
* @param result The information the returning Activity is providing us.
|
||||
*/
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent result)
|
||||
{
|
||||
switch (requestCode)
|
||||
{
|
||||
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
||||
// If the user picked a file, as opposed to just backing out.
|
||||
if (resultCode == MainActivity.RESULT_OK)
|
||||
{
|
||||
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mPresenter.addDirIfNeeded(new AddDirectoryHelper(this));
|
||||
}
|
||||
|
||||
void setupUI() {
|
||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
mBrowseFragment = new BrowseSupportFragment();
|
||||
fragmentManager
|
||||
.beginTransaction()
|
||||
.add(R.id.content, mBrowseFragment, "BrowseFragment")
|
||||
.commit();
|
||||
|
||||
// Set display parameters for the BrowseFragment
|
||||
mBrowseFragment.setHeadersState(BrowseFragment.HEADERS_ENABLED);
|
||||
mBrowseFragment.setBrandColor(ContextCompat.getColor(this, R.color.citra_orange_dark));
|
||||
buildRowsAdapter();
|
||||
|
||||
mBrowseFragment.setOnItemViewClickedListener(
|
||||
(itemViewHolder, item, rowViewHolder, row) ->
|
||||
{
|
||||
// Special case: user clicked on a settings row item.
|
||||
if (item instanceof TvSettingsItem) {
|
||||
TvSettingsItem settingsItem = (TvSettingsItem) item;
|
||||
mPresenter.handleOptionSelection(settingsItem.getItemId());
|
||||
} else {
|
||||
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;
|
||||
|
||||
// Start the emulation activity and send the path of the clicked ISO to it.
|
||||
EmulationActivity.launch(TvMainActivity.this,
|
||||
holder.path,
|
||||
holder.title,
|
||||
holder.screenshotPath,
|
||||
-1,
|
||||
holder.imageScreenshot);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* MainView
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void setVersionString(String version) {
|
||||
mBrowseFragment.setTitle(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
recreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshFragmentScreenshot(int fragmentPosition) {
|
||||
mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchSettingsActivity(String menuTag) {
|
||||
SettingsActivity.launch(this, menuTag, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void launchFileListActivity() {
|
||||
FileBrowserHelper.openDirectoryPicker(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showGames(Cursor games) {
|
||||
ListRow row = buildGamesRow(games);
|
||||
|
||||
// Add row to the adapter only if it is not empty.
|
||||
if (row != null) {
|
||||
mRowsAdapter.add(games);
|
||||
}
|
||||
break;
|
||||
|
||||
case MainPresenter.REQUEST_EMULATE_GAME:
|
||||
mPresenter.refreshFragmentScreenshot(resultCode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
|
||||
{
|
||||
switch (requestCode)
|
||||
{
|
||||
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
DirectoryInitializationService.startService(this);
|
||||
loadGames();
|
||||
/**
|
||||
* Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity.
|
||||
*
|
||||
* @param requestCode An int describing whether the Activity that is returning did so successfully.
|
||||
* @param resultCode An int describing what Activity is giving us this callback.
|
||||
* @param result The information the returning Activity is providing us.
|
||||
*/
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent result) {
|
||||
switch (requestCode) {
|
||||
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
||||
// If the user picked a file, as opposed to just backing out.
|
||||
if (resultCode == MainActivity.RESULT_OK) {
|
||||
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
||||
}
|
||||
break;
|
||||
|
||||
case MainPresenter.REQUEST_EMULATE_GAME:
|
||||
mPresenter.refreshFragmentScreenshot(resultCode);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
DirectoryInitializationService.startService(this);
|
||||
loadGames();
|
||||
} else {
|
||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void buildRowsAdapter()
|
||||
{
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||
|
||||
if (PermissionsHandler.hasWriteAccess(this))
|
||||
{
|
||||
loadGames();
|
||||
}
|
||||
|
||||
mRowsAdapter.add(buildSettingsRow());
|
||||
private void buildRowsAdapter() {
|
||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||
|
||||
mBrowseFragment.setAdapter(mRowsAdapter);
|
||||
}
|
||||
if (PermissionsHandler.hasWriteAccess(this)) {
|
||||
loadGames();
|
||||
}
|
||||
|
||||
private void loadGames()
|
||||
{
|
||||
mPresenter.loadGames();
|
||||
}
|
||||
mRowsAdapter.add(buildSettingsRow());
|
||||
|
||||
private ListRow buildGamesRow(Cursor games)
|
||||
{
|
||||
// Create an adapter for this row.
|
||||
CursorObjectAdapter row = new CursorObjectAdapter(new GameRowPresenter());
|
||||
|
||||
// If cursor is empty, don't return a Row.
|
||||
if (!games.moveToFirst())
|
||||
{
|
||||
return null;
|
||||
mBrowseFragment.setAdapter(mRowsAdapter);
|
||||
}
|
||||
|
||||
row.changeCursor(games);
|
||||
row.setMapper(new CursorMapper()
|
||||
{
|
||||
@Override
|
||||
protected void bindColumns(Cursor cursor)
|
||||
{
|
||||
// No-op? Not sure what this does.
|
||||
}
|
||||
private void loadGames() {
|
||||
mPresenter.loadGames();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object bind(Cursor cursor)
|
||||
{
|
||||
return Game.fromCursor(cursor);
|
||||
}
|
||||
});
|
||||
private ListRow buildGamesRow(Cursor games) {
|
||||
// Create an adapter for this row.
|
||||
CursorObjectAdapter row = new CursorObjectAdapter(new GameRowPresenter());
|
||||
|
||||
// Create the row, passing it the filled adapter and the header, and give it to the master adapter.
|
||||
return new ListRow(null, row);
|
||||
}
|
||||
// If cursor is empty, don't return a Row.
|
||||
if (!games.moveToFirst()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ListRow buildSettingsRow()
|
||||
{
|
||||
ArrayObjectAdapter rowItems = new ArrayObjectAdapter(new SettingsRowPresenter());
|
||||
row.changeCursor(games);
|
||||
row.setMapper(new CursorMapper() {
|
||||
@Override
|
||||
protected void bindColumns(Cursor cursor) {
|
||||
// No-op? Not sure what this does.
|
||||
}
|
||||
|
||||
rowItems.add(new TvSettingsItem(R.id.menu_settings_core,
|
||||
R.drawable.ic_settings_core_tv,
|
||||
R.string.grid_menu_core_settings));
|
||||
@Override
|
||||
protected Object bind(Cursor cursor) {
|
||||
return Game.fromCursor(cursor);
|
||||
}
|
||||
});
|
||||
|
||||
rowItems.add(new TvSettingsItem(R.id.button_add_directory,
|
||||
R.drawable.ic_add_tv,
|
||||
R.string.add_directory_title));
|
||||
// Create the row, passing it the filled adapter and the header, and give it to the master adapter.
|
||||
return new ListRow(null, row);
|
||||
}
|
||||
|
||||
rowItems.add(new TvSettingsItem(R.id.menu_refresh,
|
||||
R.drawable.ic_refresh_tv,
|
||||
R.string.grid_menu_refresh));
|
||||
private ListRow buildSettingsRow() {
|
||||
ArrayObjectAdapter rowItems = new ArrayObjectAdapter(new SettingsRowPresenter());
|
||||
|
||||
// Create a header for this row.
|
||||
HeaderItem header =
|
||||
new HeaderItem(R.string.preferences_settings, getString(R.string.preferences_settings));
|
||||
rowItems.add(new TvSettingsItem(R.id.menu_settings_core,
|
||||
R.drawable.ic_settings_core_tv,
|
||||
R.string.grid_menu_core_settings));
|
||||
|
||||
return new ListRow(header, rowItems);
|
||||
}
|
||||
rowItems.add(new TvSettingsItem(R.id.button_add_directory,
|
||||
R.drawable.ic_add_tv,
|
||||
R.string.add_directory_title));
|
||||
|
||||
rowItems.add(new TvSettingsItem(R.id.menu_refresh,
|
||||
R.drawable.ic_refresh_tv,
|
||||
R.string.grid_menu_refresh));
|
||||
|
||||
// Create a header for this row.
|
||||
HeaderItem header =
|
||||
new HeaderItem(R.string.preferences_settings, getString(R.string.preferences_settings));
|
||||
|
||||
return new ListRow(header, rowItems);
|
||||
}
|
||||
}
|
||||
|
@ -13,76 +13,66 @@ import android.view.ViewGroup;
|
||||
import org.citra.citra_android.R;
|
||||
import org.citra.citra_android.adapters.GameAdapter;
|
||||
|
||||
public final class PlatformGamesFragment extends Fragment implements PlatformGamesView
|
||||
{
|
||||
private static final String ARG_PLATFORM = "platform";
|
||||
public final class PlatformGamesFragment extends Fragment implements PlatformGamesView {
|
||||
private static final String ARG_PLATFORM = "platform";
|
||||
|
||||
private PlatformGamesPresenter mPresenter = new PlatformGamesPresenter(this);
|
||||
private PlatformGamesPresenter mPresenter = new PlatformGamesPresenter(this);
|
||||
|
||||
private GameAdapter mAdapter;
|
||||
private RecyclerView mRecyclerView;
|
||||
private GameAdapter mAdapter;
|
||||
private RecyclerView mRecyclerView;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||
{
|
||||
View rootView = inflater.inflate(R.layout.fragment_grid, container, false);
|
||||
|
||||
findViews(rootView);
|
||||
|
||||
mPresenter.onCreateView();
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState)
|
||||
{
|
||||
int columns = getResources().getInteger(R.integer.game_grid_columns);
|
||||
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns);
|
||||
mAdapter = new GameAdapter();
|
||||
|
||||
mRecyclerView.setLayoutManager(layoutManager);
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
|
||||
mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshScreenshotAtPosition(int position)
|
||||
{
|
||||
mAdapter.notifyItemChanged(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh()
|
||||
{
|
||||
mPresenter.refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(String gameId)
|
||||
{
|
||||
// No-op for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showGames(Cursor games)
|
||||
{
|
||||
if (mAdapter != null)
|
||||
{
|
||||
mAdapter.swapCursor(games);
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
||||
private void findViews(View root)
|
||||
{
|
||||
mRecyclerView = root.findViewById(R.id.grid_games);
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_grid, container, false);
|
||||
|
||||
findViews(rootView);
|
||||
|
||||
mPresenter.onCreateView();
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
int columns = getResources().getInteger(R.integer.game_grid_columns);
|
||||
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns);
|
||||
mAdapter = new GameAdapter();
|
||||
|
||||
mRecyclerView.setLayoutManager(layoutManager);
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
|
||||
mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshScreenshotAtPosition(int position) {
|
||||
mAdapter.notifyItemChanged(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refresh() {
|
||||
mPresenter.refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(String gameId) {
|
||||
// No-op for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showGames(Cursor games) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.swapCursor(games);
|
||||
}
|
||||
}
|
||||
|
||||
private void findViews(View root) {
|
||||
mRecyclerView = root.findViewById(R.id.grid_games);
|
||||
}
|
||||
}
|
||||
|
@ -8,40 +8,35 @@ import org.citra.citra_android.utils.Log;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public final class PlatformGamesPresenter
|
||||
{
|
||||
private final PlatformGamesView mView;
|
||||
public final class PlatformGamesPresenter {
|
||||
private final PlatformGamesView mView;
|
||||
|
||||
public PlatformGamesPresenter(PlatformGamesView view)
|
||||
{
|
||||
mView = view;
|
||||
}
|
||||
public PlatformGamesPresenter(PlatformGamesView view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
public void onCreateView()
|
||||
{
|
||||
loadGames();
|
||||
}
|
||||
public void onCreateView() {
|
||||
loadGames();
|
||||
}
|
||||
|
||||
public void refresh()
|
||||
{
|
||||
Log.debug("[PlatformGamesPresenter] : Refreshing...");
|
||||
loadGames();
|
||||
}
|
||||
public void refresh() {
|
||||
Log.debug("[PlatformGamesPresenter] : Refreshing...");
|
||||
loadGames();
|
||||
}
|
||||
|
||||
private void loadGames()
|
||||
{
|
||||
Log.debug("[PlatformGamesPresenter] : Loading games...");
|
||||
private void loadGames() {
|
||||
Log.debug("[PlatformGamesPresenter] : Loading games...");
|
||||
|
||||
GameDatabase databaseHelper = DolphinApplication.databaseHelper;
|
||||
GameDatabase databaseHelper = DolphinApplication.databaseHelper;
|
||||
|
||||
databaseHelper.getGames()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(games ->
|
||||
{
|
||||
Log.debug("[PlatformGamesPresenter] : Load finished, swapping cursor...");
|
||||
databaseHelper.getGames()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(games ->
|
||||
{
|
||||
Log.debug("[PlatformGamesPresenter] : Load finished, swapping cursor...");
|
||||
|
||||
mView.showGames(games);
|
||||
});
|
||||
}
|
||||
mView.showGames(games);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -5,34 +5,33 @@ import android.database.Cursor;
|
||||
/**
|
||||
* Abstraction for a screen representing a single platform's games.
|
||||
*/
|
||||
public interface PlatformGamesView
|
||||
{
|
||||
/**
|
||||
* Tell the view to refresh its contents.
|
||||
*/
|
||||
void refresh();
|
||||
public interface PlatformGamesView {
|
||||
/**
|
||||
* Tell the view to refresh its contents.
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
/**
|
||||
* Tell the view that a certain game's screenshot has been updated,
|
||||
* and should be redrawn on-screen.
|
||||
*
|
||||
* @param position The index of the game that should be redrawn.
|
||||
*/
|
||||
void refreshScreenshotAtPosition(int position);
|
||||
/**
|
||||
* Tell the view that a certain game's screenshot has been updated,
|
||||
* and should be redrawn on-screen.
|
||||
*
|
||||
* @param position The index of the game that should be redrawn.
|
||||
*/
|
||||
void refreshScreenshotAtPosition(int position);
|
||||
|
||||
/**
|
||||
* Pass a click event to the view's Presenter. Typically called from the
|
||||
* view's list adapter.
|
||||
*
|
||||
* @param gameId The ID of the game that was clicked.
|
||||
*/
|
||||
void onItemClick(String gameId);
|
||||
/**
|
||||
* Pass a click event to the view's Presenter. Typically called from the
|
||||
* view's list adapter.
|
||||
*
|
||||
* @param gameId The ID of the game that was clicked.
|
||||
*/
|
||||
void onItemClick(String gameId);
|
||||
|
||||
/**
|
||||
* To be called when an asynchronous database read completes. Passes the
|
||||
* result, in this case a {@link Cursor}, to the view.
|
||||
*
|
||||
* @param games A Cursor containing the games read from the database.
|
||||
*/
|
||||
void showGames(Cursor games);
|
||||
/**
|
||||
* To be called when an asynchronous database read completes. Passes the
|
||||
* result, in this case a {@link Cursor}, to the view.
|
||||
*
|
||||
* @param games A Cursor containing the games read from the database.
|
||||
*/
|
||||
void showGames(Cursor games);
|
||||
}
|
||||
|
@ -18,249 +18,215 @@ import org.citra.citra_android.R;
|
||||
import org.citra.citra_android.model.settings.SettingSection;
|
||||
import org.citra.citra_android.services.DirectoryInitializationService;
|
||||
import org.citra.citra_android.utils.DirectoryStateReceiver;
|
||||
import org.citra.citra_android.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";
|
||||
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 static final String FRAGMENT_TAG = "settings";
|
||||
private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this);
|
||||
|
||||
private ProgressDialog dialog;
|
||||
private ProgressDialog dialog;
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
context.startActivity(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_settings);
|
||||
setContentView(R.layout.activity_settings);
|
||||
|
||||
Intent launcher = getIntent();
|
||||
String filename = launcher.getStringExtra(ARG_FILE_NAME);
|
||||
String gameID = launcher.getStringExtra(ARG_GAME_ID);
|
||||
Intent launcher = getIntent();
|
||||
String filename = launcher.getStringExtra(ARG_FILE_NAME);
|
||||
String gameID = launcher.getStringExtra(ARG_GAME_ID);
|
||||
|
||||
mPresenter.onCreate(savedInstanceState, filename, gameID);
|
||||
}
|
||||
mPresenter.onCreate(savedInstanceState, filename, gameID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu)
|
||||
{
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_settings, menu);
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_settings, menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item)
|
||||
{
|
||||
return mPresenter.handleOptionsItem(item.getItemId());
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return mPresenter.handleOptionsItem(item.getItemId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState)
|
||||
{
|
||||
// Critical: If super method is not called, rotations will be busted.
|
||||
super.onSaveInstanceState(outState);
|
||||
mPresenter.saveState(outState);
|
||||
}
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
// Critical: If super method is not called, rotations will be busted.
|
||||
super.onSaveInstanceState(outState);
|
||||
mPresenter.saveState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart()
|
||||
{
|
||||
super.onStart();
|
||||
mPresenter.onStart();
|
||||
}
|
||||
@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
|
||||
* IntentService which will do so on a background thread.
|
||||
*/
|
||||
@Override
|
||||
protected void onStop()
|
||||
{
|
||||
super.onStop();
|
||||
/**
|
||||
* 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
|
||||
* IntentService which will do so on a background thread.
|
||||
*/
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
|
||||
mPresenter.onStop(isFinishing());
|
||||
}
|
||||
mPresenter.onStop(isFinishing());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed()
|
||||
{
|
||||
mPresenter.onBackPressed();
|
||||
}
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
mPresenter.onBackPressed();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void showSettingsFragment(String menuTag, boolean addToStack, String gameID)
|
||||
{
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||
@Override
|
||||
public void showSettingsFragment(String menuTag, boolean addToStack, String gameID) {
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||
|
||||
if (addToStack)
|
||||
{
|
||||
if (areSystemAnimationsEnabled())
|
||||
{
|
||||
transaction.setCustomAnimations(
|
||||
R.animator.settings_enter,
|
||||
R.animator.settings_exit,
|
||||
R.animator.settings_pop_enter,
|
||||
R.animator.setttings_pop_exit);
|
||||
}
|
||||
if (addToStack) {
|
||||
if (areSystemAnimationsEnabled()) {
|
||||
transaction.setCustomAnimations(
|
||||
R.animator.settings_enter,
|
||||
R.animator.settings_exit,
|
||||
R.animator.settings_pop_enter,
|
||||
R.animator.setttings_pop_exit);
|
||||
}
|
||||
|
||||
transaction.addToBackStack(null);
|
||||
mPresenter.addToStack();
|
||||
}
|
||||
transaction.replace(R.id.frame_content, SettingsFragment.newInstance(menuTag, gameID), FRAGMENT_TAG);
|
||||
transaction.addToBackStack(null);
|
||||
mPresenter.addToStack();
|
||||
}
|
||||
transaction.replace(R.id.frame_content, SettingsFragment.newInstance(menuTag, gameID), FRAGMENT_TAG);
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
transaction.commit();
|
||||
}
|
||||
|
||||
private boolean areSystemAnimationsEnabled()
|
||||
{
|
||||
float duration = Settings.Global.getFloat(
|
||||
getContentResolver(),
|
||||
Settings.Global.ANIMATOR_DURATION_SCALE, 1);
|
||||
float transition = Settings.Global.getFloat(
|
||||
getContentResolver(),
|
||||
Settings.Global.TRANSITION_ANIMATION_SCALE, 1);
|
||||
return duration != 0 && transition != 0;
|
||||
}
|
||||
private boolean areSystemAnimationsEnabled() {
|
||||
float duration = Settings.Global.getFloat(
|
||||
getContentResolver(),
|
||||
Settings.Global.ANIMATOR_DURATION_SCALE, 1);
|
||||
float transition = Settings.Global.getFloat(
|
||||
getContentResolver(),
|
||||
Settings.Global.TRANSITION_ANIMATION_SCALE, 1);
|
||||
return duration != 0 && transition != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter)
|
||||
{
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||
receiver,
|
||||
filter);
|
||||
DirectoryInitializationService.startService(this);
|
||||
}
|
||||
@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 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);
|
||||
}
|
||||
@Override
|
||||
public void showLoading() {
|
||||
if (dialog == null) {
|
||||
dialog = new ProgressDialog(this);
|
||||
dialog.setMessage(getString(R.string.load_settings));
|
||||
dialog.setIndeterminate(true);
|
||||
}
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideLoading()
|
||||
{
|
||||
dialog.dismiss();
|
||||
}
|
||||
@Override
|
||||
public void hideLoading() {
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showPermissionNeededHint()
|
||||
{
|
||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
@Override
|
||||
public void showPermissionNeededHint() {
|
||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showExternalStorageNotMountedHint()
|
||||
{
|
||||
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
@Override
|
||||
public void showExternalStorageNotMountedHint() {
|
||||
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, SettingSection> getSettings(int file)
|
||||
{
|
||||
return mPresenter.getSettings(file);
|
||||
}
|
||||
@Override
|
||||
public HashMap<String, SettingSection> getSettings(int file) {
|
||||
return mPresenter.getSettings(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings)
|
||||
{
|
||||
mPresenter.setSettings(settings);
|
||||
}
|
||||
@Override
|
||||
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) {
|
||||
mPresenter.setSettings(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings)
|
||||
{
|
||||
SettingsFragmentView fragment = getFragment();
|
||||
@Override
|
||||
public void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings) {
|
||||
SettingsFragmentView fragment = getFragment();
|
||||
|
||||
if (fragment != null)
|
||||
{
|
||||
fragment.onSettingsFileLoaded(settings);
|
||||
}
|
||||
}
|
||||
if (fragment != null) {
|
||||
fragment.onSettingsFileLoaded(settings);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettingsFileNotFound()
|
||||
{
|
||||
SettingsFragmentView fragment = getFragment();
|
||||
@Override
|
||||
public void onSettingsFileNotFound() {
|
||||
SettingsFragmentView fragment = getFragment();
|
||||
|
||||
if (fragment != null)
|
||||
{
|
||||
fragment.loadDefaultSettings();
|
||||
}
|
||||
}
|
||||
if (fragment != null) {
|
||||
fragment.loadDefaultSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showToastMessage(String message)
|
||||
{
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
@Override
|
||||
public void showToastMessage(String message) {
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void popBackStack()
|
||||
{
|
||||
getSupportFragmentManager().popBackStackImmediate();
|
||||
}
|
||||
@Override
|
||||
public void popBackStack() {
|
||||
getSupportFragmentManager().popBackStackImmediate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettingChanged()
|
||||
{
|
||||
mPresenter.onSettingChanged();
|
||||
}
|
||||
@Override
|
||||
public void onSettingChanged() {
|
||||
mPresenter.onSettingChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGcPadSettingChanged(String key, int value)
|
||||
{
|
||||
mPresenter.onGcPadSettingChanged(key, value);
|
||||
}
|
||||
@Override
|
||||
public void onGcPadSettingChanged(String key, int value) {
|
||||
mPresenter.onGcPadSettingChanged(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWiimoteSettingChanged(String section, int value)
|
||||
{
|
||||
mPresenter.onWiimoteSettingChanged(section, value);
|
||||
}
|
||||
@Override
|
||||
public void onWiimoteSettingChanged(String section, int value) {
|
||||
mPresenter.onWiimoteSettingChanged(section, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExtensionSettingChanged(String key, int value)
|
||||
{
|
||||
mPresenter.onExtensionSettingChanged(key, value);
|
||||
}
|
||||
@Override
|
||||
public void onExtensionSettingChanged(String key, int value) {
|
||||
mPresenter.onExtensionSettingChanged(key, value);
|
||||
}
|
||||
|
||||
private SettingsFragment getFragment()
|
||||
{
|
||||
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||
}
|
||||
private SettingsFragment getFragment() {
|
||||
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.citra.citra_android.NativeLibrary;
|
||||
import org.citra.citra_android.R;
|
||||
import org.citra.citra_android.model.settings.SettingSection;
|
||||
import org.citra.citra_android.services.DirectoryInitializationService;
|
||||
@ -17,204 +16,167 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public final class SettingsActivityPresenter
|
||||
{
|
||||
private static final String KEY_SHOULD_SAVE = "should_save";
|
||||
public final class SettingsActivityPresenter {
|
||||
private static final String KEY_SHOULD_SAVE = "should_save";
|
||||
|
||||
private SettingsActivityView mView;
|
||||
private SettingsActivityView mView;
|
||||
|
||||
private ArrayList<HashMap<String, SettingSection>> mSettings = new ArrayList<>();
|
||||
private ArrayList<HashMap<String, SettingSection>> mSettings = new ArrayList<>();
|
||||
|
||||
private int mStackCount;
|
||||
private int mStackCount;
|
||||
|
||||
private boolean mShouldSave;
|
||||
private boolean mShouldSave;
|
||||
|
||||
private DirectoryStateReceiver directoryStateReceiver;
|
||||
private DirectoryStateReceiver directoryStateReceiver;
|
||||
|
||||
private String menuTag;
|
||||
private String gameId;
|
||||
private String menuTag;
|
||||
private String gameId;
|
||||
|
||||
public SettingsActivityPresenter(SettingsActivityView view)
|
||||
{
|
||||
mView = view;
|
||||
}
|
||||
public SettingsActivityPresenter(SettingsActivityView view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
public void onCreate(Bundle savedInstanceState, String menuTag, String gameId)
|
||||
{
|
||||
if (savedInstanceState == null)
|
||||
{
|
||||
this.menuTag = menuTag;
|
||||
this.gameId = gameId;
|
||||
}
|
||||
else
|
||||
{
|
||||
mShouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
|
||||
}
|
||||
}
|
||||
public void onCreate(Bundle savedInstanceState, String menuTag, String gameId) {
|
||||
if (savedInstanceState == null) {
|
||||
this.menuTag = menuTag;
|
||||
this.gameId = gameId;
|
||||
} else {
|
||||
mShouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
|
||||
}
|
||||
}
|
||||
|
||||
public void onStart()
|
||||
{
|
||||
prepareDolphinDirectoriesIfNeeded();
|
||||
}
|
||||
public void onStart() {
|
||||
prepareDolphinDirectoriesIfNeeded();
|
||||
}
|
||||
|
||||
void loadSettingsUI()
|
||||
{
|
||||
if (mSettings.isEmpty())
|
||||
{
|
||||
if (!TextUtils.isEmpty(gameId))
|
||||
{
|
||||
mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile("../GameSettings/" + gameId, mView));
|
||||
}
|
||||
else
|
||||
{
|
||||
mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile(SettingsFile.FILE_NAME_CONFIG, mView));
|
||||
}
|
||||
}
|
||||
void loadSettingsUI() {
|
||||
if (mSettings.isEmpty()) {
|
||||
if (!TextUtils.isEmpty(gameId)) {
|
||||
mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile("../GameSettings/" + gameId, mView));
|
||||
} else {
|
||||
mSettings.add(SettingsFile.SETTINGS_DOLPHIN, SettingsFile.readFile(SettingsFile.FILE_NAME_CONFIG, mView));
|
||||
}
|
||||
}
|
||||
|
||||
mView.showSettingsFragment(menuTag, false, gameId);
|
||||
mView.onSettingsFileLoaded(mSettings);
|
||||
}
|
||||
mView.showSettingsFragment(menuTag, false, gameId);
|
||||
mView.onSettingsFileLoaded(mSettings);
|
||||
}
|
||||
|
||||
private void prepareDolphinDirectoriesIfNeeded()
|
||||
{
|
||||
File configFile = new File(DirectoryInitializationService.getUserDirectory() + "/config/"+SettingsFile.FILE_NAME_CONFIG + ".ini");
|
||||
if(!configFile.exists()) {
|
||||
private void prepareDolphinDirectoriesIfNeeded() {
|
||||
File configFile = new File(DirectoryInitializationService.getUserDirectory() + "/config/" + SettingsFile.FILE_NAME_CONFIG + ".ini");
|
||||
if (!configFile.exists()) {
|
||||
|
||||
}
|
||||
if (DirectoryInitializationService.areDolphinDirectoriesReady()) {
|
||||
loadSettingsUI();
|
||||
} else {
|
||||
mView.showLoading();
|
||||
IntentFilter statusIntentFilter = new IntentFilter(
|
||||
DirectoryInitializationService.BROADCAST_ACTION);
|
||||
}
|
||||
if (DirectoryInitializationService.areDolphinDirectoriesReady()) {
|
||||
loadSettingsUI();
|
||||
} else {
|
||||
mView.showLoading();
|
||||
IntentFilter statusIntentFilter = new IntentFilter(
|
||||
DirectoryInitializationService.BROADCAST_ACTION);
|
||||
|
||||
directoryStateReceiver =
|
||||
new DirectoryStateReceiver(directoryInitializationState ->
|
||||
{
|
||||
if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
||||
{
|
||||
mView.hideLoading();
|
||||
loadSettingsUI();
|
||||
}
|
||||
else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
||||
{
|
||||
mView.showPermissionNeededHint();
|
||||
mView.hideLoading();
|
||||
}
|
||||
else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
|
||||
{
|
||||
mView.showExternalStorageNotMountedHint();
|
||||
mView.hideLoading();
|
||||
}
|
||||
});
|
||||
directoryStateReceiver =
|
||||
new DirectoryStateReceiver(directoryInitializationState ->
|
||||
{
|
||||
if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED) {
|
||||
mView.hideLoading();
|
||||
loadSettingsUI();
|
||||
} else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED) {
|
||||
mView.showPermissionNeededHint();
|
||||
mView.hideLoading();
|
||||
} else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE) {
|
||||
mView.showExternalStorageNotMountedHint();
|
||||
mView.hideLoading();
|
||||
}
|
||||
});
|
||||
|
||||
mView.startDirectoryInitializationService(directoryStateReceiver, statusIntentFilter);
|
||||
}
|
||||
}
|
||||
mView.startDirectoryInitializationService(directoryStateReceiver, statusIntentFilter);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings)
|
||||
{
|
||||
mSettings = settings;
|
||||
}
|
||||
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) {
|
||||
mSettings = settings;
|
||||
}
|
||||
|
||||
public HashMap<String, SettingSection> getSettings(int file)
|
||||
{
|
||||
return mSettings.get(file);
|
||||
}
|
||||
public HashMap<String, SettingSection> getSettings(int file) {
|
||||
return mSettings.get(file);
|
||||
}
|
||||
|
||||
public void onStop(boolean finishing)
|
||||
{
|
||||
if (directoryStateReceiver != null)
|
||||
{
|
||||
mView.stopListeningToDirectoryInitializationService(directoryStateReceiver);
|
||||
directoryStateReceiver = null;
|
||||
}
|
||||
public void onStop(boolean finishing) {
|
||||
if (directoryStateReceiver != null) {
|
||||
mView.stopListeningToDirectoryInitializationService(directoryStateReceiver);
|
||||
directoryStateReceiver = null;
|
||||
}
|
||||
|
||||
if (mSettings != null && finishing && mShouldSave)
|
||||
{
|
||||
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);
|
||||
}
|
||||
mView.showToastMessage("Saved settings for " + gameId);
|
||||
} else {
|
||||
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
|
||||
SettingsFile.saveFile(SettingsFile.FILE_NAME_CONFIG, mSettings.get(SettingsFile.SETTINGS_DOLPHIN), mView);
|
||||
mView.showToastMessage("Saved settings to INI files");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mSettings != null && finishing && mShouldSave) {
|
||||
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);
|
||||
}
|
||||
mView.showToastMessage("Saved settings for " + gameId);
|
||||
} else {
|
||||
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
|
||||
SettingsFile.saveFile(SettingsFile.FILE_NAME_CONFIG, mSettings.get(SettingsFile.SETTINGS_DOLPHIN), mView);
|
||||
mView.showToastMessage("Saved settings to INI files");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addToStack()
|
||||
{
|
||||
mStackCount++;
|
||||
}
|
||||
public void addToStack() {
|
||||
mStackCount++;
|
||||
}
|
||||
|
||||
public void onBackPressed()
|
||||
{
|
||||
if (mStackCount > 0)
|
||||
{
|
||||
mView.popBackStack();
|
||||
mStackCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
mView.finish();
|
||||
}
|
||||
}
|
||||
public void onBackPressed() {
|
||||
if (mStackCount > 0) {
|
||||
mView.popBackStack();
|
||||
mStackCount--;
|
||||
} else {
|
||||
mView.finish();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean handleOptionsItem(int itemId)
|
||||
{
|
||||
switch (itemId)
|
||||
{
|
||||
case R.id.menu_save_exit:
|
||||
mView.finish();
|
||||
return true;
|
||||
}
|
||||
public boolean handleOptionsItem(int itemId) {
|
||||
switch (itemId) {
|
||||
case R.id.menu_save_exit:
|
||||
mView.finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onSettingChanged()
|
||||
{
|
||||
mShouldSave = true;
|
||||
}
|
||||
public void onSettingChanged() {
|
||||
mShouldSave = true;
|
||||
}
|
||||
|
||||
public void saveState(Bundle outState)
|
||||
{
|
||||
outState.putBoolean(KEY_SHOULD_SAVE, mShouldSave);
|
||||
}
|
||||
public void saveState(Bundle outState) {
|
||||
outState.putBoolean(KEY_SHOULD_SAVE, mShouldSave);
|
||||
}
|
||||
|
||||
public void onGcPadSettingChanged(String key, int value)
|
||||
{
|
||||
if (value != 0) // Not disabled
|
||||
{
|
||||
mView.showSettingsFragment(key + (value / 6), true, gameId);
|
||||
}
|
||||
}
|
||||
public void onGcPadSettingChanged(String key, int value) {
|
||||
if (value != 0) // Not disabled
|
||||
{
|
||||
mView.showSettingsFragment(key + (value / 6), true, gameId);
|
||||
}
|
||||
}
|
||||
|
||||
public void onWiimoteSettingChanged(String section, int value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 1:
|
||||
mView.showSettingsFragment(section, true, gameId);
|
||||
break;
|
||||
public void onWiimoteSettingChanged(String section, int value) {
|
||||
switch (value) {
|
||||
case 1:
|
||||
mView.showSettingsFragment(section, true, gameId);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
mView.showToastMessage("Please make sure Continuous Scanning is enabled in Core Settings.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
mView.showToastMessage("Please make sure Continuous Scanning is enabled in Core Settings.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void onExtensionSettingChanged(String key, int value)
|
||||
{
|
||||
if (value != 0) // None
|
||||
{
|
||||
mView.showSettingsFragment(key + value, true, gameId);
|
||||
}
|
||||
}
|
||||
public void onExtensionSettingChanged(String key, int value) {
|
||||
if (value != 0) // None
|
||||
{
|
||||
mView.showSettingsFragment(key + value, true, gameId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,130 +11,129 @@ import java.util.HashMap;
|
||||
/**
|
||||
* Abstraction for the Activity that manages SettingsFragments.
|
||||
*/
|
||||
public interface SettingsActivityView
|
||||
{
|
||||
/**
|
||||
* Show a new SettingsFragment.
|
||||
*
|
||||
* @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, String gameId);
|
||||
public interface SettingsActivityView {
|
||||
/**
|
||||
* Show a new SettingsFragment.
|
||||
*
|
||||
* @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, String gameId);
|
||||
|
||||
/**
|
||||
* Called by a contained Fragment to get access to the Setting HashMap
|
||||
* loaded from disk, so that each Fragment doesn't need to perform its own
|
||||
* read operation.
|
||||
*
|
||||
* @param file The settings file to load.
|
||||
* @return A possibly null HashMap of Settings.
|
||||
*/
|
||||
HashMap<String, SettingSection> getSettings(int file);
|
||||
/**
|
||||
* Called by a contained Fragment to get access to the Setting HashMap
|
||||
* loaded from disk, so that each Fragment doesn't need to perform its own
|
||||
* read operation.
|
||||
*
|
||||
* @param file The settings file to load.
|
||||
* @return A possibly null HashMap of Settings.
|
||||
*/
|
||||
HashMap<String, SettingSection> getSettings(int file);
|
||||
|
||||
/**
|
||||
* Used to provide the Activity with Settings HashMaps if a Fragment already
|
||||
* has one; for example, if a rotation occurs, the Fragment will not be killed,
|
||||
* but the Activity will, so the Activity needs to have its HashMaps resupplied.
|
||||
*
|
||||
* @param settings The ArrayList of all the Settings HashMaps.
|
||||
*/
|
||||
void setSettings(ArrayList<HashMap<String, SettingSection>> settings);
|
||||
/**
|
||||
* Used to provide the Activity with Settings HashMaps if a Fragment already
|
||||
* has one; for example, if a rotation occurs, the Fragment will not be killed,
|
||||
* but the Activity will, so the Activity needs to have its HashMaps resupplied.
|
||||
*
|
||||
* @param settings The ArrayList of all the Settings HashMaps.
|
||||
*/
|
||||
void setSettings(ArrayList<HashMap<String, SettingSection>> settings);
|
||||
|
||||
/**
|
||||
* Called when an asynchronous load operation completes.
|
||||
*
|
||||
* @param settings The (possibly null) result of the ini load operation.
|
||||
*/
|
||||
void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings);
|
||||
/**
|
||||
* Called when an asynchronous load operation completes.
|
||||
*
|
||||
* @param settings The (possibly null) result of the ini load operation.
|
||||
*/
|
||||
void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings);
|
||||
|
||||
/**
|
||||
* Called when an asynchronous load operation fails.
|
||||
*/
|
||||
void onSettingsFileNotFound();
|
||||
/**
|
||||
* Called when an asynchronous load operation fails.
|
||||
*/
|
||||
void onSettingsFileNotFound();
|
||||
|
||||
/**
|
||||
* Display a popup text message on screen.
|
||||
*
|
||||
* @param message The contents of the onscreen message.
|
||||
*/
|
||||
void showToastMessage(String message);
|
||||
/**
|
||||
* Display a popup text message on screen.
|
||||
*
|
||||
* @param message The contents of the onscreen message.
|
||||
*/
|
||||
void showToastMessage(String message);
|
||||
|
||||
/**
|
||||
* Show the previous fragment.
|
||||
*/
|
||||
void popBackStack();
|
||||
/**
|
||||
* Show the previous fragment.
|
||||
*/
|
||||
void popBackStack();
|
||||
|
||||
/**
|
||||
* End the activity.
|
||||
*/
|
||||
void finish();
|
||||
/**
|
||||
* End the activity.
|
||||
*/
|
||||
void finish();
|
||||
|
||||
/**
|
||||
* Called by a containing Fragment to tell the Activity that a setting was changed;
|
||||
* unless this has been called, the Activity will not save to disk.
|
||||
*/
|
||||
void onSettingChanged();
|
||||
/**
|
||||
* Called by a containing Fragment to tell the Activity that a setting was changed;
|
||||
* unless this has been called, the Activity will not save to disk.
|
||||
*/
|
||||
void onSettingChanged();
|
||||
|
||||
/**
|
||||
* Called by a containing Fragment to tell the containing Activity that a GCPad's setting
|
||||
* was modified.
|
||||
*
|
||||
* @param key Identifier for the GCPad that was modified.
|
||||
* @param value New setting for the GCPad.
|
||||
*/
|
||||
void onGcPadSettingChanged(String key, int value);
|
||||
/**
|
||||
* Called by a containing Fragment to tell the containing Activity that a GCPad's setting
|
||||
* was modified.
|
||||
*
|
||||
* @param key Identifier for the GCPad that was modified.
|
||||
* @param value New setting for the GCPad.
|
||||
*/
|
||||
void onGcPadSettingChanged(String key, int value);
|
||||
|
||||
/**
|
||||
* Called by a containing Fragment to tell the containing Activity that a Wiimote's setting
|
||||
* was modified.
|
||||
*
|
||||
* @param section Identifier for Wiimote that was modified; Wiimotes are identified by their section,
|
||||
* not their key.
|
||||
* @param value New setting for the Wiimote.
|
||||
*/
|
||||
void onWiimoteSettingChanged(String section, int value);
|
||||
/**
|
||||
* Called by a containing Fragment to tell the containing Activity that a Wiimote's setting
|
||||
* was modified.
|
||||
*
|
||||
* @param section Identifier for Wiimote that was modified; Wiimotes are identified by their section,
|
||||
* not their key.
|
||||
* @param value New setting for the Wiimote.
|
||||
*/
|
||||
void onWiimoteSettingChanged(String section, int value);
|
||||
|
||||
/**
|
||||
* Called by a containing Fragment to tell the containing Activity that an extension setting
|
||||
* was modified.
|
||||
*
|
||||
* @param key Identifier for the extension that was modified.
|
||||
* @param value New setting for the extension.
|
||||
*/
|
||||
void onExtensionSettingChanged(String key, int value);
|
||||
/**
|
||||
* Called by a containing Fragment to tell the containing Activity that an extension setting
|
||||
* was modified.
|
||||
*
|
||||
* @param key Identifier for the extension that was modified.
|
||||
* @param value New setting for the extension.
|
||||
*/
|
||||
void onExtensionSettingChanged(String key, int value);
|
||||
|
||||
/**
|
||||
* Show loading dialog while loading the settings
|
||||
*/
|
||||
void showLoading();
|
||||
/**
|
||||
* Show loading dialog while loading the settings
|
||||
*/
|
||||
void showLoading();
|
||||
|
||||
/**
|
||||
* Hide the loading the dialog
|
||||
*/
|
||||
void hideLoading();
|
||||
/**
|
||||
* Hide the loading the dialog
|
||||
*/
|
||||
void hideLoading();
|
||||
|
||||
/**
|
||||
* Show a hint to the user that the app needs write to external storage access
|
||||
*/
|
||||
void showPermissionNeededHint();
|
||||
/**
|
||||
* Show a hint to the user that the app needs write to external storage access
|
||||
*/
|
||||
void showPermissionNeededHint();
|
||||
|
||||
/**
|
||||
* Show a hint to the user that the app needs the external storage to be mounted
|
||||
*/
|
||||
void showExternalStorageNotMountedHint();
|
||||
/**
|
||||
* Show a hint to the user that the app needs the external storage to be mounted
|
||||
*/
|
||||
void showExternalStorageNotMountedHint();
|
||||
|
||||
/**
|
||||
* Start the DirectoryInitializationService and listen for the result.
|
||||
*
|
||||
* @param receiver the broadcast receiver for the DirectoryInitializationService
|
||||
* @param filter the Intent broadcasts to be received.
|
||||
*/
|
||||
void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter);
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* Stop listening to the DirectoryInitializationService.
|
||||
*
|
||||
* @param receiver The broadcast receiver to unregister.
|
||||
*/
|
||||
void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver);
|
||||
}
|
||||
|
@ -40,140 +40,125 @@ import org.citra.citra_android.utils.SettingsFile;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
|
||||
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener
|
||||
{
|
||||
private SettingsFragmentView mView;
|
||||
private Context mContext;
|
||||
private ArrayList<SettingsItem> mSettings;
|
||||
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener {
|
||||
private SettingsFragmentView mView;
|
||||
private Context mContext;
|
||||
private ArrayList<SettingsItem> mSettings;
|
||||
|
||||
private SettingsItem mClickedItem;
|
||||
private int mSeekbarProgress;
|
||||
private SettingsItem mClickedItem;
|
||||
private int mSeekbarProgress;
|
||||
|
||||
private AlertDialog mDialog;
|
||||
private TextView mTextSliderValue;
|
||||
private AlertDialog mDialog;
|
||||
private TextView mTextSliderValue;
|
||||
|
||||
public SettingsAdapter(SettingsFragmentView view, Context context)
|
||||
{
|
||||
mView = view;
|
||||
mContext = context;
|
||||
}
|
||||
public SettingsAdapter(SettingsFragmentView view, Context context) {
|
||||
mView = view;
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
|
||||
{
|
||||
View view;
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
@Override
|
||||
public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view;
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
|
||||
switch (viewType)
|
||||
{
|
||||
case SettingsItem.TYPE_HEADER:
|
||||
view = inflater.inflate(R.layout.list_item_settings_header, parent, false);
|
||||
return new HeaderViewHolder(view, this);
|
||||
switch (viewType) {
|
||||
case SettingsItem.TYPE_HEADER:
|
||||
view = inflater.inflate(R.layout.list_item_settings_header, parent, false);
|
||||
return new HeaderViewHolder(view, this);
|
||||
|
||||
case SettingsItem.TYPE_CHECKBOX:
|
||||
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false);
|
||||
return new CheckBoxSettingViewHolder(view, this);
|
||||
case SettingsItem.TYPE_CHECKBOX:
|
||||
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false);
|
||||
return new CheckBoxSettingViewHolder(view, this);
|
||||
|
||||
case SettingsItem.TYPE_SINGLE_CHOICE:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new SingleChoiceViewHolder(view, this);
|
||||
case SettingsItem.TYPE_SINGLE_CHOICE:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new SingleChoiceViewHolder(view, this);
|
||||
|
||||
case SettingsItem.TYPE_SLIDER:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new SliderViewHolder(view, this);
|
||||
case SettingsItem.TYPE_SLIDER:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new SliderViewHolder(view, this);
|
||||
|
||||
case SettingsItem.TYPE_SUBMENU:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new SubmenuViewHolder(view, this);
|
||||
case SettingsItem.TYPE_SUBMENU:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new SubmenuViewHolder(view, this);
|
||||
|
||||
case SettingsItem.TYPE_INPUT_BINDING:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new InputBindingSettingViewHolder(view, this, mContext);
|
||||
case SettingsItem.TYPE_INPUT_BINDING:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new InputBindingSettingViewHolder(view, this, mContext);
|
||||
|
||||
case SettingsItem.TYPE_DATETIME_SETTING:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new DateTimeViewHolder(view, this);
|
||||
case SettingsItem.TYPE_DATETIME_SETTING:
|
||||
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||
return new DateTimeViewHolder(view, this);
|
||||
|
||||
|
||||
default:
|
||||
Log.error("[SettingsAdapter] Invalid view type: " + viewType);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
default:
|
||||
Log.error("[SettingsAdapter] Invalid view type: " + viewType);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(SettingViewHolder holder, int position)
|
||||
{
|
||||
holder.bind(getItem(position));
|
||||
}
|
||||
@Override
|
||||
public void onBindViewHolder(SettingViewHolder holder, int position) {
|
||||
holder.bind(getItem(position));
|
||||
}
|
||||
|
||||
private SettingsItem getItem(int position)
|
||||
{
|
||||
return mSettings.get(position);
|
||||
}
|
||||
private SettingsItem getItem(int position) {
|
||||
return mSettings.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount()
|
||||
{
|
||||
if (mSettings != null)
|
||||
{
|
||||
return mSettings.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (mSettings != null) {
|
||||
return mSettings.size();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position)
|
||||
{
|
||||
return getItem(position).getType();
|
||||
}
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
return getItem(position).getType();
|
||||
}
|
||||
|
||||
public void setSettings(ArrayList<SettingsItem> settings)
|
||||
{
|
||||
mSettings = settings;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
public void setSettings(ArrayList<SettingsItem> settings) {
|
||||
mSettings = settings;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void onBooleanClick(CheckBoxSetting item, int position, boolean checked)
|
||||
{
|
||||
IntSetting setting = item.setChecked(checked);
|
||||
notifyItemChanged(position);
|
||||
public void onBooleanClick(CheckBoxSetting item, int position, boolean checked) {
|
||||
IntSetting setting = item.setChecked(checked);
|
||||
notifyItemChanged(position);
|
||||
|
||||
if (setting != null)
|
||||
{
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
if (setting != null) {
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
|
||||
mView.onSettingChanged();
|
||||
}
|
||||
mView.onSettingChanged();
|
||||
}
|
||||
|
||||
public void onSingleChoiceClick(SingleChoiceSetting item)
|
||||
{
|
||||
mClickedItem = item;
|
||||
public void onSingleChoiceClick(SingleChoiceSetting item) {
|
||||
mClickedItem = item;
|
||||
|
||||
int value = getSelectionForSingleChoiceValue(item);
|
||||
int value = getSelectionForSingleChoiceValue(item);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
|
||||
|
||||
builder.setTitle(item.getNameId());
|
||||
builder.setSingleChoiceItems(item.getChoicesId(), value, this);
|
||||
builder.setTitle(item.getNameId());
|
||||
builder.setSingleChoiceItems(item.getChoicesId(), value, this);
|
||||
|
||||
mDialog = builder.show();
|
||||
}
|
||||
mDialog = builder.show();
|
||||
}
|
||||
|
||||
public void onDateTimeClick(DateTimeSetting item){
|
||||
mClickedItem = item;
|
||||
public void onDateTimeClick(DateTimeSetting item) {
|
||||
mClickedItem = item;
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
|
||||
View view = inflater.inflate(R.layout.sysclock_datetime_picker, null);
|
||||
LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
|
||||
View view = inflater.inflate(R.layout.sysclock_datetime_picker, null);
|
||||
|
||||
DatePicker dp = (DatePicker) view.findViewById(R.id.date_picker);
|
||||
TimePicker tp = (TimePicker) view.findViewById(R.id.time_picker);
|
||||
DatePicker dp = view.findViewById(R.id.date_picker);
|
||||
TimePicker tp = view.findViewById(R.id.time_picker);
|
||||
|
||||
//set date and time to substrings of settingValue; format = 2018-12-24 04:20:69 (alright maybe not that 69)
|
||||
String settingValue = item.getValue();
|
||||
@ -188,7 +173,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
//set it
|
||||
int year = dp.getYear();
|
||||
if (year < 2000){
|
||||
if (year < 2000) {
|
||||
year = 2000;
|
||||
}
|
||||
String month = ("00" + (dp.getMonth() + 1)).substring(String.valueOf(dp.getMonth() + 1).length());
|
||||
@ -203,200 +188,169 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
|
||||
closeDialog();
|
||||
}
|
||||
};
|
||||
DialogInterface.OnClickListener cancel = new DialogInterface.OnClickListener() {
|
||||
DialogInterface.OnClickListener cancel = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
closeDialog();
|
||||
}
|
||||
};
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton("Set", ok);
|
||||
builder.setNegativeButton("Cancel", cancel);
|
||||
mDialog = builder.show();
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton("Set", ok);
|
||||
builder.setNegativeButton("Cancel", cancel);
|
||||
mDialog = builder.show();
|
||||
}
|
||||
public void onSliderClick(SliderSetting item)
|
||||
{
|
||||
mClickedItem = item;
|
||||
mSeekbarProgress = item.getSelectedValue();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
|
||||
|
||||
LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
|
||||
View view = inflater.inflate(R.layout.dialog_seekbar, null);
|
||||
public void onSliderClick(SliderSetting item) {
|
||||
mClickedItem = item;
|
||||
mSeekbarProgress = item.getSelectedValue();
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
|
||||
|
||||
builder.setTitle(item.getNameId());
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton(R.string.ok, this);
|
||||
builder.setNegativeButton(R.string.cancel, this);
|
||||
mDialog = builder.show();
|
||||
LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
|
||||
View view = inflater.inflate(R.layout.dialog_seekbar, null);
|
||||
|
||||
mTextSliderValue = view.findViewById(R.id.text_value);
|
||||
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
|
||||
builder.setTitle(item.getNameId());
|
||||
builder.setView(view);
|
||||
builder.setPositiveButton(R.string.ok, this);
|
||||
builder.setNegativeButton(R.string.cancel, this);
|
||||
mDialog = builder.show();
|
||||
|
||||
TextView units = view.findViewById(R.id.text_units);
|
||||
units.setText(item.getUnits());
|
||||
mTextSliderValue = view.findViewById(R.id.text_value);
|
||||
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
|
||||
|
||||
SeekBar seekbar = view.findViewById(R.id.seekbar);
|
||||
TextView units = view.findViewById(R.id.text_units);
|
||||
units.setText(item.getUnits());
|
||||
|
||||
seekbar.setMax(item.getMax());
|
||||
seekbar.setProgress(mSeekbarProgress);
|
||||
SeekBar seekbar = view.findViewById(R.id.seekbar);
|
||||
|
||||
seekbar.setOnSeekBarChangeListener(this);
|
||||
}
|
||||
seekbar.setMax(item.getMax());
|
||||
seekbar.setProgress(mSeekbarProgress);
|
||||
|
||||
public void onSubmenuClick(SubmenuSetting item)
|
||||
{
|
||||
mView.loadSubMenu(item.getMenuKey());
|
||||
}
|
||||
seekbar.setOnSeekBarChangeListener(this);
|
||||
}
|
||||
|
||||
public void onInputBindingClick(final InputBindingSetting item, final int position)
|
||||
{
|
||||
final MotionAlertDialog dialog = new MotionAlertDialog(mContext, item);
|
||||
dialog.setTitle(R.string.input_binding);
|
||||
dialog.setMessage(String.format(mContext.getString(R.string.input_binding_descrip), mContext.getString(item.getNameId())));
|
||||
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), this);
|
||||
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, mContext.getString(R.string.clear), (dialogInterface, i) ->
|
||||
{
|
||||
item.setValue("");
|
||||
public void onSubmenuClick(SubmenuSetting item) {
|
||||
mView.loadSubMenu(item.getMenuKey());
|
||||
}
|
||||
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.remove(item.getKey());
|
||||
editor.apply();
|
||||
});
|
||||
dialog.setOnDismissListener(dialog1 ->
|
||||
{
|
||||
StringSetting setting = new StringSetting(item.getKey(), item.getSection(), item.getFile(), item.getValue());
|
||||
notifyItemChanged(position);
|
||||
public void onInputBindingClick(final InputBindingSetting item, final int position) {
|
||||
final MotionAlertDialog dialog = new MotionAlertDialog(mContext, item);
|
||||
dialog.setTitle(R.string.input_binding);
|
||||
dialog.setMessage(String.format(mContext.getString(R.string.input_binding_descrip), mContext.getString(item.getNameId())));
|
||||
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), this);
|
||||
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, mContext.getString(R.string.clear), (dialogInterface, i) ->
|
||||
{
|
||||
item.setValue("");
|
||||
|
||||
if (setting != null)
|
||||
{
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.remove(item.getKey());
|
||||
editor.apply();
|
||||
});
|
||||
dialog.setOnDismissListener(dialog1 ->
|
||||
{
|
||||
StringSetting setting = new StringSetting(item.getKey(), item.getSection(), item.getFile(), item.getValue());
|
||||
notifyItemChanged(position);
|
||||
|
||||
mView.onSettingChanged();
|
||||
});
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
dialog.show();
|
||||
}
|
||||
if (setting != null) {
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
if (mClickedItem instanceof SingleChoiceSetting)
|
||||
{
|
||||
SingleChoiceSetting scSetting = (SingleChoiceSetting) mClickedItem;
|
||||
mView.onSettingChanged();
|
||||
});
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
int value = getValueForSingleChoiceSelection(scSetting, which);
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (mClickedItem instanceof SingleChoiceSetting) {
|
||||
SingleChoiceSetting scSetting = (SingleChoiceSetting) mClickedItem;
|
||||
|
||||
// Get the backing Setting, which may be null (if for example it was missing from the file)
|
||||
IntSetting setting = scSetting.setSelectedValue(value);
|
||||
if (setting != null)
|
||||
{
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
int value = getValueForSingleChoiceSelection(scSetting, which);
|
||||
|
||||
closeDialog();
|
||||
}
|
||||
else if (mClickedItem instanceof SliderSetting)
|
||||
{
|
||||
SliderSetting sliderSetting = (SliderSetting) mClickedItem;
|
||||
if (sliderSetting.getSetting() instanceof FloatSetting)
|
||||
{
|
||||
float value;
|
||||
// Get the backing Setting, which may be null (if for example it was missing from the file)
|
||||
IntSetting setting = scSetting.setSelectedValue(value);
|
||||
if (setting != null) {
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
|
||||
if (sliderSetting.getKey().equals(SettingsFile.KEY_FRAME_LIMIT))
|
||||
{
|
||||
value = mSeekbarProgress / 100.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = (float) mSeekbarProgress;
|
||||
}
|
||||
closeDialog();
|
||||
} else if (mClickedItem instanceof SliderSetting) {
|
||||
SliderSetting sliderSetting = (SliderSetting) mClickedItem;
|
||||
if (sliderSetting.getSetting() instanceof FloatSetting) {
|
||||
float value;
|
||||
|
||||
FloatSetting setting = sliderSetting.setSelectedValue(value);
|
||||
if (setting != null)
|
||||
{
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress);
|
||||
if (setting != null)
|
||||
{
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sliderSetting.getKey().equals(SettingsFile.KEY_FRAME_LIMIT)) {
|
||||
value = mSeekbarProgress / 100.0f;
|
||||
} else {
|
||||
value = (float) mSeekbarProgress;
|
||||
}
|
||||
|
||||
mView.onSettingChanged();
|
||||
mClickedItem = null;
|
||||
mSeekbarProgress = -1;
|
||||
}
|
||||
FloatSetting setting = sliderSetting.setSelectedValue(value);
|
||||
if (setting != null) {
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
} else {
|
||||
IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress);
|
||||
if (setting != null) {
|
||||
mView.putSetting(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void closeDialog()
|
||||
{
|
||||
if (mDialog != null)
|
||||
{
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
}
|
||||
}
|
||||
mView.onSettingChanged();
|
||||
mClickedItem = null;
|
||||
mSeekbarProgress = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
|
||||
{
|
||||
mSeekbarProgress = progress;
|
||||
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
|
||||
}
|
||||
public void closeDialog() {
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar)
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
mSeekbarProgress = progress;
|
||||
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar)
|
||||
{
|
||||
}
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which)
|
||||
{
|
||||
int valuesId = item.getValuesId();
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
}
|
||||
|
||||
if (valuesId > 0)
|
||||
{
|
||||
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
|
||||
return valuesArray[which];
|
||||
}
|
||||
else
|
||||
{
|
||||
return which;
|
||||
}
|
||||
}
|
||||
private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which) {
|
||||
int valuesId = item.getValuesId();
|
||||
|
||||
private int getSelectionForSingleChoiceValue(SingleChoiceSetting item)
|
||||
{
|
||||
int value = item.getSelectedValue();
|
||||
int valuesId = item.getValuesId();
|
||||
if (valuesId > 0) {
|
||||
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
|
||||
return valuesArray[which];
|
||||
} else {
|
||||
return which;
|
||||
}
|
||||
}
|
||||
|
||||
if (valuesId > 0)
|
||||
{
|
||||
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
|
||||
for (int index = 0; index < valuesArray.length; index++)
|
||||
{
|
||||
int current = valuesArray[index];
|
||||
if (current == value)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
private int getSelectionForSingleChoiceValue(SingleChoiceSetting item) {
|
||||
int value = item.getSelectedValue();
|
||||
int valuesId = item.getValuesId();
|
||||
|
||||
return -1;
|
||||
}
|
||||
if (valuesId > 0) {
|
||||
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
|
||||
for (int index = 0; index < valuesArray.length; index++) {
|
||||
int current = valuesArray[index];
|
||||
if (current == value) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -21,169 +21,148 @@ import org.citra.citra_android.utils.SettingsFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public final class SettingsFragment extends Fragment implements SettingsFragmentView
|
||||
{
|
||||
private static final String ARGUMENT_MENU_TAG = "menu_tag";
|
||||
private static final String ARGUMENT_GAME_ID = "game_id";
|
||||
public final class SettingsFragment extends Fragment implements SettingsFragmentView {
|
||||
private static final String ARGUMENT_MENU_TAG = "menu_tag";
|
||||
private static final String ARGUMENT_GAME_ID = "game_id";
|
||||
|
||||
private SettingsFragmentPresenter mPresenter = new SettingsFragmentPresenter(this);
|
||||
private SettingsActivityView mActivity;
|
||||
private SettingsFragmentPresenter mPresenter = new SettingsFragmentPresenter(this);
|
||||
private SettingsActivityView mActivity;
|
||||
|
||||
private SettingsAdapter mAdapter;
|
||||
private SettingsAdapter mAdapter;
|
||||
|
||||
public static Fragment newInstance(String menuTag, String gameId)
|
||||
{
|
||||
SettingsFragment fragment = new SettingsFragment();
|
||||
public static Fragment newInstance(String menuTag, String gameId) {
|
||||
SettingsFragment fragment = new SettingsFragment();
|
||||
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putString(ARGUMENT_MENU_TAG, menuTag);
|
||||
arguments.putString(ARGUMENT_GAME_ID, gameId);
|
||||
Bundle arguments = new Bundle();
|
||||
arguments.putString(ARGUMENT_MENU_TAG, menuTag);
|
||||
arguments.putString(ARGUMENT_GAME_ID, gameId);
|
||||
|
||||
fragment.setArguments(arguments);
|
||||
return fragment;
|
||||
}
|
||||
fragment.setArguments(arguments);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context)
|
||||
{
|
||||
super.onAttach(context);
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
|
||||
mActivity = (SettingsActivityView) context;
|
||||
mPresenter.onAttach();
|
||||
}
|
||||
mActivity = (SettingsActivityView) context;
|
||||
mPresenter.onAttach();
|
||||
}
|
||||
|
||||
/**
|
||||
* This version of onAttach is needed for versions below Marshmallow.
|
||||
*
|
||||
* @param activity
|
||||
*/
|
||||
@Override
|
||||
public void onAttach(Activity activity)
|
||||
{
|
||||
super.onAttach(activity);
|
||||
/**
|
||||
* This version of onAttach is needed for versions below Marshmallow.
|
||||
*
|
||||
* @param activity
|
||||
*/
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
||||
mActivity = (SettingsActivityView) activity;
|
||||
mPresenter.onAttach();
|
||||
}
|
||||
mActivity = (SettingsActivityView) activity;
|
||||
mPresenter.onAttach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setRetainInstance(true);
|
||||
String menuTag = getArguments().getString(ARGUMENT_MENU_TAG);
|
||||
String gameId = getArguments().getString(ARGUMENT_GAME_ID);
|
||||
setRetainInstance(true);
|
||||
String menuTag = getArguments().getString(ARGUMENT_MENU_TAG);
|
||||
String gameId = getArguments().getString(ARGUMENT_GAME_ID);
|
||||
|
||||
mAdapter = new SettingsAdapter(this, getActivity());
|
||||
mAdapter = new SettingsAdapter(this, getActivity());
|
||||
|
||||
mPresenter.onCreate(menuTag, gameId);
|
||||
}
|
||||
mPresenter.onCreate(menuTag, gameId);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
return inflater.inflate(R.layout.fragment_settings, container, false);
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_settings, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
|
||||
{
|
||||
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
|
||||
|
||||
RecyclerView recyclerView = view.findViewById(R.id.list_settings);
|
||||
RecyclerView recyclerView = view.findViewById(R.id.list_settings);
|
||||
|
||||
recyclerView.setAdapter(mAdapter);
|
||||
recyclerView.setLayoutManager(manager);
|
||||
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
|
||||
recyclerView.setAdapter(mAdapter);
|
||||
recyclerView.setLayoutManager(manager);
|
||||
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
|
||||
|
||||
SettingsActivityView activity = (SettingsActivityView) getActivity();
|
||||
SettingsActivityView activity = (SettingsActivityView) getActivity();
|
||||
|
||||
ArrayList<HashMap<String, SettingSection>> settings = new ArrayList<>();
|
||||
settings.add(SettingsFile.SETTINGS_DOLPHIN, activity.getSettings(SettingsFile.SETTINGS_DOLPHIN));
|
||||
mPresenter.onViewCreated(settings);
|
||||
}
|
||||
ArrayList<HashMap<String, SettingSection>> settings = new ArrayList<>();
|
||||
settings.add(SettingsFile.SETTINGS_DOLPHIN, activity.getSettings(SettingsFile.SETTINGS_DOLPHIN));
|
||||
mPresenter.onViewCreated(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach()
|
||||
{
|
||||
super.onDetach();
|
||||
mActivity = null;
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mActivity = null;
|
||||
|
||||
if (mAdapter != null)
|
||||
{
|
||||
mAdapter.closeDialog();
|
||||
}
|
||||
}
|
||||
if (mAdapter != null) {
|
||||
mAdapter.closeDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings)
|
||||
{
|
||||
mPresenter.setSettings(settings);
|
||||
}
|
||||
@Override
|
||||
public void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings) {
|
||||
mPresenter.setSettings(settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void passSettingsToActivity(ArrayList<HashMap<String, SettingSection>> settings)
|
||||
{
|
||||
if (mActivity != null)
|
||||
{
|
||||
mActivity.setSettings(settings);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void passSettingsToActivity(ArrayList<HashMap<String, SettingSection>> settings) {
|
||||
if (mActivity != null) {
|
||||
mActivity.setSettings(settings);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showSettingsList(ArrayList<SettingsItem> settingsList)
|
||||
{
|
||||
mAdapter.setSettings(settingsList);
|
||||
}
|
||||
@Override
|
||||
public void showSettingsList(ArrayList<SettingsItem> settingsList) {
|
||||
mAdapter.setSettings(settingsList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadDefaultSettings()
|
||||
{
|
||||
mPresenter.loadDefaultSettings();
|
||||
}
|
||||
@Override
|
||||
public void loadDefaultSettings() {
|
||||
mPresenter.loadDefaultSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSubMenu(String menuKey)
|
||||
{
|
||||
mActivity.showSettingsFragment(menuKey, true, getArguments().getString(ARGUMENT_GAME_ID));
|
||||
}
|
||||
@Override
|
||||
public void loadSubMenu(String menuKey) {
|
||||
mActivity.showSettingsFragment(menuKey, true, getArguments().getString(ARGUMENT_GAME_ID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showToastMessage(String message)
|
||||
{
|
||||
mActivity.showToastMessage(message);
|
||||
}
|
||||
@Override
|
||||
public void showToastMessage(String message) {
|
||||
mActivity.showToastMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putSetting(Setting setting)
|
||||
{
|
||||
mPresenter.putSetting(setting);
|
||||
}
|
||||
@Override
|
||||
public void putSetting(Setting setting) {
|
||||
mPresenter.putSetting(setting);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettingChanged()
|
||||
{
|
||||
mActivity.onSettingChanged();
|
||||
}
|
||||
@Override
|
||||
public void onSettingChanged() {
|
||||
mActivity.onSettingChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGcPadSettingChanged(String key, int value)
|
||||
{
|
||||
mActivity.onGcPadSettingChanged(key, value);
|
||||
}
|
||||
@Override
|
||||
public void onGcPadSettingChanged(String key, int value) {
|
||||
mActivity.onGcPadSettingChanged(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWiimoteSettingChanged(String section, int value)
|
||||
{
|
||||
mActivity.onWiimoteSettingChanged(section, value);
|
||||
}
|
||||
@Override
|
||||
public void onWiimoteSettingChanged(String section, int value) {
|
||||
mActivity.onWiimoteSettingChanged(section, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onExtensionSettingChanged(String key, int value)
|
||||
{
|
||||
mActivity.onExtensionSettingChanged(key, value);
|
||||
}
|
||||
@Override
|
||||
public void onExtensionSettingChanged(String key, int value) {
|
||||
mActivity.onExtensionSettingChanged(key, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,205 +18,178 @@ import org.citra.citra_android.utils.SettingsFile;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public final class SettingsFragmentPresenter
|
||||
{
|
||||
private SettingsFragmentView mView;
|
||||
public final class SettingsFragmentPresenter {
|
||||
private SettingsFragmentView mView;
|
||||
|
||||
private String mMenuTag;
|
||||
private String mGameID;
|
||||
private String mMenuTag;
|
||||
private String mGameID;
|
||||
|
||||
private ArrayList<HashMap<String, SettingSection>> mSettings;
|
||||
private ArrayList<SettingsItem> mSettingsList;
|
||||
private ArrayList<HashMap<String, SettingSection>> mSettings;
|
||||
private ArrayList<SettingsItem> mSettingsList;
|
||||
|
||||
private int mControllerNumber;
|
||||
private int mControllerType;
|
||||
private int mControllerNumber;
|
||||
private int mControllerType;
|
||||
|
||||
public SettingsFragmentPresenter(SettingsFragmentView view)
|
||||
{
|
||||
mView = view;
|
||||
}
|
||||
public SettingsFragmentPresenter(SettingsFragmentView view) {
|
||||
mView = view;
|
||||
}
|
||||
|
||||
public void onCreate(String menuTag, String gameId)
|
||||
{
|
||||
mGameID = gameId;
|
||||
mMenuTag = menuTag;
|
||||
public void onCreate(String menuTag, String gameId) {
|
||||
mGameID = gameId;
|
||||
mMenuTag = menuTag;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void onViewCreated(ArrayList<HashMap<String, SettingSection>> settings)
|
||||
{
|
||||
setSettings(settings);
|
||||
}
|
||||
public void onViewCreated(ArrayList<HashMap<String, SettingSection>> settings) {
|
||||
setSettings(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the screen is rotated, the Activity will forget the settings map. This fragment
|
||||
* won't, though; so rather than have the Activity reload from disk, have the fragment pass
|
||||
* the settings map back to the Activity.
|
||||
*/
|
||||
public void onAttach()
|
||||
{
|
||||
if (mSettings != null)
|
||||
{
|
||||
mView.passSettingsToActivity(mSettings);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* If the screen is rotated, the Activity will forget the settings map. This fragment
|
||||
* won't, though; so rather than have the Activity reload from disk, have the fragment pass
|
||||
* the settings map back to the Activity.
|
||||
*/
|
||||
public void onAttach() {
|
||||
if (mSettings != null) {
|
||||
mView.passSettingsToActivity(mSettings);
|
||||
}
|
||||
}
|
||||
|
||||
public void putSetting(Setting setting)
|
||||
{
|
||||
mSettings.get(setting.getFile()).get(setting.getSection()).putSetting(setting);
|
||||
}
|
||||
public void putSetting(Setting setting) {
|
||||
mSettings.get(setting.getFile()).get(setting.getSection()).putSetting(setting);
|
||||
}
|
||||
|
||||
public void loadDefaultSettings()
|
||||
{
|
||||
loadSettingsList();
|
||||
}
|
||||
public void loadDefaultSettings() {
|
||||
loadSettingsList();
|
||||
}
|
||||
|
||||
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings)
|
||||
{
|
||||
if (mSettingsList == null && settings != null)
|
||||
{
|
||||
mSettings = settings;
|
||||
public void setSettings(ArrayList<HashMap<String, SettingSection>> settings) {
|
||||
if (mSettingsList == null && settings != null) {
|
||||
mSettings = settings;
|
||||
|
||||
loadSettingsList();
|
||||
}
|
||||
else
|
||||
{
|
||||
mView.showSettingsList(mSettingsList);
|
||||
}
|
||||
}
|
||||
loadSettingsList();
|
||||
} else {
|
||||
mView.showSettingsList(mSettingsList);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSettingsList()
|
||||
{
|
||||
if (!TextUtils.isEmpty(mGameID))
|
||||
{
|
||||
mView.getActivity().setTitle("Game Settings: " + mGameID);
|
||||
}
|
||||
ArrayList<SettingsItem> sl = new ArrayList<>();
|
||||
private void loadSettingsList() {
|
||||
if (!TextUtils.isEmpty(mGameID)) {
|
||||
mView.getActivity().setTitle("Game Settings: " + mGameID);
|
||||
}
|
||||
ArrayList<SettingsItem> sl = new ArrayList<>();
|
||||
|
||||
switch (mMenuTag)
|
||||
{
|
||||
case SettingsFile.FILE_NAME_CONFIG:
|
||||
addCoreSettings(sl);
|
||||
sl.add(new HeaderSetting(null, null, R.string.video_backend, 0));
|
||||
addGraphicsSettings(sl);
|
||||
break;
|
||||
default:
|
||||
mView.showToastMessage("Unimplemented menu");
|
||||
return;
|
||||
}
|
||||
switch (mMenuTag) {
|
||||
case SettingsFile.FILE_NAME_CONFIG:
|
||||
addCoreSettings(sl);
|
||||
sl.add(new HeaderSetting(null, null, R.string.video_backend, 0));
|
||||
addGraphicsSettings(sl);
|
||||
break;
|
||||
default:
|
||||
mView.showToastMessage("Unimplemented menu");
|
||||
return;
|
||||
}
|
||||
|
||||
mSettingsList = sl;
|
||||
mView.showSettingsList(mSettingsList);
|
||||
}
|
||||
mSettingsList = sl;
|
||||
mView.showSettingsList(mSettingsList);
|
||||
}
|
||||
|
||||
private void addCoreSettings(ArrayList<SettingsItem> sl)
|
||||
{
|
||||
Setting useCpuJit = null;
|
||||
Setting audioStretch = null;
|
||||
Setting region = null;
|
||||
Setting systemClock = null;
|
||||
Setting dateTime = null;
|
||||
private void addCoreSettings(ArrayList<SettingsItem> sl) {
|
||||
Setting useCpuJit = null;
|
||||
Setting audioStretch = null;
|
||||
Setting region = null;
|
||||
Setting systemClock = null;
|
||||
Setting dateTime = null;
|
||||
|
||||
if (!mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty())
|
||||
{
|
||||
useCpuJit = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_CPU_JIT);
|
||||
audioStretch = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_AUDIO).getSetting(SettingsFile.KEY_ENABLE_AUDIO_STRETCHING);
|
||||
region = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_REGION_VALUE);
|
||||
systemClock = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_INIT_CLOCK);
|
||||
dateTime = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_INIT_TIME);
|
||||
}
|
||||
else
|
||||
{
|
||||
mView.passSettingsToActivity(mSettings);
|
||||
}
|
||||
if (!mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) {
|
||||
useCpuJit = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_CORE).getSetting(SettingsFile.KEY_CPU_JIT);
|
||||
audioStretch = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_AUDIO).getSetting(SettingsFile.KEY_ENABLE_AUDIO_STRETCHING);
|
||||
region = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_REGION_VALUE);
|
||||
systemClock = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_INIT_CLOCK);
|
||||
dateTime = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_SYSTEM).getSetting(SettingsFile.KEY_INIT_TIME);
|
||||
} else {
|
||||
mView.passSettingsToActivity(mSettings);
|
||||
}
|
||||
|
||||
String defaultCpuCore = System.getProperty("os.arch");
|
||||
switch (defaultCpuCore)
|
||||
{
|
||||
case "x86_64":
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, SettingsFile.SECTION_CORE,
|
||||
SettingsFile.SETTINGS_DOLPHIN, R.string.cpu_jit, 0, true, useCpuJit));
|
||||
break;
|
||||
case "aarch64":
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_REGION_VALUE, SettingsFile.SECTION_SYSTEM,SettingsFile.SETTINGS_DOLPHIN, R.string.region, 0, R.array.regionNames, R.array.regionValues, -1, region));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_ENABLE_AUDIO_STRETCHING, SettingsFile.SECTION_AUDIO, SettingsFile.SETTINGS_DOLPHIN, R.string.audio_stretch, R.string.audio_stretch_description, false, audioStretch));
|
||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_INIT_CLOCK, SettingsFile.SECTION_SYSTEM, SettingsFile.SETTINGS_DOLPHIN, R.string.init_clock, R.string.init_clock_descrip, R.array.systemClockNames, R.array.systemClockValues, 0, systemClock));
|
||||
sl.add(new DateTimeSetting(SettingsFile.KEY_INIT_TIME, SettingsFile.SECTION_SYSTEM, SettingsFile.SETTINGS_DOLPHIN, R.string.init_time, R.string.init_time_descrip, "2000-01-01 00:00:01", dateTime));
|
||||
}
|
||||
String defaultCpuCore = System.getProperty("os.arch");
|
||||
switch (defaultCpuCore) {
|
||||
case "x86_64":
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, SettingsFile.SECTION_CORE,
|
||||
SettingsFile.SETTINGS_DOLPHIN, R.string.cpu_jit, 0, true, useCpuJit));
|
||||
break;
|
||||
case "aarch64":
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_REGION_VALUE, SettingsFile.SECTION_SYSTEM, SettingsFile.SETTINGS_DOLPHIN, R.string.region, 0, R.array.regionNames, R.array.regionValues, -1, region));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_ENABLE_AUDIO_STRETCHING, SettingsFile.SECTION_AUDIO, SettingsFile.SETTINGS_DOLPHIN, R.string.audio_stretch, R.string.audio_stretch_description, false, audioStretch));
|
||||
sl.add(new SingleChoiceSetting(SettingsFile.KEY_INIT_CLOCK, SettingsFile.SECTION_SYSTEM, SettingsFile.SETTINGS_DOLPHIN, R.string.init_clock, R.string.init_clock_descrip, R.array.systemClockNames, R.array.systemClockValues, 0, systemClock));
|
||||
sl.add(new DateTimeSetting(SettingsFile.KEY_INIT_TIME, SettingsFile.SECTION_SYSTEM, SettingsFile.SETTINGS_DOLPHIN, R.string.init_time, R.string.init_time_descrip, "2000-01-01 00:00:01", dateTime));
|
||||
}
|
||||
|
||||
private void addGraphicsSettings(ArrayList<SettingsItem> sl)
|
||||
{
|
||||
Setting hardwareRenderer = null;
|
||||
Setting hardwareShader = null;
|
||||
Setting shadersAccurateMul = null;
|
||||
Setting shadersAccurateGs = null;
|
||||
Setting shaderJitEnable = null;
|
||||
Setting resolutionFactor = null;
|
||||
Setting vsyncEnable = null;
|
||||
Setting frameLimitEnable = null;
|
||||
Setting frameLimitValue = null;
|
||||
Setting stereoscopyEnable = null;
|
||||
Setting stereoscopyDepth = null;
|
||||
private void addGraphicsSettings(ArrayList<SettingsItem> sl) {
|
||||
Setting hardwareRenderer = null;
|
||||
Setting hardwareShader = null;
|
||||
Setting shadersAccurateMul = null;
|
||||
Setting shadersAccurateGs = null;
|
||||
Setting shaderJitEnable = null;
|
||||
Setting resolutionFactor = null;
|
||||
Setting vsyncEnable = null;
|
||||
Setting frameLimitEnable = null;
|
||||
Setting frameLimitValue = null;
|
||||
Setting stereoscopyEnable = null;
|
||||
Setting stereoscopyDepth = null;
|
||||
|
||||
if (!mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty())
|
||||
{
|
||||
hardwareRenderer = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_HW_RENDERER);
|
||||
hardwareShader = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_HW_SHADER);
|
||||
shadersAccurateMul = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
|
||||
shadersAccurateGs = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_SHADERS_ACCURATE_GS);
|
||||
shaderJitEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_USE_SHADER_JIT);
|
||||
resolutionFactor = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_RESOLUTION_FACTOR);
|
||||
vsyncEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_USE_VSYNC);
|
||||
frameLimitEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FRAME_LIMIT_ENABLED);
|
||||
frameLimitValue = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FRAME_LIMIT);
|
||||
stereoscopyEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_STEREOSCOPY);
|
||||
stereoscopyDepth = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FACTOR_3D);
|
||||
}
|
||||
else
|
||||
{
|
||||
mView.passSettingsToActivity(mSettings);
|
||||
}
|
||||
if (!mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) {
|
||||
hardwareRenderer = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_HW_RENDERER);
|
||||
hardwareShader = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_HW_SHADER);
|
||||
shadersAccurateMul = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL);
|
||||
shadersAccurateGs = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_SHADERS_ACCURATE_GS);
|
||||
shaderJitEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_USE_SHADER_JIT);
|
||||
resolutionFactor = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_RESOLUTION_FACTOR);
|
||||
vsyncEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_USE_VSYNC);
|
||||
frameLimitEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FRAME_LIMIT_ENABLED);
|
||||
frameLimitValue = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FRAME_LIMIT);
|
||||
stereoscopyEnable = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_STEREOSCOPY);
|
||||
stereoscopyDepth = mSettings.get(SettingsFile.SETTINGS_DOLPHIN).get(SettingsFile.SECTION_RENDERER).getSetting(SettingsFile.KEY_FACTOR_3D);
|
||||
} else {
|
||||
mView.passSettingsToActivity(mSettings);
|
||||
}
|
||||
|
||||
if (mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty())
|
||||
{
|
||||
mView.passSettingsToActivity(mSettings);
|
||||
}
|
||||
if (mSettings.get(SettingsFile.SETTINGS_DOLPHIN).isEmpty()) {
|
||||
mView.passSettingsToActivity(mSettings);
|
||||
}
|
||||
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_RENDERER, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.hw_renderer, 0, true, hardwareRenderer));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_SHADER, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.hw_shaders, R.string.hw_shaders_descrip, true, hardwareShader));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.shaders_accurate_mul, 0, false, shadersAccurateMul));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_GS, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.shaders_accurate_gs , 0, false, shadersAccurateGs));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_SHADER_JIT, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.use_shader_jit, 0, true, shaderJitEnable));
|
||||
sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.internal_resolution, R.string.internal_resolution_descrip, 10, "x", 0, resolutionFactor));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_VSYNC, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.vsync , 0, false, vsyncEnable));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_FRAME_LIMIT_ENABLED, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.overclock_enable, 0, false, frameLimitEnable));
|
||||
sl.add(new SliderSetting(SettingsFile.KEY_FRAME_LIMIT, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.overclock_title, R.string.overclock_enable_description, 500, "%", 100, frameLimitValue));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_RENDERER, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.hw_renderer, 0, true, hardwareRenderer));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_SHADER, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.hw_shaders, R.string.hw_shaders_descrip, true, hardwareShader));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.shaders_accurate_mul, 0, false, shadersAccurateMul));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_GS, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.shaders_accurate_gs, 0, false, shadersAccurateGs));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_SHADER_JIT, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.use_shader_jit, 0, true, shaderJitEnable));
|
||||
sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.internal_resolution, R.string.internal_resolution_descrip, 10, "x", 0, resolutionFactor));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_VSYNC, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.vsync, 0, false, vsyncEnable));
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_FRAME_LIMIT_ENABLED, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.overclock_enable, 0, false, frameLimitEnable));
|
||||
sl.add(new SliderSetting(SettingsFile.KEY_FRAME_LIMIT, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.overclock_title, R.string.overclock_enable_description, 500, "%", 100, frameLimitValue));
|
||||
|
||||
// Todo: Implement ColorPickerSetting
|
||||
// sl.add(new ColorPickerSetting(SettingsFile.KEY_BACKGROUND_RED,SettingsFile.KEY_BACKGROUND_GREEN,SettingsFile.KEY_BACKGROUND_BLUE, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string., R.string., Color.BLACK, backgroundColor));
|
||||
// Todo: Implement ColorPickerSetting
|
||||
// sl.add(new ColorPickerSetting(SettingsFile.KEY_BACKGROUND_RED,SettingsFile.KEY_BACKGROUND_GREEN,SettingsFile.KEY_BACKGROUND_BLUE, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string., R.string., Color.BLACK, backgroundColor));
|
||||
|
||||
/*
|
||||
Check if we support stereo
|
||||
If we support desktop GL then we must support at least OpenGL 3.2
|
||||
If we only support OpenGLES then we need both OpenGLES 3.1 and AEP
|
||||
*/
|
||||
EGLHelper helper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT);
|
||||
EGLHelper helper = new EGLHelper(EGLHelper.EGL_OPENGL_ES2_BIT);
|
||||
|
||||
if ((helper.supportsOpenGL() && helper.GetVersion() >= 320) ||
|
||||
(helper.supportsGLES3() && helper.GetVersion() >= 310 && helper.SupportsExtension("GL_ANDROID_extension_pack_es31a")))
|
||||
{
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_STEREOSCOPY, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.stereoscopy, R.string.stereoscopy_descrip, false, stereoscopyEnable));
|
||||
sl.add(new SliderSetting(SettingsFile.KEY_FACTOR_3D, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.sterescopy_depth,R.string.sterescopy_depth_descrip,100,"%",0, stereoscopyDepth));
|
||||
}
|
||||
if ((helper.supportsOpenGL() && helper.GetVersion() >= 320) ||
|
||||
(helper.supportsGLES3() && helper.GetVersion() >= 310 && helper.SupportsExtension("GL_ANDROID_extension_pack_es31a"))) {
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_STEREOSCOPY, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.stereoscopy, R.string.stereoscopy_descrip, false, stereoscopyEnable));
|
||||
sl.add(new SliderSetting(SettingsFile.KEY_FACTOR_3D, SettingsFile.SECTION_RENDERER, SettingsFile.SETTINGS_DOLPHIN, R.string.sterescopy_depth, R.string.sterescopy_depth_descrip, 100, "%", 0, stereoscopyDepth));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void addGcPadSubSettings(ArrayList<SettingsItem> sl, int gcPadNumber, int gcPadType)
|
||||
{
|
||||
private void addGcPadSubSettings(ArrayList<SettingsItem> sl, int gcPadNumber, int gcPadType) {
|
||||
/*
|
||||
if (gcPadType == 1) // Emulated
|
||||
{
|
||||
@ -280,18 +253,14 @@ public final class SettingsFragmentPresenter
|
||||
sl.add(new CheckBoxSetting(SettingsFile.KEY_GCADAPTER_BONGOS + gcPadNumber, SettingsFile.SECTION_CORE, SettingsFile.SETTINGS_DOLPHIN, R.string.gc_adapter_bongos, R.string.gc_adapter_bongos_description, false, bongos));
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getInvertedBooleanValue(int file, String section, String key, boolean defaultValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
return ((IntSetting) mSettings.get(file).get(section).getSetting(key)).getValue() != 1;
|
||||
}
|
||||
catch (NullPointerException ex)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
private boolean getInvertedBooleanValue(int file, String section, String key, boolean defaultValue) {
|
||||
try {
|
||||
return ((IntSetting) mSettings.get(file).get(section).getSetting(key)).getValue() != 1;
|
||||
} catch (NullPointerException ex) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -13,92 +13,91 @@ import java.util.HashMap;
|
||||
* Abstraction for a screen showing a list of settings. Instances of
|
||||
* this type of view will each display a layer of the setting hierarchy.
|
||||
*/
|
||||
public interface SettingsFragmentView
|
||||
{
|
||||
/**
|
||||
* Called by the containing Activity to notify the Fragment that an
|
||||
* asynchronous load operation completed.
|
||||
*
|
||||
* @param settings The (possibly null) result of the ini load operation.
|
||||
*/
|
||||
void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings);
|
||||
public interface SettingsFragmentView {
|
||||
/**
|
||||
* Called by the containing Activity to notify the Fragment that an
|
||||
* asynchronous load operation completed.
|
||||
*
|
||||
* @param settings The (possibly null) result of the ini load operation.
|
||||
*/
|
||||
void onSettingsFileLoaded(ArrayList<HashMap<String, SettingSection>> settings);
|
||||
|
||||
/**
|
||||
* Pass a settings HashMap to the containing activity, so that it can
|
||||
* share the HashMap with other SettingsFragments; useful so that rotations
|
||||
* do not require an additional load operation.
|
||||
*
|
||||
* @param settings An ArrayList containing all the settings HashMaps.
|
||||
*/
|
||||
void passSettingsToActivity(ArrayList<HashMap<String, SettingSection>> settings);
|
||||
/**
|
||||
* Pass a settings HashMap to the containing activity, so that it can
|
||||
* share the HashMap with other SettingsFragments; useful so that rotations
|
||||
* do not require an additional load operation.
|
||||
*
|
||||
* @param settings An ArrayList containing all the settings HashMaps.
|
||||
*/
|
||||
void passSettingsToActivity(ArrayList<HashMap<String, SettingSection>> settings);
|
||||
|
||||
/**
|
||||
* Pass an ArrayList to the View so that it can be displayed on screen.
|
||||
*
|
||||
* @param settingsList The result of converting the HashMap to an ArrayList
|
||||
*/
|
||||
void showSettingsList(ArrayList<SettingsItem> settingsList);
|
||||
/**
|
||||
* Pass an ArrayList to the View so that it can be displayed on screen.
|
||||
*
|
||||
* @param settingsList The result of converting the HashMap to an ArrayList
|
||||
*/
|
||||
void showSettingsList(ArrayList<SettingsItem> settingsList);
|
||||
|
||||
/**
|
||||
* Called by the containing Activity when an asynchronous load operation fails.
|
||||
* Instructs the Fragment to load the settings screen with defaults selected.
|
||||
*/
|
||||
void loadDefaultSettings();
|
||||
/**
|
||||
* Called by the containing Activity when an asynchronous load operation fails.
|
||||
* Instructs the Fragment to load the settings screen with defaults selected.
|
||||
*/
|
||||
void loadDefaultSettings();
|
||||
|
||||
/**
|
||||
* @return The Fragment's containing activity.
|
||||
*/
|
||||
FragmentActivity getActivity();
|
||||
/**
|
||||
* @return The Fragment's containing activity.
|
||||
*/
|
||||
FragmentActivity getActivity();
|
||||
|
||||
/**
|
||||
* Tell the Fragment to tell the containing Activity to show a new
|
||||
* Fragment containing a submenu of settings.
|
||||
*
|
||||
* @param menuKey Identifier for the settings group that should be shown.
|
||||
*/
|
||||
void loadSubMenu(String menuKey);
|
||||
/**
|
||||
* Tell the Fragment to tell the containing Activity to show a new
|
||||
* Fragment containing a submenu of settings.
|
||||
*
|
||||
* @param menuKey Identifier for the settings group that should be shown.
|
||||
*/
|
||||
void loadSubMenu(String menuKey);
|
||||
|
||||
/**
|
||||
* Tell the Fragment to tell the containing activity to display a toast message.
|
||||
*
|
||||
* @param message Text to be shown in the Toast
|
||||
*/
|
||||
void showToastMessage(String message);
|
||||
/**
|
||||
* Tell the Fragment to tell the containing activity to display a toast message.
|
||||
*
|
||||
* @param message Text to be shown in the Toast
|
||||
*/
|
||||
void showToastMessage(String message);
|
||||
|
||||
/**
|
||||
* Have the fragment add a setting to the HashMap.
|
||||
*
|
||||
* @param setting The (possibly previously missing) new setting.
|
||||
*/
|
||||
void putSetting(Setting setting);
|
||||
/**
|
||||
* Have the fragment add a setting to the HashMap.
|
||||
*
|
||||
* @param setting The (possibly previously missing) new setting.
|
||||
*/
|
||||
void putSetting(Setting setting);
|
||||
|
||||
/**
|
||||
* Have the fragment tell the containing Activity that a setting was modified.
|
||||
*/
|
||||
void onSettingChanged();
|
||||
/**
|
||||
* Have the fragment tell the containing Activity that a setting was modified.
|
||||
*/
|
||||
void onSettingChanged();
|
||||
|
||||
/**
|
||||
* Have the fragment tell the containing Activity that a GCPad's setting was modified.
|
||||
*
|
||||
* @param key Identifier for the GCPad that was modified.
|
||||
* @param value New setting for the GCPad.
|
||||
*/
|
||||
void onGcPadSettingChanged(String key, int value);
|
||||
/**
|
||||
* Have the fragment tell the containing Activity that a GCPad's setting was modified.
|
||||
*
|
||||
* @param key Identifier for the GCPad that was modified.
|
||||
* @param value New setting for the GCPad.
|
||||
*/
|
||||
void onGcPadSettingChanged(String key, int value);
|
||||
|
||||
/**
|
||||
* Have the fragment tell the containing Activity that a Wiimote's setting was modified.
|
||||
*
|
||||
* @param section Identifier for Wiimote that was modified; Wiimotes are identified by their section,
|
||||
* not their key.
|
||||
* @param value New setting for the Wiimote.
|
||||
*/
|
||||
void onWiimoteSettingChanged(String section, int value);
|
||||
/**
|
||||
* Have the fragment tell the containing Activity that a Wiimote's setting was modified.
|
||||
*
|
||||
* @param section Identifier for Wiimote that was modified; Wiimotes are identified by their section,
|
||||
* not their key.
|
||||
* @param value New setting for the Wiimote.
|
||||
*/
|
||||
void onWiimoteSettingChanged(String section, int value);
|
||||
|
||||
/**
|
||||
* Have the fragment tell the containing Activity that an extension setting was modified.
|
||||
*
|
||||
* @param key Identifier for the extension that was modified.
|
||||
* @param value New setting for the extension.
|
||||
*/
|
||||
void onExtensionSettingChanged(String key, int value);
|
||||
/**
|
||||
* Have the fragment tell the containing Activity that an extension setting was modified.
|
||||
*
|
||||
* @param key Identifier for the extension that was modified.
|
||||
* @param value New setting for the extension.
|
||||
*/
|
||||
void onExtensionSettingChanged(String key, int value);
|
||||
}
|
||||
|
@ -7,50 +7,41 @@ import android.widget.FrameLayout;
|
||||
/**
|
||||
* FrameLayout subclass with few Properties added to simplify animations.
|
||||
*/
|
||||
public final class SettingsFrameLayout extends FrameLayout
|
||||
{
|
||||
private float mVisibleness = 1.0f;
|
||||
public final class SettingsFrameLayout extends FrameLayout {
|
||||
private float mVisibleness = 1.0f;
|
||||
|
||||
public SettingsFrameLayout(Context context)
|
||||
{
|
||||
super(context);
|
||||
}
|
||||
public SettingsFrameLayout(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SettingsFrameLayout(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
}
|
||||
public SettingsFrameLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr)
|
||||
{
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
|
||||
{
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
public float getYFraction()
|
||||
{
|
||||
return getY() / getHeight();
|
||||
}
|
||||
public float getYFraction() {
|
||||
return getY() / getHeight();
|
||||
}
|
||||
|
||||
public void setYFraction(float yFraction)
|
||||
{
|
||||
final int height = getHeight();
|
||||
setY((height > 0) ? (yFraction * height) : -9999);
|
||||
}
|
||||
public void setYFraction(float yFraction) {
|
||||
final int height = getHeight();
|
||||
setY((height > 0) ? (yFraction * height) : -9999);
|
||||
}
|
||||
|
||||
public float getVisibleness()
|
||||
{
|
||||
return mVisibleness;
|
||||
}
|
||||
public float getVisibleness() {
|
||||
return mVisibleness;
|
||||
}
|
||||
|
||||
public void setVisibleness(float visibleness)
|
||||
{
|
||||
setScaleX(visibleness);
|
||||
setScaleY(visibleness);
|
||||
setAlpha(visibleness);
|
||||
}
|
||||
public void setVisibleness(float visibleness) {
|
||||
setScaleX(visibleness);
|
||||
setScaleY(visibleness);
|
||||
setAlpha(visibleness);
|
||||
}
|
||||
}
|
||||
|
@ -9,48 +9,42 @@ import org.citra.citra_android.model.settings.view.CheckBoxSetting;
|
||||
import org.citra.citra_android.model.settings.view.SettingsItem;
|
||||
import org.citra.citra_android.ui.settings.SettingsAdapter;
|
||||
|
||||
public final class CheckBoxSettingViewHolder extends SettingViewHolder
|
||||
{
|
||||
private CheckBoxSetting mItem;
|
||||
public final class CheckBoxSettingViewHolder extends SettingViewHolder {
|
||||
private CheckBoxSetting mItem;
|
||||
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
|
||||
private CheckBox mCheckbox;
|
||||
private CheckBox mCheckbox;
|
||||
|
||||
public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter)
|
||||
{
|
||||
super(itemView, adapter);
|
||||
}
|
||||
public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter) {
|
||||
super(itemView, adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void findViews(View root)
|
||||
{
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
mCheckbox = root.findViewById(R.id.checkbox);
|
||||
}
|
||||
@Override
|
||||
protected void findViews(View root) {
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
mCheckbox = root.findViewById(R.id.checkbox);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SettingsItem item)
|
||||
{
|
||||
mItem = (CheckBoxSetting) item;
|
||||
@Override
|
||||
public void bind(SettingsItem item) {
|
||||
mItem = (CheckBoxSetting) item;
|
||||
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
|
||||
if (item.getDescriptionId() > 0)
|
||||
{
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
if (item.getDescriptionId() > 0) {
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
|
||||
mCheckbox.setChecked(mItem.isChecked());
|
||||
}
|
||||
mCheckbox.setChecked(mItem.isChecked());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
mCheckbox.toggle();
|
||||
@Override
|
||||
public void onClick(View clicked) {
|
||||
mCheckbox.toggle();
|
||||
|
||||
getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked());
|
||||
}
|
||||
getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked());
|
||||
}
|
||||
}
|
||||
|
@ -9,21 +9,18 @@ import org.citra.citra_android.model.settings.view.SettingsItem;
|
||||
import org.citra.citra_android.ui.settings.SettingsAdapter;
|
||||
import org.citra.citra_android.utils.Log;
|
||||
|
||||
public final class DateTimeViewHolder extends SettingViewHolder
|
||||
{
|
||||
public final class DateTimeViewHolder extends SettingViewHolder {
|
||||
private DateTimeSetting mItem;
|
||||
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
|
||||
public DateTimeViewHolder(View itemView, SettingsAdapter adapter)
|
||||
{
|
||||
public DateTimeViewHolder(View itemView, SettingsAdapter adapter) {
|
||||
super(itemView, adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void findViews(View root)
|
||||
{
|
||||
protected void findViews(View root) {
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
Log.error("test " + mTextSettingName);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
@ -31,19 +28,16 @@ public final class DateTimeViewHolder extends SettingViewHolder
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SettingsItem item)
|
||||
{
|
||||
public void bind(SettingsItem item) {
|
||||
mItem = (DateTimeSetting) item;
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
if (item.getDescriptionId() > 0)
|
||||
{
|
||||
if (item.getDescriptionId() > 0) {
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
public void onClick(View clicked) {
|
||||
getAdapter().onDateTimeClick(mItem);
|
||||
}
|
||||
}
|
@ -7,31 +7,26 @@ import org.citra.citra_android.R;
|
||||
import org.citra.citra_android.model.settings.view.SettingsItem;
|
||||
import org.citra.citra_android.ui.settings.SettingsAdapter;
|
||||
|
||||
public final class HeaderViewHolder extends SettingViewHolder
|
||||
{
|
||||
private TextView mHeaderName;
|
||||
public final class HeaderViewHolder extends SettingViewHolder {
|
||||
private TextView mHeaderName;
|
||||
|
||||
public HeaderViewHolder(View itemView, SettingsAdapter adapter)
|
||||
{
|
||||
super(itemView, adapter);
|
||||
itemView.setOnClickListener(null);
|
||||
}
|
||||
public HeaderViewHolder(View itemView, SettingsAdapter adapter) {
|
||||
super(itemView, adapter);
|
||||
itemView.setOnClickListener(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void findViews(View root)
|
||||
{
|
||||
mHeaderName = root.findViewById(R.id.text_header_name);
|
||||
}
|
||||
@Override
|
||||
protected void findViews(View root) {
|
||||
mHeaderName = root.findViewById(R.id.text_header_name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SettingsItem item)
|
||||
{
|
||||
mHeaderName.setText(item.getNameId());
|
||||
}
|
||||
@Override
|
||||
public void bind(SettingsItem item) {
|
||||
mHeaderName.setText(item.getNameId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
@Override
|
||||
public void onClick(View clicked) {
|
||||
// no-op
|
||||
}
|
||||
}
|
@ -11,43 +11,38 @@ import org.citra.citra_android.model.settings.view.InputBindingSetting;
|
||||
import org.citra.citra_android.model.settings.view.SettingsItem;
|
||||
import org.citra.citra_android.ui.settings.SettingsAdapter;
|
||||
|
||||
public final class InputBindingSettingViewHolder extends SettingViewHolder
|
||||
{
|
||||
private InputBindingSetting mItem;
|
||||
public final class InputBindingSettingViewHolder extends SettingViewHolder {
|
||||
private InputBindingSetting mItem;
|
||||
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
|
||||
private Context mContext;
|
||||
private Context mContext;
|
||||
|
||||
public InputBindingSettingViewHolder(View itemView, SettingsAdapter adapter, Context context)
|
||||
{
|
||||
super(itemView, adapter);
|
||||
public InputBindingSettingViewHolder(View itemView, SettingsAdapter adapter, Context context) {
|
||||
super(itemView, adapter);
|
||||
|
||||
mContext = context;
|
||||
}
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void findViews(View root)
|
||||
{
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
@Override
|
||||
protected void findViews(View root) {
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SettingsItem item)
|
||||
{
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
@Override
|
||||
public void bind(SettingsItem item) {
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
|
||||
mItem = (InputBindingSetting) item;
|
||||
mItem = (InputBindingSetting) item;
|
||||
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
mTextSettingDescription.setText(sharedPreferences.getString(mItem.getKey(), ""));
|
||||
}
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
mTextSettingDescription.setText(sharedPreferences.getString(mItem.getKey(), ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
|
||||
}
|
||||
@Override
|
||||
public void onClick(View clicked) {
|
||||
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
|
||||
}
|
||||
}
|
||||
|
@ -6,46 +6,43 @@ import android.view.View;
|
||||
import org.citra.citra_android.model.settings.view.SettingsItem;
|
||||
import org.citra.citra_android.ui.settings.SettingsAdapter;
|
||||
|
||||
public abstract class SettingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
|
||||
{
|
||||
private SettingsAdapter mAdapter;
|
||||
public abstract class SettingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
private SettingsAdapter mAdapter;
|
||||
|
||||
public SettingViewHolder(View itemView, SettingsAdapter adapter)
|
||||
{
|
||||
super(itemView);
|
||||
public SettingViewHolder(View itemView, SettingsAdapter adapter) {
|
||||
super(itemView);
|
||||
|
||||
mAdapter = adapter;
|
||||
mAdapter = adapter;
|
||||
|
||||
itemView.setOnClickListener(this);
|
||||
itemView.setOnClickListener(this);
|
||||
|
||||
findViews(itemView);
|
||||
}
|
||||
findViews(itemView);
|
||||
}
|
||||
|
||||
protected SettingsAdapter getAdapter()
|
||||
{
|
||||
return mAdapter;
|
||||
}
|
||||
protected SettingsAdapter getAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets handles to all this ViewHolder's child views using their XML-defined identifiers.
|
||||
*
|
||||
* @param root The newly inflated top-level view.
|
||||
*/
|
||||
protected abstract void findViews(View root);
|
||||
/**
|
||||
* Gets handles to all this ViewHolder's child views using their XML-defined identifiers.
|
||||
*
|
||||
* @param root The newly inflated top-level view.
|
||||
*/
|
||||
protected abstract void findViews(View root);
|
||||
|
||||
/**
|
||||
* Called by the adapter to set this ViewHolder's child views to display the list item
|
||||
* it must now represent.
|
||||
*
|
||||
* @param item The list item that should be represented by this ViewHolder.
|
||||
*/
|
||||
public abstract void bind(SettingsItem item);
|
||||
/**
|
||||
* Called by the adapter to set this ViewHolder's child views to display the list item
|
||||
* it must now represent.
|
||||
*
|
||||
* @param item The list item that should be represented by this ViewHolder.
|
||||
*/
|
||||
public abstract void bind(SettingsItem item);
|
||||
|
||||
/**
|
||||
* Called when this ViewHolder's view is clicked on. Implementations should usually pass
|
||||
* this event up to the adapter.
|
||||
*
|
||||
* @param clicked The view that was clicked on.
|
||||
*/
|
||||
public abstract void onClick(View clicked);
|
||||
/**
|
||||
* Called when this ViewHolder's view is clicked on. Implementations should usually pass
|
||||
* this event up to the adapter.
|
||||
*
|
||||
* @param clicked The view that was clicked on.
|
||||
*/
|
||||
public abstract void onClick(View clicked);
|
||||
}
|
||||
|
@ -8,41 +8,35 @@ import org.citra.citra_android.model.settings.view.SettingsItem;
|
||||
import org.citra.citra_android.model.settings.view.SingleChoiceSetting;
|
||||
import org.citra.citra_android.ui.settings.SettingsAdapter;
|
||||
|
||||
public final class SingleChoiceViewHolder extends SettingViewHolder
|
||||
{
|
||||
private SingleChoiceSetting mItem;
|
||||
public final class SingleChoiceViewHolder extends SettingViewHolder {
|
||||
private SingleChoiceSetting mItem;
|
||||
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
|
||||
public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter)
|
||||
{
|
||||
super(itemView, adapter);
|
||||
}
|
||||
public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter) {
|
||||
super(itemView, adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void findViews(View root)
|
||||
{
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
@Override
|
||||
protected void findViews(View root) {
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SettingsItem item)
|
||||
{
|
||||
mItem = (SingleChoiceSetting) item;
|
||||
@Override
|
||||
public void bind(SettingsItem item) {
|
||||
mItem = (SingleChoiceSetting) item;
|
||||
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
|
||||
if (item.getDescriptionId() > 0)
|
||||
{
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
}
|
||||
if (item.getDescriptionId() > 0) {
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
getAdapter().onSingleChoiceClick(mItem);
|
||||
}
|
||||
@Override
|
||||
public void onClick(View clicked) {
|
||||
getAdapter().onSingleChoiceClick(mItem);
|
||||
}
|
||||
}
|
||||
|
@ -8,42 +8,36 @@ import org.citra.citra_android.model.settings.view.SettingsItem;
|
||||
import org.citra.citra_android.model.settings.view.SliderSetting;
|
||||
import org.citra.citra_android.ui.settings.SettingsAdapter;
|
||||
|
||||
public final class SliderViewHolder extends SettingViewHolder
|
||||
{
|
||||
private SliderSetting mItem;
|
||||
public final class SliderViewHolder extends SettingViewHolder {
|
||||
private SliderSetting mItem;
|
||||
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
|
||||
public SliderViewHolder(View itemView, SettingsAdapter adapter)
|
||||
{
|
||||
super(itemView, adapter);
|
||||
}
|
||||
public SliderViewHolder(View itemView, SettingsAdapter adapter) {
|
||||
super(itemView, adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void findViews(View root)
|
||||
{
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
@Override
|
||||
protected void findViews(View root) {
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SettingsItem item)
|
||||
{
|
||||
mItem = (SliderSetting) item;
|
||||
@Override
|
||||
public void bind(SettingsItem item) {
|
||||
mItem = (SliderSetting) item;
|
||||
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
|
||||
if (item.getDescriptionId() > 0)
|
||||
{
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
}
|
||||
if (item.getDescriptionId() > 0) {
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
getAdapter().onSliderClick(mItem);
|
||||
}
|
||||
@Override
|
||||
public void onClick(View clicked) {
|
||||
getAdapter().onSliderClick(mItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,41 +8,35 @@ import org.citra.citra_android.model.settings.view.SettingsItem;
|
||||
import org.citra.citra_android.model.settings.view.SubmenuSetting;
|
||||
import org.citra.citra_android.ui.settings.SettingsAdapter;
|
||||
|
||||
public final class SubmenuViewHolder extends SettingViewHolder
|
||||
{
|
||||
private SubmenuSetting mItem;
|
||||
public final class SubmenuViewHolder extends SettingViewHolder {
|
||||
private SubmenuSetting mItem;
|
||||
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
private TextView mTextSettingName;
|
||||
private TextView mTextSettingDescription;
|
||||
|
||||
public SubmenuViewHolder(View itemView, SettingsAdapter adapter)
|
||||
{
|
||||
super(itemView, adapter);
|
||||
}
|
||||
public SubmenuViewHolder(View itemView, SettingsAdapter adapter) {
|
||||
super(itemView, adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void findViews(View root)
|
||||
{
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
@Override
|
||||
protected void findViews(View root) {
|
||||
mTextSettingName = root.findViewById(R.id.text_setting_name);
|
||||
mTextSettingDescription = root.findViewById(R.id.text_setting_description);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(SettingsItem item)
|
||||
{
|
||||
mItem = (SubmenuSetting) item;
|
||||
@Override
|
||||
public void bind(SettingsItem item) {
|
||||
mItem = (SubmenuSetting) item;
|
||||
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
mTextSettingName.setText(item.getNameId());
|
||||
|
||||
if (item.getDescriptionId() > 0)
|
||||
{
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
}
|
||||
if (item.getDescriptionId() > 0) {
|
||||
mTextSettingDescription.setText(item.getDescriptionId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View clicked)
|
||||
{
|
||||
getAdapter().onSubmenuClick(mItem);
|
||||
}
|
||||
@Override
|
||||
public void onClick(View clicked) {
|
||||
getAdapter().onSubmenuClick(mItem);
|
||||
}
|
||||
}
|
@ -8,37 +8,31 @@ import android.net.Uri;
|
||||
import org.citra.citra_android.model.GameDatabase;
|
||||
import org.citra.citra_android.model.GameProvider;
|
||||
|
||||
public class AddDirectoryHelper
|
||||
{
|
||||
private Context mContext;
|
||||
public class AddDirectoryHelper {
|
||||
private Context mContext;
|
||||
|
||||
public interface AddDirectoryListener
|
||||
{
|
||||
void onDirectoryAdded();
|
||||
}
|
||||
public AddDirectoryHelper(Context context) {
|
||||
this.mContext = context;
|
||||
}
|
||||
|
||||
public AddDirectoryHelper(Context context)
|
||||
{
|
||||
this.mContext = context;
|
||||
}
|
||||
public void addDirectory(String dir, AddDirectoryListener addDirectoryListener) {
|
||||
AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver()) {
|
||||
@Override
|
||||
protected void onInsertComplete(int token, Object cookie, Uri uri) {
|
||||
addDirectoryListener.onDirectoryAdded();
|
||||
}
|
||||
};
|
||||
|
||||
public void addDirectory(String dir, AddDirectoryListener addDirectoryListener)
|
||||
{
|
||||
AsyncQueryHandler handler = new AsyncQueryHandler(mContext.getContentResolver())
|
||||
{
|
||||
@Override
|
||||
protected void onInsertComplete(int token, Object cookie, Uri uri)
|
||||
{
|
||||
addDirectoryListener.onDirectoryAdded();
|
||||
}
|
||||
};
|
||||
ContentValues file = new ContentValues();
|
||||
file.put(GameDatabase.KEY_FOLDER_PATH, dir);
|
||||
|
||||
ContentValues file = new ContentValues();
|
||||
file.put(GameDatabase.KEY_FOLDER_PATH, dir);
|
||||
handler.startInsert(0, // We don't need to identify this call to the handler
|
||||
null, // We don't need to pass additional data to the handler
|
||||
GameProvider.URI_FOLDER, // Tell the GameProvider we are adding a folder
|
||||
file);
|
||||
}
|
||||
|
||||
handler.startInsert(0, // We don't need to identify this call to the handler
|
||||
null, // We don't need to pass additional data to the handler
|
||||
GameProvider.URI_FOLDER, // Tell the GameProvider we are adding a folder
|
||||
file);
|
||||
}
|
||||
public interface AddDirectoryListener {
|
||||
void onDirectoryAdded();
|
||||
}
|
||||
}
|
||||
|
@ -3,27 +3,23 @@ package org.citra.citra_android.utils;
|
||||
import android.view.View;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
|
||||
public final class Animations
|
||||
{
|
||||
private Animations()
|
||||
{
|
||||
}
|
||||
public final class Animations {
|
||||
private Animations() {
|
||||
}
|
||||
|
||||
public static ViewPropertyAnimator fadeViewIn(View view)
|
||||
{
|
||||
view.setVisibility(View.VISIBLE);
|
||||
public static ViewPropertyAnimator fadeViewIn(View view) {
|
||||
view.setVisibility(View.VISIBLE);
|
||||
|
||||
return view.animate()
|
||||
.withLayer()
|
||||
.setDuration(100)
|
||||
.alpha(1.0f);
|
||||
}
|
||||
return view.animate()
|
||||
.withLayer()
|
||||
.setDuration(100)
|
||||
.alpha(1.0f);
|
||||
}
|
||||
|
||||
public static ViewPropertyAnimator fadeViewOut(View view)
|
||||
{
|
||||
return view.animate()
|
||||
.withLayer()
|
||||
.setDuration(300)
|
||||
.alpha(0.0f);
|
||||
}
|
||||
public static ViewPropertyAnimator fadeViewOut(View view) {
|
||||
return view.animate()
|
||||
.withLayer()
|
||||
.setDuration(300)
|
||||
.alpha(0.0f);
|
||||
}
|
||||
}
|
||||
|
@ -7,77 +7,61 @@ import android.view.MotionEvent;
|
||||
/**
|
||||
* Some controllers have incorrect mappings. This class has special-case fixes for them.
|
||||
*/
|
||||
public class ControllerMappingHelper
|
||||
{
|
||||
/**
|
||||
* Some controllers report extra button presses that can be ignored.
|
||||
*/
|
||||
public boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode)
|
||||
{
|
||||
if (isDualShock4(inputDevice))
|
||||
{
|
||||
// The two analog triggers generate analog motion events as well as a keycode.
|
||||
// We always prefer to use the analog values, so throw away the button press
|
||||
// Even though the triggers are L/R2, without mappings they generate L/R1 events.
|
||||
return keyCode == KeyEvent.KEYCODE_BUTTON_L1 || keyCode == KeyEvent.KEYCODE_BUTTON_R1;
|
||||
public class ControllerMappingHelper {
|
||||
/**
|
||||
* Some controllers report extra button presses that can be ignored.
|
||||
*/
|
||||
public boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode) {
|
||||
if (isDualShock4(inputDevice)) {
|
||||
// The two analog triggers generate analog motion events as well as a keycode.
|
||||
// We always prefer to use the analog values, so throw away the button press
|
||||
// Even though the triggers are L/R2, without mappings they generate L/R1 events.
|
||||
return keyCode == KeyEvent.KEYCODE_BUTTON_L1 || keyCode == KeyEvent.KEYCODE_BUTTON_R1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale an axis to be zero-centered with a proper range.
|
||||
*/
|
||||
public float scaleAxis(InputDevice inputDevice, int axis, float value)
|
||||
{
|
||||
if (isDualShock4(inputDevice))
|
||||
{
|
||||
// Android doesn't have correct mappings for this controller's triggers. It reports them
|
||||
// as RX & RY, centered at -1.0, and with a range of [-1.0, 1.0]
|
||||
// Scale them to properly zero-centered with a range of [0.0, 1.0].
|
||||
if (axis == MotionEvent.AXIS_RX || axis == MotionEvent.AXIS_RY)
|
||||
{
|
||||
return (value + 1) / 2.0f;
|
||||
}
|
||||
/**
|
||||
* Scale an axis to be zero-centered with a proper range.
|
||||
*/
|
||||
public float scaleAxis(InputDevice inputDevice, int axis, float value) {
|
||||
if (isDualShock4(inputDevice)) {
|
||||
// Android doesn't have correct mappings for this controller's triggers. It reports them
|
||||
// as RX & RY, centered at -1.0, and with a range of [-1.0, 1.0]
|
||||
// Scale them to properly zero-centered with a range of [0.0, 1.0].
|
||||
if (axis == MotionEvent.AXIS_RX || axis == MotionEvent.AXIS_RY) {
|
||||
return (value + 1) / 2.0f;
|
||||
}
|
||||
} else if (isXboxOneWireless(inputDevice)) {
|
||||
// Same as the DualShock 4, the mappings are missing.
|
||||
if (axis == MotionEvent.AXIS_Z || axis == MotionEvent.AXIS_RZ) {
|
||||
return (value + 1) / 2.0f;
|
||||
}
|
||||
if (axis == MotionEvent.AXIS_GENERIC_1) {
|
||||
// This axis is stuck at ~.5. Ignore it.
|
||||
return 0.0f;
|
||||
}
|
||||
} else if (isMogaPro2Hid(inputDevice)) {
|
||||
// This controller has a broken axis that reports a constant value. Ignore it.
|
||||
if (axis == MotionEvent.AXIS_GENERIC_1) {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
else if (isXboxOneWireless(inputDevice))
|
||||
{
|
||||
// Same as the DualShock 4, the mappings are missing.
|
||||
if (axis == MotionEvent.AXIS_Z || axis == MotionEvent.AXIS_RZ)
|
||||
{
|
||||
return (value + 1) / 2.0f;
|
||||
}
|
||||
if (axis == MotionEvent.AXIS_GENERIC_1)
|
||||
{
|
||||
// This axis is stuck at ~.5. Ignore it.
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
private boolean isDualShock4(InputDevice inputDevice) {
|
||||
// Sony DualShock 4 controller
|
||||
return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc;
|
||||
}
|
||||
else if (isMogaPro2Hid(inputDevice))
|
||||
{
|
||||
// This controller has a broken axis that reports a constant value. Ignore it.
|
||||
if (axis == MotionEvent.AXIS_GENERIC_1)
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
private boolean isXboxOneWireless(InputDevice inputDevice) {
|
||||
// Microsoft Xbox One controller
|
||||
return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private boolean isDualShock4(InputDevice inputDevice)
|
||||
{
|
||||
// Sony DualShock 4 controller
|
||||
return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc;
|
||||
}
|
||||
|
||||
private boolean isXboxOneWireless(InputDevice inputDevice)
|
||||
{
|
||||
// Microsoft Xbox One controller
|
||||
return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0;
|
||||
}
|
||||
|
||||
private boolean isMogaPro2Hid(InputDevice inputDevice)
|
||||
{
|
||||
// Moga Pro 2 HID
|
||||
return inputDevice.getVendorId() == 0x20d6 && inputDevice.getProductId() == 0x6271;
|
||||
}
|
||||
private boolean isMogaPro2Hid(InputDevice inputDevice) {
|
||||
// Moga Pro 2 HID
|
||||
return inputDevice.getVendorId() == 0x20d6 && inputDevice.getProductId() == 0x6271;
|
||||
}
|
||||
}
|
||||
|
@ -9,20 +9,17 @@ import org.citra.citra_android.services.DirectoryInitializationService.Directory
|
||||
|
||||
import rx.functions.Action1;
|
||||
|
||||
public class DirectoryStateReceiver extends BroadcastReceiver
|
||||
{
|
||||
Action1<DirectoryInitializationState> callback;
|
||||
public class DirectoryStateReceiver extends BroadcastReceiver {
|
||||
Action1<DirectoryInitializationState> callback;
|
||||
|
||||
public DirectoryStateReceiver(Action1<DirectoryInitializationState> callback)
|
||||
{
|
||||
this.callback = 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);
|
||||
}
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
DirectoryInitializationState state = (DirectoryInitializationState) intent
|
||||
.getSerializableExtra(DirectoryInitializationService.EXTRA_STATE);
|
||||
callback.call(state);
|
||||
}
|
||||
}
|
||||
|
@ -22,368 +22,332 @@ import javax.microedition.khronos.opengles.GL10;
|
||||
* EGL initialization out of the way if all that is
|
||||
* wanted is to query the underlying GL API for information.
|
||||
*/
|
||||
public final class EGLHelper
|
||||
{
|
||||
private final EGL10 mEGL;
|
||||
private final EGLDisplay mDisplay;
|
||||
private EGLConfig[] mEGLConfigs;
|
||||
private EGLContext mEGLContext;
|
||||
private EGLSurface mEGLSurface;
|
||||
private GL10 mGL;
|
||||
public final class EGLHelper {
|
||||
// Renderable type bitmasks
|
||||
public static final int EGL_OPENGL_ES_BIT = 0x0001;
|
||||
public static final int EGL_OPENGL_ES2_BIT = 0x0004;
|
||||
public static final int EGL_OPENGL_BIT = 0x0008;
|
||||
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
|
||||
// API types
|
||||
public static final int EGL_OPENGL_ES_API = 0x30A0;
|
||||
public static final int EGL_OPENGL_API = 0x30A2;
|
||||
private final EGL10 mEGL;
|
||||
private final EGLDisplay mDisplay;
|
||||
private EGLConfig[] mEGLConfigs;
|
||||
private EGLContext mEGLContext;
|
||||
private EGLSurface mEGLSurface;
|
||||
private GL10 mGL;
|
||||
// GL support flags
|
||||
private boolean supportGL;
|
||||
private boolean supportGLES2;
|
||||
private boolean supportGLES3;
|
||||
|
||||
// GL support flags
|
||||
private boolean supportGL;
|
||||
private boolean supportGLES2;
|
||||
private boolean supportGLES3;
|
||||
|
||||
// Renderable type bitmasks
|
||||
public static final int EGL_OPENGL_ES_BIT = 0x0001;
|
||||
public static final int EGL_OPENGL_ES2_BIT = 0x0004;
|
||||
public static final int EGL_OPENGL_BIT = 0x0008;
|
||||
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
|
||||
|
||||
// API types
|
||||
public static final int EGL_OPENGL_ES_API = 0x30A0;
|
||||
public static final int EGL_OPENGL_API = 0x30A2;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* <p>
|
||||
* Initializes the underlying {@link EGLSurface} with a width and height of 1.
|
||||
* This is useful if all you need to use this class for is to query information
|
||||
* from specific API contexts.
|
||||
*
|
||||
* @param renderableType Bitmask indicating which types of client API contexts
|
||||
* the framebuffer config must support.
|
||||
*/
|
||||
public EGLHelper(int renderableType)
|
||||
{
|
||||
this(1, 1, renderableType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param width Width of the underlying {@link EGLSurface}.
|
||||
* @param height Height of the underlying {@link EGLSurface}.
|
||||
* @param renderableType Bitmask indicating which types of client API contexts
|
||||
* the framebuffer config must support.
|
||||
*/
|
||||
public EGLHelper(int width, int height, int renderableType)
|
||||
{
|
||||
// Initialize handle to an EGL display.
|
||||
mEGL = (EGL10) EGLContext.getEGL();
|
||||
mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// If a display is present, initialize EGL.
|
||||
if (mDisplay != EGL10.EGL_NO_DISPLAY)
|
||||
{
|
||||
int[] version = new int[2];
|
||||
if (mEGL.eglInitialize(mDisplay, version))
|
||||
{
|
||||
// Detect supported GL APIs, initialize configs, etc.
|
||||
detect();
|
||||
|
||||
// Create context and surface
|
||||
create(width, height, renderableType);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error("[EGLHelper] Error initializing EGL.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.error("[EGLHelper] Error initializing EGL display.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all resources associated with this helper.
|
||||
* <p>
|
||||
* This should be called whenever this helper is no longer needed.
|
||||
*/
|
||||
public void closeHelper()
|
||||
{
|
||||
mEGL.eglTerminate(mDisplay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets information through EGL.<br/>
|
||||
* <p>
|
||||
* Index 0: Vendor <br/>
|
||||
* Index 1: Version <br/>
|
||||
* Index 2: Renderer <br/>
|
||||
* Index 3: Extensions <br/>
|
||||
*
|
||||
* @return information retrieved through EGL.
|
||||
*/
|
||||
public String[] getEGLInfo()
|
||||
{
|
||||
return new String[]{
|
||||
mGL.glGetString(GL10.GL_VENDOR),
|
||||
mGL.glGetString(GL10.GL_VERSION),
|
||||
mGL.glGetString(GL10.GL_RENDERER),
|
||||
mGL.glGetString(GL10.GL_EXTENSIONS),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this device supports OpenGL.
|
||||
*
|
||||
* @return true if this device supports OpenGL; false otherwise.
|
||||
*/
|
||||
public boolean supportsOpenGL()
|
||||
{
|
||||
return supportGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this device supports OpenGL ES 2.
|
||||
* <br/>
|
||||
* Note that if this returns true, then OpenGL ES 1 is also supported.
|
||||
*
|
||||
* @return true if this device supports OpenGL ES 2; false otherwise.
|
||||
*/
|
||||
public boolean supportsGLES2()
|
||||
{
|
||||
return supportGLES2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this device supports OpenGL ES 3.
|
||||
* <br/>
|
||||
* Note that if this returns true, then OpenGL ES 1 and 2 are also supported.
|
||||
*
|
||||
* @return true if this device supports OpenGL ES 3; false otherwise.
|
||||
*/
|
||||
public boolean supportsGLES3()
|
||||
{
|
||||
return supportGLES3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGL10} instance.
|
||||
*
|
||||
* @return the underlying {@link EGL10} instance.
|
||||
*/
|
||||
public EGL10 getEGL()
|
||||
{
|
||||
return mEGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link GL10} instance.
|
||||
*
|
||||
* @return the underlying {@link GL10} instance.
|
||||
*/
|
||||
public GL10 getGL()
|
||||
{
|
||||
return mGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLDisplay}.
|
||||
*
|
||||
* @return the underlying {@link EGLDisplay}
|
||||
*/
|
||||
public EGLDisplay getDisplay()
|
||||
{
|
||||
return mDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all supported framebuffer configurations for this device.
|
||||
*
|
||||
* @return all supported framebuffer configurations for this device.
|
||||
*/
|
||||
public EGLConfig[] getConfigs()
|
||||
{
|
||||
return mEGLConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLContext}.
|
||||
*
|
||||
* @return the underlying {@link EGLContext}.
|
||||
*/
|
||||
public EGLContext getContext()
|
||||
{
|
||||
return mEGLContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLSurface}.
|
||||
*
|
||||
* @return the underlying {@link EGLSurface}.
|
||||
*/
|
||||
public EGLSurface getSurface()
|
||||
{
|
||||
return mEGLSurface;
|
||||
}
|
||||
|
||||
// Detects the specific kind of GL modes that are supported
|
||||
private boolean detect()
|
||||
{
|
||||
// Get total number of configs available.
|
||||
int[] numConfigs = new int[1];
|
||||
if (!mEGL.eglGetConfigs(mDisplay, null, 0, numConfigs))
|
||||
{
|
||||
Log.error("[EGLHelper] Error retrieving number of EGL configs available.");
|
||||
return false;
|
||||
/**
|
||||
* Constructor
|
||||
* <p>
|
||||
* Initializes the underlying {@link EGLSurface} with a width and height of 1.
|
||||
* This is useful if all you need to use this class for is to query information
|
||||
* from specific API contexts.
|
||||
*
|
||||
* @param renderableType Bitmask indicating which types of client API contexts
|
||||
* the framebuffer config must support.
|
||||
*/
|
||||
public EGLHelper(int renderableType) {
|
||||
this(1, 1, renderableType);
|
||||
}
|
||||
|
||||
// Now get all the configurations
|
||||
mEGLConfigs = new EGLConfig[numConfigs[0]];
|
||||
if (!mEGL.eglGetConfigs(mDisplay, mEGLConfigs, mEGLConfigs.length, numConfigs))
|
||||
{
|
||||
Log.error("[EGLHelper] Error retrieving all EGL configs.");
|
||||
return false;
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param width Width of the underlying {@link EGLSurface}.
|
||||
* @param height Height of the underlying {@link EGLSurface}.
|
||||
* @param renderableType Bitmask indicating which types of client API contexts
|
||||
* the framebuffer config must support.
|
||||
*/
|
||||
public EGLHelper(int width, int height, int renderableType) {
|
||||
// Initialize handle to an EGL display.
|
||||
mEGL = (EGL10) EGLContext.getEGL();
|
||||
mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// If a display is present, initialize EGL.
|
||||
if (mDisplay != EGL10.EGL_NO_DISPLAY) {
|
||||
int[] version = new int[2];
|
||||
if (mEGL.eglInitialize(mDisplay, version)) {
|
||||
// Detect supported GL APIs, initialize configs, etc.
|
||||
detect();
|
||||
|
||||
// Create context and surface
|
||||
create(width, height, renderableType);
|
||||
} else {
|
||||
Log.error("[EGLHelper] Error initializing EGL.");
|
||||
}
|
||||
} else {
|
||||
Log.error("[EGLHelper] Error initializing EGL display.");
|
||||
}
|
||||
}
|
||||
|
||||
for (EGLConfig mEGLConfig : mEGLConfigs)
|
||||
{
|
||||
int[] attribVal = new int[1];
|
||||
boolean ret =
|
||||
mEGL.eglGetConfigAttrib(mDisplay, mEGLConfig, EGL10.EGL_RENDERABLE_TYPE, attribVal);
|
||||
if (ret)
|
||||
{
|
||||
if ((attribVal[0] & EGL_OPENGL_BIT) != 0)
|
||||
supportGL = true;
|
||||
|
||||
if ((attribVal[0] & EGL_OPENGL_ES2_BIT) != 0)
|
||||
supportGLES2 = true;
|
||||
|
||||
if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0)
|
||||
supportGLES3 = true;
|
||||
}
|
||||
/**
|
||||
* Releases all resources associated with this helper.
|
||||
* <p>
|
||||
* This should be called whenever this helper is no longer needed.
|
||||
*/
|
||||
public void closeHelper() {
|
||||
mEGL.eglTerminate(mDisplay);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates the context and surface.
|
||||
private void create(int width, int height, int renderableType)
|
||||
{
|
||||
int[] attribs = {
|
||||
EGL10.EGL_WIDTH, width,
|
||||
EGL10.EGL_HEIGHT, height,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
|
||||
// Initially we just assume GLES2 will be the default context.
|
||||
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
int[] ctx_attribs = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
|
||||
// Determine the type of context that will be created
|
||||
// and change the attribute arrays accordingly.
|
||||
switch (renderableType)
|
||||
{
|
||||
case EGL_OPENGL_ES_BIT:
|
||||
ctx_attribs[1] = 1;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_BIT:
|
||||
ctx_attribs[0] = EGL10.EGL_NONE;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_ES3_BIT_KHR:
|
||||
ctx_attribs[1] = 3;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_ES2_BIT:
|
||||
default: // Fall-back to GLES 2.
|
||||
ctx_attribs[1] = 2;
|
||||
break;
|
||||
/**
|
||||
* Gets information through EGL.<br/>
|
||||
* <p>
|
||||
* Index 0: Vendor <br/>
|
||||
* Index 1: Version <br/>
|
||||
* Index 2: Renderer <br/>
|
||||
* Index 3: Extensions <br/>
|
||||
*
|
||||
* @return information retrieved through EGL.
|
||||
*/
|
||||
public String[] getEGLInfo() {
|
||||
return new String[]{
|
||||
mGL.glGetString(GL10.GL_VENDOR),
|
||||
mGL.glGetString(GL10.GL_VERSION),
|
||||
mGL.glGetString(GL10.GL_RENDERER),
|
||||
mGL.glGetString(GL10.GL_EXTENSIONS),
|
||||
};
|
||||
}
|
||||
if (renderableType == EGL_OPENGL_BIT)
|
||||
NativeLibrary.eglBindAPI(EGL_OPENGL_API);
|
||||
else
|
||||
NativeLibrary.eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
mEGLContext =
|
||||
mEGL.eglCreateContext(mDisplay, mEGLConfigs[0], EGL10.EGL_NO_CONTEXT, ctx_attribs);
|
||||
mEGLSurface = mEGL.eglCreatePbufferSurface(mDisplay, mEGLConfigs[0], attribs);
|
||||
mEGL.eglMakeCurrent(mDisplay, mEGLSurface, mEGLSurface, mEGLContext);
|
||||
mGL = (GL10) mEGLContext.getGL();
|
||||
}
|
||||
/**
|
||||
* Whether or not this device supports OpenGL.
|
||||
*
|
||||
* @return true if this device supports OpenGL; false otherwise.
|
||||
*/
|
||||
public boolean supportsOpenGL() {
|
||||
return supportGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GL10#glGetString(int)}
|
||||
* <p>
|
||||
* Accepts the following constants:
|
||||
* <ul>
|
||||
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
||||
* <li>GL_VERSION - Version or release number.</li>
|
||||
* <li>GL_RENDERER - Name of the renderer</li>
|
||||
* <li>GL_SHADING_LANGUAGE_VERSION - Version or release number of the shading language </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param glEnum A symbolic constant within {@link GL10}.
|
||||
* @return the string information represented by {@code glEnum}.
|
||||
*/
|
||||
public String glGetString(int glEnum)
|
||||
{
|
||||
return mGL.glGetString(glEnum);
|
||||
}
|
||||
/**
|
||||
* Whether or not this device supports OpenGL ES 2.
|
||||
* <br/>
|
||||
* Note that if this returns true, then OpenGL ES 1 is also supported.
|
||||
*
|
||||
* @return true if this device supports OpenGL ES 2; false otherwise.
|
||||
*/
|
||||
public boolean supportsGLES2() {
|
||||
return supportGLES2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GLES30#glGetStringi(int, int)}
|
||||
* <p>
|
||||
* Accepts the following constants:
|
||||
* <ul>
|
||||
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
||||
* <li>GL_VERSION - Version or release number.</li>
|
||||
* <li>GL_RENDERER - Name of the renderer</li>
|
||||
* <li>GL_SHADING_LANGUAGE_VERSION - Version or release number of the shading language </li>
|
||||
* <li>GL_EXTENSIONS - Extension string supported by the implementation at {@code index}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param glEnum A symbolic GL constant
|
||||
* @param index The index of the string to return.
|
||||
* @return the string information represented by {@code glEnum} and {@code index}.
|
||||
*/
|
||||
public String glGetStringi(int glEnum, int index)
|
||||
{
|
||||
return GLES30.glGetStringi(glEnum, index);
|
||||
}
|
||||
/**
|
||||
* Whether or not this device supports OpenGL ES 3.
|
||||
* <br/>
|
||||
* Note that if this returns true, then OpenGL ES 1 and 2 are also supported.
|
||||
*
|
||||
* @return true if this device supports OpenGL ES 3; false otherwise.
|
||||
*/
|
||||
public boolean supportsGLES3() {
|
||||
return supportGLES3;
|
||||
}
|
||||
|
||||
public boolean SupportsExtension(String extension)
|
||||
{
|
||||
int[] num_ext = new int[1];
|
||||
GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, num_ext, 0);
|
||||
/**
|
||||
* Gets the underlying {@link EGL10} instance.
|
||||
*
|
||||
* @return the underlying {@link EGL10} instance.
|
||||
*/
|
||||
public EGL10 getEGL() {
|
||||
return mEGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link GL10} instance.
|
||||
*
|
||||
* @return the underlying {@link GL10} instance.
|
||||
*/
|
||||
public GL10 getGL() {
|
||||
return mGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLDisplay}.
|
||||
*
|
||||
* @return the underlying {@link EGLDisplay}
|
||||
*/
|
||||
public EGLDisplay getDisplay() {
|
||||
return mDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all supported framebuffer configurations for this device.
|
||||
*
|
||||
* @return all supported framebuffer configurations for this device.
|
||||
*/
|
||||
public EGLConfig[] getConfigs() {
|
||||
return mEGLConfigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLContext}.
|
||||
*
|
||||
* @return the underlying {@link EGLContext}.
|
||||
*/
|
||||
public EGLContext getContext() {
|
||||
return mEGLContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the underlying {@link EGLSurface}.
|
||||
*
|
||||
* @return the underlying {@link EGLSurface}.
|
||||
*/
|
||||
public EGLSurface getSurface() {
|
||||
return mEGLSurface;
|
||||
}
|
||||
|
||||
// Detects the specific kind of GL modes that are supported
|
||||
private boolean detect() {
|
||||
// Get total number of configs available.
|
||||
int[] numConfigs = new int[1];
|
||||
if (!mEGL.eglGetConfigs(mDisplay, null, 0, numConfigs)) {
|
||||
Log.error("[EGLHelper] Error retrieving number of EGL configs available.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now get all the configurations
|
||||
mEGLConfigs = new EGLConfig[numConfigs[0]];
|
||||
if (!mEGL.eglGetConfigs(mDisplay, mEGLConfigs, mEGLConfigs.length, numConfigs)) {
|
||||
Log.error("[EGLHelper] Error retrieving all EGL configs.");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (EGLConfig mEGLConfig : mEGLConfigs) {
|
||||
int[] attribVal = new int[1];
|
||||
boolean ret =
|
||||
mEGL.eglGetConfigAttrib(mDisplay, mEGLConfig, EGL10.EGL_RENDERABLE_TYPE, attribVal);
|
||||
if (ret) {
|
||||
if ((attribVal[0] & EGL_OPENGL_BIT) != 0)
|
||||
supportGL = true;
|
||||
|
||||
if ((attribVal[0] & EGL_OPENGL_ES2_BIT) != 0)
|
||||
supportGLES2 = true;
|
||||
|
||||
if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0)
|
||||
supportGLES3 = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_ext[0]; ++i)
|
||||
{
|
||||
String ext = GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i);
|
||||
if (ext.equals(extension))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetVersion()
|
||||
{
|
||||
int[] major = new int[1];
|
||||
int[] minor = new int[1];
|
||||
GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, major, 0);
|
||||
GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, minor, 0);
|
||||
return major[0] * 100 + minor[0] * 10;
|
||||
}
|
||||
// Creates the context and surface.
|
||||
private void create(int width, int height, int renderableType) {
|
||||
int[] attribs = {
|
||||
EGL10.EGL_WIDTH, width,
|
||||
EGL10.EGL_HEIGHT, height,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GL10#glGetIntegerv(int, int[], int)
|
||||
*
|
||||
* @param glEnum A symbolic GL constant.
|
||||
* @return the integer information represented by {@code glEnum}.
|
||||
*/
|
||||
public int glGetInteger(int glEnum)
|
||||
{
|
||||
int[] val = new int[1];
|
||||
mGL.glGetIntegerv(glEnum, val, 0);
|
||||
return val[0];
|
||||
}
|
||||
// Initially we just assume GLES2 will be the default context.
|
||||
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||
int[] ctx_attribs = {
|
||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||
EGL10.EGL_NONE
|
||||
};
|
||||
|
||||
// Determine the type of context that will be created
|
||||
// and change the attribute arrays accordingly.
|
||||
switch (renderableType) {
|
||||
case EGL_OPENGL_ES_BIT:
|
||||
ctx_attribs[1] = 1;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_BIT:
|
||||
ctx_attribs[0] = EGL10.EGL_NONE;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_ES3_BIT_KHR:
|
||||
ctx_attribs[1] = 3;
|
||||
break;
|
||||
|
||||
case EGL_OPENGL_ES2_BIT:
|
||||
default: // Fall-back to GLES 2.
|
||||
ctx_attribs[1] = 2;
|
||||
break;
|
||||
}
|
||||
if (renderableType == EGL_OPENGL_BIT)
|
||||
NativeLibrary.eglBindAPI(EGL_OPENGL_API);
|
||||
else
|
||||
NativeLibrary.eglBindAPI(EGL_OPENGL_ES_API);
|
||||
|
||||
mEGLContext =
|
||||
mEGL.eglCreateContext(mDisplay, mEGLConfigs[0], EGL10.EGL_NO_CONTEXT, ctx_attribs);
|
||||
mEGLSurface = mEGL.eglCreatePbufferSurface(mDisplay, mEGLConfigs[0], attribs);
|
||||
mEGL.eglMakeCurrent(mDisplay, mEGLSurface, mEGLSurface, mEGLContext);
|
||||
mGL = (GL10) mEGLContext.getGL();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GL10#glGetString(int)}
|
||||
* <p>
|
||||
* Accepts the following constants:
|
||||
* <ul>
|
||||
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
||||
* <li>GL_VERSION - Version or release number.</li>
|
||||
* <li>GL_RENDERER - Name of the renderer</li>
|
||||
* <li>GL_SHADING_LANGUAGE_VERSION - Version or release number of the shading language </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param glEnum A symbolic constant within {@link GL10}.
|
||||
* @return the string information represented by {@code glEnum}.
|
||||
*/
|
||||
public String glGetString(int glEnum) {
|
||||
return mGL.glGetString(glEnum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GLES30#glGetStringi(int, int)}
|
||||
* <p>
|
||||
* Accepts the following constants:
|
||||
* <ul>
|
||||
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
||||
* <li>GL_VERSION - Version or release number.</li>
|
||||
* <li>GL_RENDERER - Name of the renderer</li>
|
||||
* <li>GL_SHADING_LANGUAGE_VERSION - Version or release number of the shading language </li>
|
||||
* <li>GL_EXTENSIONS - Extension string supported by the implementation at {@code index}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param glEnum A symbolic GL constant
|
||||
* @param index The index of the string to return.
|
||||
* @return the string information represented by {@code glEnum} and {@code index}.
|
||||
*/
|
||||
public String glGetStringi(int glEnum, int index) {
|
||||
return GLES30.glGetStringi(glEnum, index);
|
||||
}
|
||||
|
||||
public boolean SupportsExtension(String extension) {
|
||||
int[] num_ext = new int[1];
|
||||
GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, num_ext, 0);
|
||||
|
||||
for (int i = 0; i < num_ext[0]; ++i) {
|
||||
String ext = GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i);
|
||||
if (ext.equals(extension))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetVersion() {
|
||||
int[] major = new int[1];
|
||||
int[] minor = new int[1];
|
||||
GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, major, 0);
|
||||
GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, minor, 0);
|
||||
return major[0] * 100 + minor[0] * 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified call to {@link GL10#glGetIntegerv(int, int[], int)
|
||||
*
|
||||
* @param glEnum A symbolic GL constant.
|
||||
* @return the integer information represented by {@code glEnum}.
|
||||
*/
|
||||
public int glGetInteger(int glEnum) {
|
||||
int[] val = new int[1];
|
||||
mGL.glGetIntegerv(glEnum, val, 0);
|
||||
return val[0];
|
||||
}
|
||||
}
|
||||
|
@ -15,45 +15,40 @@ import org.citra.citra_android.ui.main.MainPresenter;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public final class FileBrowserHelper
|
||||
{
|
||||
public static void openDirectoryPicker(FragmentActivity activity)
|
||||
{
|
||||
Intent i = new Intent(activity, CustomFilePickerActivity.class);
|
||||
public final class FileBrowserHelper {
|
||||
public static void openDirectoryPicker(FragmentActivity activity) {
|
||||
Intent i = new Intent(activity, CustomFilePickerActivity.class);
|
||||
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
|
||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
|
||||
Environment.getExternalStorageDirectory().getPath());
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
|
||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
|
||||
Environment.getExternalStorageDirectory().getPath());
|
||||
|
||||
activity.startActivityForResult(i, MainPresenter.REQUEST_ADD_DIRECTORY);
|
||||
}
|
||||
|
||||
public static void openFilePicker(FragmentActivity activity, int requestCode)
|
||||
{
|
||||
Intent i = new Intent(activity, CustomFilePickerActivity.class);
|
||||
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_FILE);
|
||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
|
||||
Environment.getExternalStorageDirectory().getPath());
|
||||
|
||||
activity.startActivityForResult(i, requestCode);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getSelectedDirectory(Intent result)
|
||||
{
|
||||
// Use the provided utility method to parse the result
|
||||
List<Uri> files = Utils.getSelectedFilesFromResult(result);
|
||||
if (!files.isEmpty())
|
||||
{
|
||||
File file = Utils.getFileForUri(files.get(0));
|
||||
return file.getAbsolutePath();
|
||||
activity.startActivityForResult(i, MainPresenter.REQUEST_ADD_DIRECTORY);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public static void openFilePicker(FragmentActivity activity, int requestCode) {
|
||||
Intent i = new Intent(activity, CustomFilePickerActivity.class);
|
||||
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, false);
|
||||
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_FILE);
|
||||
i.putExtra(FilePickerActivity.EXTRA_START_PATH,
|
||||
Environment.getExternalStorageDirectory().getPath());
|
||||
|
||||
activity.startActivityForResult(i, requestCode);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getSelectedDirectory(Intent result) {
|
||||
// Use the provided utility method to parse the result
|
||||
List<Uri> files = Utils.getSelectedFilesFromResult(result);
|
||||
if (!files.isEmpty()) {
|
||||
File file = Utils.getFileForUri(files.get(0));
|
||||
return file.getAbsolutePath();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -10,21 +10,18 @@ import org.citra.citra_android.NativeLibrary;
|
||||
|
||||
import java.nio.IntBuffer;
|
||||
|
||||
public class GameBannerRequestHandler extends RequestHandler
|
||||
{
|
||||
@Override
|
||||
public boolean canHandleRequest(Request data)
|
||||
{
|
||||
return "iso".equals(data.uri.getScheme());
|
||||
}
|
||||
public class GameBannerRequestHandler extends RequestHandler {
|
||||
@Override
|
||||
public boolean canHandleRequest(Request data) {
|
||||
return "iso".equals(data.uri.getScheme());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result load(Request request, int networkPolicy)
|
||||
{
|
||||
String url = request.uri.getHost() + request.uri.getPath();
|
||||
int[] vector = NativeLibrary.GetBanner(url);
|
||||
Bitmap bitmap = Bitmap.createBitmap(48, 48, Bitmap.Config.RGB_565);
|
||||
bitmap.copyPixelsFromBuffer(IntBuffer.wrap(vector));
|
||||
return new Result(bitmap, Picasso.LoadedFrom.DISK);
|
||||
}
|
||||
@Override
|
||||
public Result load(Request request, int networkPolicy) {
|
||||
String url = request.uri.getHost() + request.uri.getPath();
|
||||
int[] vector = NativeLibrary.GetBanner(url);
|
||||
Bitmap bitmap = Bitmap.createBitmap(48, 48, Bitmap.Config.RGB_565);
|
||||
bitmap.copyPixelsFromBuffer(IntBuffer.wrap(vector));
|
||||
return new Result(bitmap, Picasso.LoadedFrom.DISK);
|
||||
}
|
||||
}
|
||||
|
@ -19,143 +19,116 @@ import org.citra.citra_android.services.USBPermService;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Java_GCAdapter
|
||||
{
|
||||
public static UsbManager manager;
|
||||
static byte[] controller_payload = new byte[37];
|
||||
public class Java_GCAdapter {
|
||||
public static UsbManager manager;
|
||||
static byte[] controller_payload = new byte[37];
|
||||
|
||||
static UsbDeviceConnection usb_con;
|
||||
static UsbInterface usb_intf;
|
||||
static UsbEndpoint usb_in;
|
||||
static UsbEndpoint usb_out;
|
||||
static UsbDeviceConnection usb_con;
|
||||
static UsbInterface usb_intf;
|
||||
static UsbEndpoint usb_in;
|
||||
static UsbEndpoint usb_out;
|
||||
|
||||
private static void RequestPermission()
|
||||
{
|
||||
Context context = NativeLibrary.sEmulationActivity.get();
|
||||
if (context != null)
|
||||
{
|
||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
||||
{
|
||||
UsbDevice dev = pair.getValue();
|
||||
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e)
|
||||
{
|
||||
if (!manager.hasPermission(dev))
|
||||
{
|
||||
Intent intent = new Intent();
|
||||
PendingIntent pend_intent;
|
||||
intent.setClass(context, USBPermService.class);
|
||||
pend_intent = PendingIntent.getService(context, 0, intent, 0);
|
||||
manager.requestPermission(dev, pend_intent);
|
||||
}
|
||||
private static void RequestPermission() {
|
||||
Context context = NativeLibrary.sEmulationActivity.get();
|
||||
if (context != null) {
|
||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) {
|
||||
UsbDevice dev = pair.getValue();
|
||||
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) {
|
||||
if (!manager.hasPermission(dev)) {
|
||||
Intent intent = new Intent();
|
||||
PendingIntent pend_intent;
|
||||
intent.setClass(context, USBPermService.class);
|
||||
pend_intent = PendingIntent.getService(context, 0, intent, 0);
|
||||
manager.requestPermission(dev, pend_intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.warning("Cannot request GameCube Adapter permission as EmulationActivity is null.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.warning("Cannot request GameCube Adapter permission as EmulationActivity is null.");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Shutdown()
|
||||
{
|
||||
usb_con.close();
|
||||
}
|
||||
|
||||
public static int GetFD()
|
||||
{
|
||||
return usb_con.getFileDescriptor();
|
||||
}
|
||||
|
||||
public static boolean QueryAdapter()
|
||||
{
|
||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
||||
{
|
||||
UsbDevice dev = pair.getValue();
|
||||
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e)
|
||||
{
|
||||
if (manager.hasPermission(dev))
|
||||
return true;
|
||||
else
|
||||
RequestPermission();
|
||||
}
|
||||
public static void Shutdown() {
|
||||
usb_con.close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void InitAdapter()
|
||||
{
|
||||
byte[] init = {0x13};
|
||||
usb_con.bulkTransfer(usb_in, init, init.length, 0);
|
||||
}
|
||||
public static int GetFD() {
|
||||
return usb_con.getFileDescriptor();
|
||||
}
|
||||
|
||||
public static int Input()
|
||||
{
|
||||
return usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 16);
|
||||
}
|
||||
|
||||
public static int Output(byte[] rumble)
|
||||
{
|
||||
return usb_con.bulkTransfer(usb_out, rumble, 5, 16);
|
||||
}
|
||||
|
||||
public static boolean OpenAdapter()
|
||||
{
|
||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
||||
{
|
||||
UsbDevice dev = pair.getValue();
|
||||
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e)
|
||||
{
|
||||
if (manager.hasPermission(dev))
|
||||
{
|
||||
usb_con = manager.openDevice(dev);
|
||||
|
||||
Log.info("GCAdapter: Number of configurations: " + dev.getConfigurationCount());
|
||||
Log.info("GCAdapter: Number of interfaces: " + dev.getInterfaceCount());
|
||||
|
||||
if (dev.getConfigurationCount() > 0 && dev.getInterfaceCount() > 0)
|
||||
{
|
||||
UsbConfiguration conf = dev.getConfiguration(0);
|
||||
usb_intf = conf.getInterface(0);
|
||||
usb_con.claimInterface(usb_intf, true);
|
||||
|
||||
Log.info("GCAdapter: Number of endpoints: " + usb_intf.getEndpointCount());
|
||||
|
||||
if (usb_intf.getEndpointCount() == 2)
|
||||
{
|
||||
for (int i = 0; i < usb_intf.getEndpointCount(); ++i)
|
||||
if (usb_intf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
|
||||
usb_in = usb_intf.getEndpoint(i);
|
||||
public static boolean QueryAdapter() {
|
||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) {
|
||||
UsbDevice dev = pair.getValue();
|
||||
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) {
|
||||
if (manager.hasPermission(dev))
|
||||
return true;
|
||||
else
|
||||
usb_out = usb_intf.getEndpoint(i);
|
||||
|
||||
InitAdapter();
|
||||
return true;
|
||||
RequestPermission();
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_con.releaseInterface(usb_intf);
|
||||
}
|
||||
}
|
||||
|
||||
final Activity emulationActivity = NativeLibrary.sEmulationActivity.get();
|
||||
if (emulationActivity != null)
|
||||
{
|
||||
emulationActivity.runOnUiThread(() -> Toast.makeText(emulationActivity,
|
||||
"GameCube Adapter couldn't be opened. Please re-plug the device.",
|
||||
Toast.LENGTH_LONG).show());
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.warning("Cannot show toast for GameCube Adapter failure.");
|
||||
}
|
||||
usb_con.close();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void InitAdapter() {
|
||||
byte[] init = {0x13};
|
||||
usb_con.bulkTransfer(usb_in, init, init.length, 0);
|
||||
}
|
||||
|
||||
public static int Input() {
|
||||
return usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 16);
|
||||
}
|
||||
|
||||
public static int Output(byte[] rumble) {
|
||||
return usb_con.bulkTransfer(usb_out, rumble, 5, 16);
|
||||
}
|
||||
|
||||
public static boolean OpenAdapter() {
|
||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet()) {
|
||||
UsbDevice dev = pair.getValue();
|
||||
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) {
|
||||
if (manager.hasPermission(dev)) {
|
||||
usb_con = manager.openDevice(dev);
|
||||
|
||||
Log.info("GCAdapter: Number of configurations: " + dev.getConfigurationCount());
|
||||
Log.info("GCAdapter: Number of interfaces: " + dev.getInterfaceCount());
|
||||
|
||||
if (dev.getConfigurationCount() > 0 && dev.getInterfaceCount() > 0) {
|
||||
UsbConfiguration conf = dev.getConfiguration(0);
|
||||
usb_intf = conf.getInterface(0);
|
||||
usb_con.claimInterface(usb_intf, true);
|
||||
|
||||
Log.info("GCAdapter: Number of endpoints: " + usb_intf.getEndpointCount());
|
||||
|
||||
if (usb_intf.getEndpointCount() == 2) {
|
||||
for (int i = 0; i < usb_intf.getEndpointCount(); ++i)
|
||||
if (usb_intf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
|
||||
usb_in = usb_intf.getEndpoint(i);
|
||||
else
|
||||
usb_out = usb_intf.getEndpoint(i);
|
||||
|
||||
InitAdapter();
|
||||
return true;
|
||||
} else {
|
||||
usb_con.releaseInterface(usb_intf);
|
||||
}
|
||||
}
|
||||
|
||||
final Activity emulationActivity = NativeLibrary.sEmulationActivity.get();
|
||||
if (emulationActivity != null) {
|
||||
emulationActivity.runOnUiThread(() -> Toast.makeText(emulationActivity,
|
||||
"GameCube Adapter couldn't be opened. Please re-plug the device.",
|
||||
Toast.LENGTH_LONG).show());
|
||||
} else {
|
||||
Log.warning("Cannot show toast for GameCube Adapter failure.");
|
||||
}
|
||||
usb_con.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -7,47 +7,37 @@ import org.citra.citra_android.BuildConfig;
|
||||
* with the same TAG automatically provided. Also no-ops VERBOSE and DEBUG log
|
||||
* levels in release builds.
|
||||
*/
|
||||
public final class Log
|
||||
{
|
||||
private static final String TAG = "Citra Frontend";
|
||||
public final class Log {
|
||||
private static final String TAG = "Citra Frontend";
|
||||
|
||||
private Log()
|
||||
{
|
||||
}
|
||||
|
||||
public static void verbose(String message)
|
||||
{
|
||||
if (BuildConfig.DEBUG)
|
||||
{
|
||||
android.util.Log.v(TAG, message);
|
||||
private Log() {
|
||||
}
|
||||
}
|
||||
|
||||
public static void debug(String message)
|
||||
{
|
||||
if (BuildConfig.DEBUG)
|
||||
{
|
||||
android.util.Log.d(TAG, message);
|
||||
public static void verbose(String message) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
android.util.Log.v(TAG, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void info(String message)
|
||||
{
|
||||
android.util.Log.i(TAG, message);
|
||||
}
|
||||
public static void debug(String message) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
android.util.Log.d(TAG, message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void warning(String message)
|
||||
{
|
||||
android.util.Log.w(TAG, message);
|
||||
}
|
||||
public static void info(String message) {
|
||||
android.util.Log.i(TAG, message);
|
||||
}
|
||||
|
||||
public static void error(String message)
|
||||
{
|
||||
android.util.Log.e(TAG, message);
|
||||
}
|
||||
public static void warning(String message) {
|
||||
android.util.Log.w(TAG, message);
|
||||
}
|
||||
|
||||
public static void wtf(String message)
|
||||
{
|
||||
android.util.Log.wtf(TAG, message);
|
||||
}
|
||||
public static void error(String message) {
|
||||
android.util.Log.e(TAG, message);
|
||||
}
|
||||
|
||||
public static void wtf(String message) {
|
||||
android.util.Log.wtf(TAG, message);
|
||||
}
|
||||
}
|
||||
|
@ -14,59 +14,51 @@ import org.citra.citra_android.R;
|
||||
|
||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||
|
||||
public class PermissionsHandler
|
||||
{
|
||||
public static final int REQUEST_CODE_WRITE_PERMISSION = 500;
|
||||
public class PermissionsHandler {
|
||||
public static final int REQUEST_CODE_WRITE_PERMISSION = 500;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public static boolean checkWritePermission(final FragmentActivity activity)
|
||||
{
|
||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
|
||||
{
|
||||
return true;
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public static boolean checkWritePermission(final FragmentActivity activity) {
|
||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int hasWritePermission = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
|
||||
|
||||
if (hasWritePermission != PackageManager.PERMISSION_GRANTED) {
|
||||
if (activity.shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE)) {
|
||||
showMessageOKCancel(activity, activity.getString(R.string.write_permission_needed),
|
||||
(dialog, which) -> activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
|
||||
REQUEST_CODE_WRITE_PERMISSION));
|
||||
return false;
|
||||
}
|
||||
|
||||
activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
|
||||
REQUEST_CODE_WRITE_PERMISSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int hasWritePermission = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
|
||||
public static boolean hasWriteAccess(Context context) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
int hasWritePermission = ContextCompat.checkSelfPermission(context, WRITE_EXTERNAL_STORAGE);
|
||||
return hasWritePermission == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
if (hasWritePermission != PackageManager.PERMISSION_GRANTED)
|
||||
{
|
||||
if (activity.shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE))
|
||||
{
|
||||
showMessageOKCancel(activity, activity.getString(R.string.write_permission_needed),
|
||||
(dialog, which) -> activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
|
||||
REQUEST_CODE_WRITE_PERMISSION));
|
||||
return false;
|
||||
}
|
||||
|
||||
activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
|
||||
REQUEST_CODE_WRITE_PERMISSION);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean hasWriteAccess(Context context)
|
||||
{
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
{
|
||||
int hasWritePermission = ContextCompat.checkSelfPermission(context, WRITE_EXTERNAL_STORAGE);
|
||||
return hasWritePermission == PackageManager.PERMISSION_GRANTED;
|
||||
private static void showMessageOKCancel(final FragmentActivity activity, String message,
|
||||
DialogInterface.OnClickListener okListener) {
|
||||
new AlertDialog.Builder(activity)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, okListener)
|
||||
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) ->
|
||||
Toast.makeText(activity, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show())
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void showMessageOKCancel(final FragmentActivity activity, String message,
|
||||
DialogInterface.OnClickListener okListener)
|
||||
{
|
||||
new AlertDialog.Builder(activity)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(android.R.string.ok, okListener)
|
||||
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) ->
|
||||
Toast.makeText(activity, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||
.show())
|
||||
.create()
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
@ -11,40 +11,35 @@ import org.citra.citra_android.R;
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
|
||||
public class PicassoUtils
|
||||
{
|
||||
public static void loadGameBanner(ImageView imageView, String screenshotPath, String gamePath)
|
||||
{
|
||||
File file = new File(URI.create(screenshotPath.replaceAll(" ", "%20")));
|
||||
if (file.exists())
|
||||
{
|
||||
// Fill in the view contents.
|
||||
Picasso.with(imageView.getContext())
|
||||
.load(screenshotPath)
|
||||
.fit()
|
||||
.centerCrop()
|
||||
.noFade()
|
||||
.noPlaceholder()
|
||||
.config(Bitmap.Config.RGB_565)
|
||||
.error(R.drawable.no_banner)
|
||||
.into(imageView);
|
||||
public class PicassoUtils {
|
||||
public static void loadGameBanner(ImageView imageView, String screenshotPath, String gamePath) {
|
||||
File file = new File(URI.create(screenshotPath.replaceAll(" ", "%20")));
|
||||
if (file.exists()) {
|
||||
// Fill in the view contents.
|
||||
Picasso.with(imageView.getContext())
|
||||
.load(screenshotPath)
|
||||
.fit()
|
||||
.centerCrop()
|
||||
.noFade()
|
||||
.noPlaceholder()
|
||||
.config(Bitmap.Config.RGB_565)
|
||||
.error(R.drawable.no_banner)
|
||||
.into(imageView);
|
||||
} else {
|
||||
Picasso picassoInstance = new Picasso.Builder(imageView.getContext())
|
||||
.addRequestHandler(new GameBannerRequestHandler())
|
||||
.build();
|
||||
|
||||
picassoInstance
|
||||
.load(Uri.parse("iso:/" + gamePath))
|
||||
.fit()
|
||||
.noFade()
|
||||
.noPlaceholder()
|
||||
.config(Bitmap.Config.RGB_565)
|
||||
.error(R.drawable.no_banner)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Picasso picassoInstance = new Picasso.Builder(imageView.getContext())
|
||||
.addRequestHandler(new GameBannerRequestHandler())
|
||||
.build();
|
||||
|
||||
picassoInstance
|
||||
.load(Uri.parse("iso:/" + gamePath))
|
||||
.fit()
|
||||
.noFade()
|
||||
.noPlaceholder()
|
||||
.config(Bitmap.Config.RGB_565)
|
||||
.error(R.drawable.no_banner)
|
||||
.into(imageView);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,279 +23,239 @@ import java.util.Set;
|
||||
* A HashMap<String, SettingSection> that constructs a new SettingSection instead of returning null
|
||||
* when getting a key not already in the map
|
||||
*/
|
||||
final class SettingsSectionMap extends HashMap<String, SettingSection>
|
||||
{
|
||||
@Override
|
||||
public SettingSection get(Object key)
|
||||
{
|
||||
if (!(key instanceof String))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
final class SettingsSectionMap extends HashMap<String, SettingSection> {
|
||||
@Override
|
||||
public SettingSection get(Object key) {
|
||||
if (!(key instanceof String)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String stringKey = (String) key;
|
||||
String stringKey = (String) key;
|
||||
|
||||
if (!super.containsKey(stringKey))
|
||||
{
|
||||
SettingSection section = new SettingSection(stringKey);
|
||||
super.put(stringKey, section);
|
||||
return section;
|
||||
if (!super.containsKey(stringKey)) {
|
||||
SettingSection section = new SettingSection(stringKey);
|
||||
super.put(stringKey, section);
|
||||
return section;
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains static methods for interacting with .ini files in which settings are stored.
|
||||
*/
|
||||
public final class SettingsFile
|
||||
{
|
||||
public static final int SETTINGS_DOLPHIN = 0;
|
||||
public final class SettingsFile {
|
||||
public static final int SETTINGS_DOLPHIN = 0;
|
||||
|
||||
public static final String FILE_NAME_CONFIG = "config";
|
||||
public static final String FILE_NAME_CONFIG = "config";
|
||||
|
||||
public static final String SECTION_CONTROLS = "Controls";
|
||||
public static final String SECTION_CORE = "Core";
|
||||
public static final String SECTION_RENDERER = "Renderer";
|
||||
public static final String SECTION_LAYOUT = "Layout";
|
||||
public static final String SECTION_AUDIO = "Audio";
|
||||
public static final String SECTION_SYSTEM = "System";
|
||||
public static final String SECTION_CAMERA = "Camera";
|
||||
public static final String SECTION_MISC = "Miscellaneous";
|
||||
public static final String SECTION_DEBUGGING = "Debugging";
|
||||
public static final String SECTION_WEBSERVICE = "WebService";
|
||||
public static final String SECTION_CONTROLS = "Controls";
|
||||
public static final String SECTION_CORE = "Core";
|
||||
public static final String SECTION_RENDERER = "Renderer";
|
||||
public static final String SECTION_LAYOUT = "Layout";
|
||||
public static final String SECTION_AUDIO = "Audio";
|
||||
public static final String SECTION_SYSTEM = "System";
|
||||
public static final String SECTION_CAMERA = "Camera";
|
||||
public static final String SECTION_MISC = "Miscellaneous";
|
||||
public static final String SECTION_DEBUGGING = "Debugging";
|
||||
public static final String SECTION_WEBSERVICE = "WebService";
|
||||
|
||||
public static final String KEY_CPU_JIT = "use_cpu_jit";
|
||||
public static final String KEY_CPU_JIT = "use_cpu_jit";
|
||||
|
||||
public static final String KEY_HW_RENDERER = "use_hw_renderer";
|
||||
public static final String KEY_HW_SHADER = "use_hw_shader";
|
||||
public static final String KEY_SHADERS_ACCURATE_MUL = "shaders_accurate_mul";
|
||||
public static final String KEY_SHADERS_ACCURATE_GS = "shaders_accurate_gs";
|
||||
public static final String KEY_USE_SHADER_JIT = "use_shader_jit";
|
||||
public static final String KEY_USE_VSYNC = "use_vsync";
|
||||
public static final String KEY_RESOLUTION_FACTOR = "resolution_factor";
|
||||
public static final String KEY_FRAME_LIMIT_ENABLED = "use_frame_limit";
|
||||
public static final String KEY_FRAME_LIMIT = "frame_limit";
|
||||
public static final String KEY_BACKGROUND_RED = "bg_red";
|
||||
public static final String KEY_BACKGROUND_BLUE = "bg_blue";
|
||||
public static final String KEY_BACKGROUND_GREEN = "bg_green";
|
||||
public static final String KEY_STEREOSCOPY = "toggle_3d";
|
||||
public static final String KEY_FACTOR_3D = "factor_3d";
|
||||
public static final String KEY_HW_RENDERER = "use_hw_renderer";
|
||||
public static final String KEY_HW_SHADER = "use_hw_shader";
|
||||
public static final String KEY_SHADERS_ACCURATE_MUL = "shaders_accurate_mul";
|
||||
public static final String KEY_SHADERS_ACCURATE_GS = "shaders_accurate_gs";
|
||||
public static final String KEY_USE_SHADER_JIT = "use_shader_jit";
|
||||
public static final String KEY_USE_VSYNC = "use_vsync";
|
||||
public static final String KEY_RESOLUTION_FACTOR = "resolution_factor";
|
||||
public static final String KEY_FRAME_LIMIT_ENABLED = "use_frame_limit";
|
||||
public static final String KEY_FRAME_LIMIT = "frame_limit";
|
||||
public static final String KEY_BACKGROUND_RED = "bg_red";
|
||||
public static final String KEY_BACKGROUND_BLUE = "bg_blue";
|
||||
public static final String KEY_BACKGROUND_GREEN = "bg_green";
|
||||
public static final String KEY_STEREOSCOPY = "toggle_3d";
|
||||
public static final String KEY_FACTOR_3D = "factor_3d";
|
||||
|
||||
public static final String KEY_LAYOUT_OPTION = "layout_option";
|
||||
public static final String KEY_SWAP_SCREEN = "swap_screen";
|
||||
public static final String KEY_LAYOUT_OPTION = "layout_option";
|
||||
public static final String KEY_SWAP_SCREEN = "swap_screen";
|
||||
|
||||
public static final String KEY_AUDIO_OUTPUT_ENGINE = "output_engine";
|
||||
public static final String KEY_ENABLE_AUDIO_STRETCHING = "enable_audio_stretching";
|
||||
public static final String KEY_VOLUME = "volume";
|
||||
public static final String KEY_AUDIO_OUTPUT_ENGINE = "output_engine";
|
||||
public static final String KEY_ENABLE_AUDIO_STRETCHING = "enable_audio_stretching";
|
||||
public static final String KEY_VOLUME = "volume";
|
||||
|
||||
public static final String KEY_USE_VIRTUAL_SD = "use_virtual_sd";
|
||||
public static final String KEY_USE_VIRTUAL_SD = "use_virtual_sd";
|
||||
|
||||
public static final String KEY_IS_NEW_3DS = "is_new_3ds";
|
||||
public static final String KEY_REGION_VALUE = "region_value";
|
||||
public static final String KEY_INIT_CLOCK = "init_clock";
|
||||
public static final String KEY_INIT_TIME = "init_time";
|
||||
public static final String KEY_IS_NEW_3DS = "is_new_3ds";
|
||||
public static final String KEY_REGION_VALUE = "region_value";
|
||||
public static final String KEY_INIT_CLOCK = "init_clock";
|
||||
public static final String KEY_INIT_TIME = "init_time";
|
||||
|
||||
public static final String KEY_CAMERA_OUTER_RIGHT_NAME = "camera_outer_right_name";
|
||||
public static final String KEY_CAMERA_OUTER_RIGHT_CONFIG = "camera_outer_right_config";
|
||||
public static final String KEY_CAMERA_OUTER_RIGHT_FLIP = "camera_outer_right_flip";
|
||||
public static final String KEY_CAMERA_OUTER_LEFT_FLIP = "camera_outer_left_flip";
|
||||
public static final String KEY_CAMERA_INNER_NAME = "camera_inner_name";
|
||||
public static final String KEY_CAMERA_INNER_CONFIG = "camera_inner_config";
|
||||
public static final String KEY_CAMERA_INNER_FLIP = "camera_inner_flip";
|
||||
public static final String KEY_CAMERA_OUTER_RIGHT_NAME = "camera_outer_right_name";
|
||||
public static final String KEY_CAMERA_OUTER_RIGHT_CONFIG = "camera_outer_right_config";
|
||||
public static final String KEY_CAMERA_OUTER_RIGHT_FLIP = "camera_outer_right_flip";
|
||||
public static final String KEY_CAMERA_OUTER_LEFT_FLIP = "camera_outer_left_flip";
|
||||
public static final String KEY_CAMERA_INNER_NAME = "camera_inner_name";
|
||||
public static final String KEY_CAMERA_INNER_CONFIG = "camera_inner_config";
|
||||
public static final String KEY_CAMERA_INNER_FLIP = "camera_inner_flip";
|
||||
|
||||
public static final String KEY_LOG_FILTER = "log_filter";
|
||||
public static final String KEY_LOG_FILTER = "log_filter";
|
||||
|
||||
private SettingsFile()
|
||||
{
|
||||
}
|
||||
private SettingsFile() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves
|
||||
* effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it
|
||||
* failed.
|
||||
*
|
||||
* @param fileName The name of the settings file without a path or extension.
|
||||
* @param view The current view.
|
||||
* @return An Observable that emits a HashMap of the file's contents, then completes.
|
||||
*/
|
||||
public static HashMap<String, SettingSection> readFile(final String fileName,
|
||||
SettingsActivityView view)
|
||||
{
|
||||
HashMap<String, SettingSection> sections = new SettingsSectionMap();
|
||||
/**
|
||||
* Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves
|
||||
* effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it
|
||||
* failed.
|
||||
*
|
||||
* @param fileName The name of the settings file without a path or extension.
|
||||
* @param view The current view.
|
||||
* @return An Observable that emits a HashMap of the file's contents, then completes.
|
||||
*/
|
||||
public static HashMap<String, SettingSection> readFile(final String fileName,
|
||||
SettingsActivityView view) {
|
||||
HashMap<String, SettingSection> sections = new SettingsSectionMap();
|
||||
|
||||
File ini = getSettingsFile(fileName);
|
||||
File ini = getSettingsFile(fileName);
|
||||
|
||||
BufferedReader reader = null;
|
||||
BufferedReader reader = null;
|
||||
|
||||
try
|
||||
{
|
||||
reader = new BufferedReader(new FileReader(ini));
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(ini));
|
||||
|
||||
SettingSection current = null;
|
||||
for (String line; (line = reader.readLine()) != null; )
|
||||
{
|
||||
if (line.startsWith("[") && line.endsWith("]"))
|
||||
{
|
||||
current = sectionFromLine(line);
|
||||
sections.put(current.getName(), current);
|
||||
SettingSection current = null;
|
||||
for (String line; (line = reader.readLine()) != null; ) {
|
||||
if (line.startsWith("[") && line.endsWith("]")) {
|
||||
current = sectionFromLine(line);
|
||||
sections.put(current.getName(), current);
|
||||
} else if ((current != null)) {
|
||||
Setting setting = settingFromLine(current, line, fileName);
|
||||
if (setting != null) {
|
||||
current.putSetting(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
|
||||
view.onSettingsFileNotFound();
|
||||
} catch (IOException e) {
|
||||
Log.error("[SettingsFile] Error reading from: " + fileName + ".ini: " + e.getMessage());
|
||||
view.onSettingsFileNotFound();
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
try {
|
||||
reader.close();
|
||||
} catch (IOException e) {
|
||||
Log.error("[SettingsFile] Error closing: " + fileName + ".ini: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((current != null))
|
||||
{
|
||||
Setting setting = settingFromLine(current, line, fileName);
|
||||
if (setting != null)
|
||||
{
|
||||
current.putSetting(setting);
|
||||
}
|
||||
|
||||
return sections;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error
|
||||
* telling why it failed.
|
||||
*
|
||||
* @param fileName The target filename without a path or extension.
|
||||
* @param sections The HashMap containing the Settings we want to serialize.
|
||||
* @param view The current view.
|
||||
* @return An Observable representing the operation.
|
||||
*/
|
||||
public static void saveFile(final String fileName, final HashMap<String, SettingSection> sections,
|
||||
SettingsActivityView view) {
|
||||
File ini = getSettingsFile(fileName);
|
||||
|
||||
Wini writer = null;
|
||||
try {
|
||||
writer = new Wini(ini);
|
||||
|
||||
Set<String> keySet = sections.keySet();
|
||||
for (String key : keySet) {
|
||||
SettingSection section = sections.get(key);
|
||||
writeSection(writer, section);
|
||||
}
|
||||
writer.store();
|
||||
} catch (IOException e) {
|
||||
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
|
||||
view.showToastMessage("Error saving " + fileName + ".ini: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
|
||||
view.onSettingsFileNotFound();
|
||||
|
||||
@NonNull
|
||||
private static File getSettingsFile(String fileName) {
|
||||
return new File(
|
||||
DirectoryInitializationService.getUserDirectory() + "/config/" + fileName + ".ini");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.error("[SettingsFile] Error reading from: " + fileName + ".ini: " + e.getMessage());
|
||||
view.onSettingsFileNotFound();
|
||||
|
||||
private static SettingSection sectionFromLine(String line) {
|
||||
String sectionName = line.substring(1, line.length() - 1);
|
||||
return new SettingSection(sectionName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (reader != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
reader.close();
|
||||
|
||||
/**
|
||||
* For a line of text, determines what type of data is being represented, and returns
|
||||
* a Setting object containing this data.
|
||||
*
|
||||
* @param current The section currently being parsed by the consuming method.
|
||||
* @param line The line of text being parsed.
|
||||
* @param fileName The name of the ini file the setting is in.
|
||||
* @return A typed Setting containing the key/value contained in the line.
|
||||
*/
|
||||
private static Setting settingFromLine(SettingSection current, String line, String fileName) {
|
||||
String[] splitLine = line.split("=");
|
||||
|
||||
if (splitLine.length != 2) {
|
||||
Log.warning("Skipping invalid config line \"" + line + "\"");
|
||||
return null;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.error("[SettingsFile] Error closing: " + fileName + ".ini: " + e.getMessage());
|
||||
|
||||
String key = splitLine[0].trim();
|
||||
String value = splitLine[1].trim();
|
||||
|
||||
if (value.isEmpty()) {
|
||||
Log.warning("Skipping null value in config line \"" + line + "\"");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
int file = SETTINGS_DOLPHIN;
|
||||
|
||||
try {
|
||||
int valueAsInt = Integer.valueOf(value);
|
||||
|
||||
return new IntSetting(key, current.getName(), file, valueAsInt);
|
||||
} catch (NumberFormatException ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
float valueAsFloat = Float.valueOf(value);
|
||||
|
||||
return new FloatSetting(key, current.getName(), file, valueAsFloat);
|
||||
} catch (NumberFormatException ex) {
|
||||
}
|
||||
|
||||
return new StringSetting(key, current.getName(), file, value);
|
||||
}
|
||||
|
||||
return sections;
|
||||
}
|
||||
/**
|
||||
* Writes the contents of a Section HashMap to disk.
|
||||
*
|
||||
* @param parser A Wini pointed at a file on disk.
|
||||
* @param section A section containing settings to be written to the file.
|
||||
*/
|
||||
private static void writeSection(Wini parser, SettingSection section) {
|
||||
// Write the section header.
|
||||
String header = section.getName();
|
||||
|
||||
/**
|
||||
* Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error
|
||||
* telling why it failed.
|
||||
*
|
||||
* @param fileName The target filename without a path or extension.
|
||||
* @param sections The HashMap containing the Settings we want to serialize.
|
||||
* @param view The current view.
|
||||
* @return An Observable representing the operation.
|
||||
*/
|
||||
public static void saveFile(final String fileName, final HashMap<String, SettingSection> sections,
|
||||
SettingsActivityView view)
|
||||
{
|
||||
File ini = getSettingsFile(fileName);
|
||||
// Write this section's values.
|
||||
HashMap<String, Setting> settings = section.getSettings();
|
||||
Set<String> keySet = settings.keySet();
|
||||
|
||||
Wini writer = null;
|
||||
try
|
||||
{
|
||||
writer = new Wini(ini);
|
||||
|
||||
Set<String> keySet = sections.keySet();
|
||||
for (String key : keySet)
|
||||
{
|
||||
SettingSection section = sections.get(key);
|
||||
writeSection(writer, section);
|
||||
}
|
||||
writer.store();
|
||||
for (String key : keySet) {
|
||||
Setting setting = settings.get(key);
|
||||
parser.put(header, setting.getKey(), setting.getValueAsString());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.getMessage());
|
||||
view.showToastMessage("Error saving " + fileName + ".ini: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static File getSettingsFile(String fileName)
|
||||
{
|
||||
return new File(
|
||||
DirectoryInitializationService.getUserDirectory() + "/config/" + fileName + ".ini");
|
||||
}
|
||||
|
||||
private static SettingSection sectionFromLine(String line)
|
||||
{
|
||||
String sectionName = line.substring(1, line.length() - 1);
|
||||
return new SettingSection(sectionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a line of text, determines what type of data is being represented, and returns
|
||||
* a Setting object containing this data.
|
||||
*
|
||||
* @param current The section currently being parsed by the consuming method.
|
||||
* @param line The line of text being parsed.
|
||||
* @param fileName The name of the ini file the setting is in.
|
||||
* @return A typed Setting containing the key/value contained in the line.
|
||||
*/
|
||||
private static Setting settingFromLine(SettingSection current, String line, String fileName)
|
||||
{
|
||||
String[] splitLine = line.split("=");
|
||||
|
||||
if (splitLine.length != 2)
|
||||
{
|
||||
Log.warning("Skipping invalid config line \"" + line + "\"");
|
||||
return null;
|
||||
}
|
||||
|
||||
String key = splitLine[0].trim();
|
||||
String value = splitLine[1].trim();
|
||||
|
||||
if(value.isEmpty()){
|
||||
Log.warning("Skipping null value in config line \"" + line + "\"");
|
||||
return null;
|
||||
}
|
||||
|
||||
int file = SETTINGS_DOLPHIN;
|
||||
|
||||
try
|
||||
{
|
||||
int valueAsInt = Integer.valueOf(value);
|
||||
|
||||
return new IntSetting(key, current.getName(), file, valueAsInt);
|
||||
}
|
||||
catch (NumberFormatException ex)
|
||||
{
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
float valueAsFloat = Float.valueOf(value);
|
||||
|
||||
return new FloatSetting(key, current.getName(), file, valueAsFloat);
|
||||
}
|
||||
catch (NumberFormatException ex)
|
||||
{
|
||||
}
|
||||
|
||||
return new StringSetting(key, current.getName(), file, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents of a Section HashMap to disk.
|
||||
*
|
||||
* @param parser A Wini pointed at a file on disk.
|
||||
* @param section A section containing settings to be written to the file.
|
||||
*/
|
||||
private static void writeSection(Wini parser, SettingSection section)
|
||||
{
|
||||
// Write the section header.
|
||||
String header = section.getName();
|
||||
|
||||
// Write this section's values.
|
||||
HashMap<String, Setting> settings = section.getSettings();
|
||||
Set<String> keySet = settings.keySet();
|
||||
|
||||
for (String key : keySet)
|
||||
{
|
||||
Setting setting = settings.get(key);
|
||||
parser.put(header, setting.getKey(), setting.getValueAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,25 +7,22 @@ import android.text.TextUtils;
|
||||
|
||||
import org.citra.citra_android.activities.EmulationActivity;
|
||||
|
||||
public final class StartupHandler
|
||||
{
|
||||
public static void HandleInit(FragmentActivity parent)
|
||||
{
|
||||
// Ask the user to grant write permission if it's not already granted
|
||||
PermissionsHandler.checkWritePermission(parent);
|
||||
public final class StartupHandler {
|
||||
public static void HandleInit(FragmentActivity parent) {
|
||||
// Ask the user to grant write permission if it's not already granted
|
||||
PermissionsHandler.checkWritePermission(parent);
|
||||
|
||||
String start_file = "";
|
||||
Bundle extras = parent.getIntent().getExtras();
|
||||
if (extras != null)
|
||||
start_file = extras.getString("AutoStartFile");
|
||||
String start_file = "";
|
||||
Bundle extras = parent.getIntent().getExtras();
|
||||
if (extras != null)
|
||||
start_file = extras.getString("AutoStartFile");
|
||||
|
||||
if (!TextUtils.isEmpty(start_file))
|
||||
{
|
||||
// Start the emulation activity, send the ISO passed in and finish the main activity
|
||||
Intent emulation_intent = new Intent(parent, EmulationActivity.class);
|
||||
emulation_intent.putExtra("SelectedGame", start_file);
|
||||
parent.startActivity(emulation_intent);
|
||||
parent.finish();
|
||||
if (!TextUtils.isEmpty(start_file)) {
|
||||
// Start the emulation activity, send the ISO passed in and finish the main activity
|
||||
Intent emulation_intent = new Intent(parent, EmulationActivity.class);
|
||||
emulation_intent.putExtra("SelectedGame", start_file);
|
||||
parent.startActivity(emulation_intent);
|
||||
parent.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,30 +11,28 @@ import org.citra.citra_android.R;
|
||||
* A simple class that stores references to views so that the GameAdapter doesn't need to
|
||||
* keep calling findViewById(), which is expensive.
|
||||
*/
|
||||
public class GameViewHolder extends RecyclerView.ViewHolder
|
||||
{
|
||||
public ImageView imageScreenshot;
|
||||
public TextView textGameTitle;
|
||||
public TextView textCompany;
|
||||
public class GameViewHolder extends RecyclerView.ViewHolder {
|
||||
public ImageView imageScreenshot;
|
||||
public TextView textGameTitle;
|
||||
public TextView textCompany;
|
||||
|
||||
public String gameId;
|
||||
public String gameId;
|
||||
|
||||
// TODO Not need any of this stuff. Currently only the properties dialog needs it.
|
||||
public String path;
|
||||
public String title;
|
||||
public String description;
|
||||
public int country;
|
||||
public String company;
|
||||
public String screenshotPath;
|
||||
// TODO Not need any of this stuff. Currently only the properties dialog needs it.
|
||||
public String path;
|
||||
public String title;
|
||||
public String description;
|
||||
public int country;
|
||||
public String company;
|
||||
public String screenshotPath;
|
||||
|
||||
public GameViewHolder(View itemView)
|
||||
{
|
||||
super(itemView);
|
||||
public GameViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
itemView.setTag(this);
|
||||
itemView.setTag(this);
|
||||
|
||||
imageScreenshot = itemView.findViewById(R.id.image_game_screen);
|
||||
textGameTitle = itemView.findViewById(R.id.text_game_title);
|
||||
textCompany = itemView.findViewById(R.id.text_company);
|
||||
}
|
||||
imageScreenshot = itemView.findViewById(R.id.image_game_screen);
|
||||
textGameTitle = itemView.findViewById(R.id.text_game_title);
|
||||
textCompany = itemView.findViewById(R.id.text_company);
|
||||
}
|
||||
}
|
||||
|
@ -9,29 +9,27 @@ import android.widget.ImageView;
|
||||
* A simple class that stores references to views so that the GameAdapter doesn't need to
|
||||
* keep calling findViewById(), which is expensive.
|
||||
*/
|
||||
public final class TvGameViewHolder extends Presenter.ViewHolder
|
||||
{
|
||||
public ImageCardView cardParent;
|
||||
public final class TvGameViewHolder extends Presenter.ViewHolder {
|
||||
public ImageCardView cardParent;
|
||||
|
||||
public ImageView imageScreenshot;
|
||||
public ImageView imageScreenshot;
|
||||
|
||||
public String gameId;
|
||||
public String gameId;
|
||||
|
||||
// TODO Not need any of this stuff. Currently only the properties dialog needs it.
|
||||
public String path;
|
||||
public String title;
|
||||
public String description;
|
||||
public int country;
|
||||
public String company;
|
||||
public String screenshotPath;
|
||||
// TODO Not need any of this stuff. Currently only the properties dialog needs it.
|
||||
public String path;
|
||||
public String title;
|
||||
public String description;
|
||||
public int country;
|
||||
public String company;
|
||||
public String screenshotPath;
|
||||
|
||||
public TvGameViewHolder(View itemView)
|
||||
{
|
||||
super(itemView);
|
||||
public TvGameViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
itemView.setTag(this);
|
||||
itemView.setTag(this);
|
||||
|
||||
cardParent = (ImageCardView) itemView;
|
||||
imageScreenshot = cardParent.getMainImageView();
|
||||
}
|
||||
cardParent = (ImageCardView) itemView;
|
||||
imageScreenshot = cardParent.getMainImageView();
|
||||
}
|
||||
}
|
||||
|
@ -4,19 +4,17 @@ import android.support.v17.leanback.widget.ImageCardView;
|
||||
import android.support.v17.leanback.widget.Presenter;
|
||||
import android.view.View;
|
||||
|
||||
public final class TvSettingsViewHolder extends Presenter.ViewHolder
|
||||
{
|
||||
public ImageCardView cardParent;
|
||||
public final class TvSettingsViewHolder extends Presenter.ViewHolder {
|
||||
public ImageCardView cardParent;
|
||||
|
||||
// Determines what action to take when this item is clicked.
|
||||
public int itemId;
|
||||
// Determines what action to take when this item is clicked.
|
||||
public int itemId;
|
||||
|
||||
public TvSettingsViewHolder(View itemView)
|
||||
{
|
||||
super(itemView);
|
||||
public TvSettingsViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
itemView.setTag(this);
|
||||
itemView.setTag(this);
|
||||
|
||||
cardParent = (ImageCardView) itemView;
|
||||
}
|
||||
cardParent = (ImageCardView) itemView;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user