Reformat Android code

This commit is contained in:
riking 2018-08-26 21:37:54 -07:00
parent ab76631a7f
commit 248ee12aed
102 changed files with 11134 additions and 10354 deletions

View File

@ -67,7 +67,8 @@ android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DANDROID_STL=c++_static", "-DCMAKE_BUILD_TYPE=RelWithDebInfo" // , "-DENABLE_GENERIC=ON"
arguments "-DANDROID_STL=c++_static", "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
// , "-DENABLE_GENERIC=ON"
abiFilters "arm64-v8a", "x86_64" //, "armeabi-v7a", "x86"
}
}

View File

@ -11,13 +11,13 @@
android:name="android.software.leanback"
android:required="false"/>
<uses-feature android:glEsVersion="0x00030000" />
<uses-feature android:glEsVersion="0x00030000"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA"/>
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
<application
android:name=".DolphinApplication"
@ -27,7 +27,9 @@
android:supportsRtl="true"
android:isGame="true"
android:banner="@drawable/banner_tv">
<meta-data android:name="android.max_aspect" android:value="2.1" />
<meta-data
android:name="android.max_aspect"
android:value="2.1"/>
<activity
android:name=".ui.main.MainActivity"
@ -67,18 +69,18 @@
android:label="@string/app_name"
android:theme="@style/FilePickerTheme">
<intent-filter>
<action android:name="android.intent.action.GET_CONTENT" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.GET_CONTENT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".activities.AppLinkActivity" >
<activity android:name=".activities.AppLinkActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data
android:host="@string/host"
android:scheme="@string/scheme" />
android:scheme="@string/scheme"/>
</intent-filter>
</activity>
@ -87,11 +89,11 @@
<service
android:name=".services.SyncChannelJobService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
android:permission="android.permission.BIND_JOB_SERVICE"/>
<service
android:name=".services.SyncProgramsJobService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
android:permission="android.permission.BIND_JOB_SERVICE"/>
<provider
android:name="android.support.v4.content.FileProvider"
@ -100,7 +102,7 @@
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/nnf_provider_paths" />
android:resource="@xml/nnf_provider_paths"/>
</provider>
</application>

View File

@ -8,15 +8,15 @@ import org.dolphinemu.dolphinemu.utils.VolleyUtil;
public class DolphinApplication extends Application
{
@Override
public void onCreate()
{
super.onCreate();
@Override
public void onCreate()
{
super.onCreate();
VolleyUtil.init(getApplicationContext());
System.loadLibrary("main");
VolleyUtil.init(getApplicationContext());
System.loadLibrary("main");
if (PermissionsHandler.hasWriteAccess(getApplicationContext()))
DirectoryInitializationService.startService(getApplicationContext());
}
if (PermissionsHandler.hasWriteAccess(getApplicationContext()))
DirectoryInitializationService.startService(getApplicationContext());
}
}

View File

@ -7,13 +7,7 @@
package org.dolphinemu.dolphinemu;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.content.res.AssetManager;
import android.view.Surface;
import android.widget.Toast;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.utils.Log;
@ -26,433 +20,448 @@ import java.lang.ref.WeakReference;
*/
public final class NativeLibrary
{
public static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
public static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
/**
* Button type for use in onTouchEvent
*/
public static final class ButtonType
{
public static final int BUTTON_A = 0;
public static final int BUTTON_B = 1;
public static final int BUTTON_START = 2;
public static final int BUTTON_X = 3;
public static final int BUTTON_Y = 4;
public static final int BUTTON_Z = 5;
public static final int BUTTON_UP = 6;
public static final int BUTTON_DOWN = 7;
public static final int BUTTON_LEFT = 8;
public static final int BUTTON_RIGHT = 9;
public static final int STICK_MAIN = 10;
public static final int STICK_MAIN_UP = 11;
public static final int STICK_MAIN_DOWN = 12;
public static final int STICK_MAIN_LEFT = 13;
public static final int STICK_MAIN_RIGHT = 14;
public static final int STICK_C = 15;
public static final int STICK_C_UP = 16;
public static final int STICK_C_DOWN = 17;
public static final int STICK_C_LEFT = 18;
public static final int STICK_C_RIGHT = 19;
public static final int TRIGGER_L = 20;
public static final int TRIGGER_R = 21;
public static final int WIIMOTE_BUTTON_A = 100;
public static final int WIIMOTE_BUTTON_B = 101;
public static final int WIIMOTE_BUTTON_MINUS = 102;
public static final int WIIMOTE_BUTTON_PLUS = 103;
public static final int WIIMOTE_BUTTON_HOME = 104;
public static final int WIIMOTE_BUTTON_1 = 105;
public static final int WIIMOTE_BUTTON_2 = 106;
public static final int WIIMOTE_UP = 107;
public static final int WIIMOTE_DOWN = 108;
public static final int WIIMOTE_LEFT = 109;
public static final int WIIMOTE_RIGHT = 110;
public static final int WIIMOTE_IR = 111;
public static final int WIIMOTE_IR_UP = 112;
public static final int WIIMOTE_IR_DOWN = 113;
public static final int WIIMOTE_IR_LEFT = 114;
public static final int WIIMOTE_IR_RIGHT = 115;
public static final int WIIMOTE_IR_FORWARD = 116;
public static final int WIIMOTE_IR_BACKWARD = 117;
public static final int WIIMOTE_IR_HIDE = 118;
public static final int WIIMOTE_SWING = 119;
public static final int WIIMOTE_SWING_UP = 120;
public static final int WIIMOTE_SWING_DOWN = 121;
public static final int WIIMOTE_SWING_LEFT = 122;
public static final int WIIMOTE_SWING_RIGHT = 123;
public static final int WIIMOTE_SWING_FORWARD = 124;
public static final int WIIMOTE_SWING_BACKWARD = 125;
public static final int WIIMOTE_TILT = 126;
public static final int WIIMOTE_TILT_FORWARD = 127;
public static final int WIIMOTE_TILT_BACKWARD = 128;
public static final int WIIMOTE_TILT_LEFT = 129;
public static final int WIIMOTE_TILT_RIGHT = 130;
public static final int WIIMOTE_TILT_MODIFIER = 131;
public static final int WIIMOTE_SHAKE_X = 132;
public static final int WIIMOTE_SHAKE_Y = 133;
public static final int WIIMOTE_SHAKE_Z = 134;
public static final int NUNCHUK_BUTTON_C = 200;
public static final int NUNCHUK_BUTTON_Z = 201;
public static final int NUNCHUK_STICK = 202;
public static final int NUNCHUK_STICK_UP = 203;
public static final int NUNCHUK_STICK_DOWN = 204;
public static final int NUNCHUK_STICK_LEFT = 205;
public static final int NUNCHUK_STICK_RIGHT = 206;
public static final int NUNCHUK_SWING = 207;
public static final int NUNCHUK_SWING_UP = 208;
public static final int NUNCHUK_SWING_DOWN = 209;
public static final int NUNCHUK_SWING_LEFT = 210;
public static final int NUNCHUK_SWING_RIGHT = 221;
public static final int NUNCHUK_SWING_FORWARD = 212;
public static final int NUNCHUK_SWING_BACKWARD = 213;
public static final int NUNCHUK_TILT = 214;
public static final int NUNCHUK_TILT_FORWARD = 215;
public static final int NUNCHUK_TILT_BACKWARD = 216;
public static final int NUNCHUK_TILT_LEFT = 217;
public static final int NUNCHUK_TILT_RIGHT = 218;
public static final int NUNCHUK_TILT_MODIFIER = 219;
public static final int NUNCHUK_SHAKE_X = 220;
public static final int NUNCHUK_SHAKE_Y = 221;
public static final int NUNCHUK_SHAKE_Z = 222;
public static final int CLASSIC_BUTTON_A = 300;
public static final int CLASSIC_BUTTON_B = 301;
public static final int CLASSIC_BUTTON_X = 302;
public static final int CLASSIC_BUTTON_Y = 303;
public static final int CLASSIC_BUTTON_MINUS = 304;
public static final int CLASSIC_BUTTON_PLUS = 305;
public static final int CLASSIC_BUTTON_HOME = 306;
public static final int CLASSIC_BUTTON_ZL = 307;
public static final int CLASSIC_BUTTON_ZR = 308;
public static final int CLASSIC_DPAD_UP = 309;
public static final int CLASSIC_DPAD_DOWN = 310;
public static final int CLASSIC_DPAD_LEFT = 311;
public static final int CLASSIC_DPAD_RIGHT = 312;
public static final int CLASSIC_STICK_LEFT = 313;
public static final int CLASSIC_STICK_LEFT_UP = 314;
public static final int CLASSIC_STICK_LEFT_DOWN = 315;
public static final int CLASSIC_STICK_LEFT_LEFT = 316;
public static final int CLASSIC_STICK_LEFT_RIGHT = 317;
public static final int CLASSIC_STICK_RIGHT = 318;
public static final int CLASSIC_STICK_RIGHT_UP = 319;
public static final int CLASSIC_STICK_RIGHT_DOWN = 100;
public static final int CLASSIC_STICK_RIGHT_LEFT = 321;
public static final int CLASSIC_STICK_RIGHT_RIGHT = 322;
public static final int CLASSIC_TRIGGER_L = 323;
public static final int CLASSIC_TRIGGER_R = 324;
public static final int GUITAR_BUTTON_MINUS = 400;
public static final int GUITAR_BUTTON_PLUS = 401;
public static final int GUITAR_FRET_GREEN = 402;
public static final int GUITAR_FRET_RED = 403;
public static final int GUITAR_FRET_YELLOW = 404;
public static final int GUITAR_FRET_BLUE = 405;
public static final int GUITAR_FRET_ORANGE = 406;
public static final int GUITAR_STRUM_UP = 407;
public static final int GUITAR_STRUM_DOWN = 408;
public static final int GUITAR_STICK = 409;
public static final int GUITAR_STICK_UP = 410;
public static final int GUITAR_STICK_DOWN = 411;
public static final int GUITAR_STICK_LEFT = 412;
public static final int GUITAR_STICK_RIGHT = 413;
public static final int GUITAR_WHAMMY_BAR = 414;
public static final int DRUMS_BUTTON_MINUS = 500;
public static final int DRUMS_BUTTON_PLUS = 501;
public static final int DRUMS_PAD_RED = 502;
public static final int DRUMS_PAD_YELLOW = 503;
public static final int DRUMS_PAD_BLUE = 504;
public static final int DRUMS_PAD_GREEN = 505;
public static final int DRUMS_PAD_ORANGE = 506;
public static final int DRUMS_PAD_BASS = 507;
public static final int DRUMS_STICK = 508;
public static final int DRUMS_STICK_UP = 509;
public static final int DRUMS_STICK_DOWN = 510;
public static final int DRUMS_STICK_LEFT = 511;
public static final int DRUMS_STICK_RIGHT = 512;
public static final int TURNTABLE_BUTTON_GREEN_LEFT = 600;
public static final int TURNTABLE_BUTTON_RED_LEFT = 601;
public static final int TURNTABLE_BUTTON_BLUE_LEFT = 602;
public static final int TURNTABLE_BUTTON_GREEN_RIGHT = 603;
public static final int TURNTABLE_BUTTON_RED_RIGHT = 604;
public static final int TURNTABLE_BUTTON_BLUE_RIGHT = 605;
public static final int TURNTABLE_BUTTON_MINUS = 606;
public static final int TURNTABLE_BUTTON_PLUS = 607;
public static final int TURNTABLE_BUTTON_HOME = 608;
public static final int TURNTABLE_BUTTON_EUPHORIA = 609;
public static final int TURNTABLE_TABLE_LEFT = 610;
public static final int TURNTABLE_TABLE_LEFT_LEFT = 611;
public static final int TURNTABLE_TABLE_LEFT_RIGHT = 612;
public static final int TURNTABLE_TABLE_RIGHT = 613;
public static final int TURNTABLE_TABLE_RIGHT_LEFT = 614;
public static final int TURNTABLE_TABLE_RIGHT_RIGHT = 615;
public static final int TURNTABLE_STICK = 616;
public static final int TURNTABLE_STICK_UP = 617;
public static final int TURNTABLE_STICK_DOWN = 618;
public static final int TURNTABLE_STICK_LEFT = 619;
public static final int TURNTABLE_STICK_RIGHT = 620;
public static final int TURNTABLE_EFFECT_DIAL = 621;
public static final int TURNTABLE_CROSSFADE = 622;
public static final int TURNTABLE_CROSSFADE_LEFT = 623;
public static final int TURNTABLE_CROSSFADE_RIGHT = 624;
}
/**
* Button type for use in onTouchEvent
*/
public static final class ButtonType
{
public static final int BUTTON_A = 0;
public static final int BUTTON_B = 1;
public static final int BUTTON_START = 2;
public static final int BUTTON_X = 3;
public static final int BUTTON_Y = 4;
public static final int BUTTON_Z = 5;
public static final int BUTTON_UP = 6;
public static final int BUTTON_DOWN = 7;
public static final int BUTTON_LEFT = 8;
public static final int BUTTON_RIGHT = 9;
public static final int STICK_MAIN = 10;
public static final int STICK_MAIN_UP = 11;
public static final int STICK_MAIN_DOWN = 12;
public static final int STICK_MAIN_LEFT = 13;
public static final int STICK_MAIN_RIGHT = 14;
public static final int STICK_C = 15;
public static final int STICK_C_UP = 16;
public static final int STICK_C_DOWN = 17;
public static final int STICK_C_LEFT = 18;
public static final int STICK_C_RIGHT = 19;
public static final int TRIGGER_L = 20;
public static final int TRIGGER_R = 21;
public static final int WIIMOTE_BUTTON_A = 100;
public static final int WIIMOTE_BUTTON_B = 101;
public static final int WIIMOTE_BUTTON_MINUS = 102;
public static final int WIIMOTE_BUTTON_PLUS = 103;
public static final int WIIMOTE_BUTTON_HOME = 104;
public static final int WIIMOTE_BUTTON_1 = 105;
public static final int WIIMOTE_BUTTON_2 = 106;
public static final int WIIMOTE_UP = 107;
public static final int WIIMOTE_DOWN = 108;
public static final int WIIMOTE_LEFT = 109;
public static final int WIIMOTE_RIGHT = 110;
public static final int WIIMOTE_IR = 111;
public static final int WIIMOTE_IR_UP = 112;
public static final int WIIMOTE_IR_DOWN = 113;
public static final int WIIMOTE_IR_LEFT = 114;
public static final int WIIMOTE_IR_RIGHT = 115;
public static final int WIIMOTE_IR_FORWARD = 116;
public static final int WIIMOTE_IR_BACKWARD = 117;
public static final int WIIMOTE_IR_HIDE = 118;
public static final int WIIMOTE_SWING = 119;
public static final int WIIMOTE_SWING_UP = 120;
public static final int WIIMOTE_SWING_DOWN = 121;
public static final int WIIMOTE_SWING_LEFT = 122;
public static final int WIIMOTE_SWING_RIGHT = 123;
public static final int WIIMOTE_SWING_FORWARD = 124;
public static final int WIIMOTE_SWING_BACKWARD = 125;
public static final int WIIMOTE_TILT = 126;
public static final int WIIMOTE_TILT_FORWARD = 127;
public static final int WIIMOTE_TILT_BACKWARD = 128;
public static final int WIIMOTE_TILT_LEFT = 129;
public static final int WIIMOTE_TILT_RIGHT = 130;
public static final int WIIMOTE_TILT_MODIFIER = 131;
public static final int WIIMOTE_SHAKE_X = 132;
public static final int WIIMOTE_SHAKE_Y = 133;
public static final int WIIMOTE_SHAKE_Z = 134;
public static final int NUNCHUK_BUTTON_C = 200;
public static final int NUNCHUK_BUTTON_Z = 201;
public static final int NUNCHUK_STICK = 202;
public static final int NUNCHUK_STICK_UP = 203;
public static final int NUNCHUK_STICK_DOWN = 204;
public static final int NUNCHUK_STICK_LEFT = 205;
public static final int NUNCHUK_STICK_RIGHT = 206;
public static final int NUNCHUK_SWING = 207;
public static final int NUNCHUK_SWING_UP = 208;
public static final int NUNCHUK_SWING_DOWN = 209;
public static final int NUNCHUK_SWING_LEFT = 210;
public static final int NUNCHUK_SWING_RIGHT = 221;
public static final int NUNCHUK_SWING_FORWARD = 212;
public static final int NUNCHUK_SWING_BACKWARD = 213;
public static final int NUNCHUK_TILT = 214;
public static final int NUNCHUK_TILT_FORWARD = 215;
public static final int NUNCHUK_TILT_BACKWARD = 216;
public static final int NUNCHUK_TILT_LEFT = 217;
public static final int NUNCHUK_TILT_RIGHT = 218;
public static final int NUNCHUK_TILT_MODIFIER = 219;
public static final int NUNCHUK_SHAKE_X = 220;
public static final int NUNCHUK_SHAKE_Y = 221;
public static final int NUNCHUK_SHAKE_Z = 222;
public static final int CLASSIC_BUTTON_A = 300;
public static final int CLASSIC_BUTTON_B = 301;
public static final int CLASSIC_BUTTON_X = 302;
public static final int CLASSIC_BUTTON_Y = 303;
public static final int CLASSIC_BUTTON_MINUS = 304;
public static final int CLASSIC_BUTTON_PLUS = 305;
public static final int CLASSIC_BUTTON_HOME = 306;
public static final int CLASSIC_BUTTON_ZL = 307;
public static final int CLASSIC_BUTTON_ZR = 308;
public static final int CLASSIC_DPAD_UP = 309;
public static final int CLASSIC_DPAD_DOWN = 310;
public static final int CLASSIC_DPAD_LEFT = 311;
public static final int CLASSIC_DPAD_RIGHT = 312;
public static final int CLASSIC_STICK_LEFT = 313;
public static final int CLASSIC_STICK_LEFT_UP = 314;
public static final int CLASSIC_STICK_LEFT_DOWN = 315;
public static final int CLASSIC_STICK_LEFT_LEFT = 316;
public static final int CLASSIC_STICK_LEFT_RIGHT = 317;
public static final int CLASSIC_STICK_RIGHT = 318;
public static final int CLASSIC_STICK_RIGHT_UP = 319;
public static final int CLASSIC_STICK_RIGHT_DOWN = 100;
public static final int CLASSIC_STICK_RIGHT_LEFT = 321;
public static final int CLASSIC_STICK_RIGHT_RIGHT = 322;
public static final int CLASSIC_TRIGGER_L = 323;
public static final int CLASSIC_TRIGGER_R = 324;
public static final int GUITAR_BUTTON_MINUS = 400;
public static final int GUITAR_BUTTON_PLUS = 401;
public static final int GUITAR_FRET_GREEN = 402;
public static final int GUITAR_FRET_RED = 403;
public static final int GUITAR_FRET_YELLOW = 404;
public static final int GUITAR_FRET_BLUE = 405;
public static final int GUITAR_FRET_ORANGE = 406;
public static final int GUITAR_STRUM_UP = 407;
public static final int GUITAR_STRUM_DOWN = 408;
public static final int GUITAR_STICK = 409;
public static final int GUITAR_STICK_UP = 410;
public static final int GUITAR_STICK_DOWN = 411;
public static final int GUITAR_STICK_LEFT = 412;
public static final int GUITAR_STICK_RIGHT = 413;
public static final int GUITAR_WHAMMY_BAR = 414;
public static final int DRUMS_BUTTON_MINUS = 500;
public static final int DRUMS_BUTTON_PLUS = 501;
public static final int DRUMS_PAD_RED = 502;
public static final int DRUMS_PAD_YELLOW = 503;
public static final int DRUMS_PAD_BLUE = 504;
public static final int DRUMS_PAD_GREEN = 505;
public static final int DRUMS_PAD_ORANGE = 506;
public static final int DRUMS_PAD_BASS = 507;
public static final int DRUMS_STICK = 508;
public static final int DRUMS_STICK_UP = 509;
public static final int DRUMS_STICK_DOWN = 510;
public static final int DRUMS_STICK_LEFT = 511;
public static final int DRUMS_STICK_RIGHT = 512;
public static final int TURNTABLE_BUTTON_GREEN_LEFT = 600;
public static final int TURNTABLE_BUTTON_RED_LEFT = 601;
public static final int TURNTABLE_BUTTON_BLUE_LEFT = 602;
public static final int TURNTABLE_BUTTON_GREEN_RIGHT = 603;
public static final int TURNTABLE_BUTTON_RED_RIGHT = 604;
public static final int TURNTABLE_BUTTON_BLUE_RIGHT = 605;
public static final int TURNTABLE_BUTTON_MINUS = 606;
public static final int TURNTABLE_BUTTON_PLUS = 607;
public static final int TURNTABLE_BUTTON_HOME = 608;
public static final int TURNTABLE_BUTTON_EUPHORIA = 609;
public static final int TURNTABLE_TABLE_LEFT = 610;
public static final int TURNTABLE_TABLE_LEFT_LEFT = 611;
public static final int TURNTABLE_TABLE_LEFT_RIGHT = 612;
public static final int TURNTABLE_TABLE_RIGHT = 613;
public static final int TURNTABLE_TABLE_RIGHT_LEFT = 614;
public static final int TURNTABLE_TABLE_RIGHT_RIGHT = 615;
public static final int TURNTABLE_STICK = 616;
public static final int TURNTABLE_STICK_UP = 617;
public static final int TURNTABLE_STICK_DOWN = 618;
public static final int TURNTABLE_STICK_LEFT = 619;
public static final int TURNTABLE_STICK_RIGHT = 620;
public static final int TURNTABLE_EFFECT_DIAL = 621;
public static final int TURNTABLE_CROSSFADE = 622;
public static final int TURNTABLE_CROSSFADE_LEFT = 623;
public static final int TURNTABLE_CROSSFADE_RIGHT = 624;
}
/**
* Button states
*/
public static final class ButtonState
{
public static final int RELEASED = 0;
public static final int PRESSED = 1;
}
/**
* Button states
*/
public static final class ButtonState
{
public static final int RELEASED = 0;
public static final int PRESSED = 1;
}
private NativeLibrary()
{
// Disallows instantiation.
}
private NativeLibrary()
{
// Disallows instantiation.
}
/**
* Default touchscreen device
*/
public static final String TouchScreenDevice = "Touchscreen";
/**
* 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 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 Value The value of the axis represented by the given ID.
*/
public static native void onGamePadMoveEvent(String Device, int Axis, float Value);
/**
* Handles gamepad movement events.
*
* @param Device The device ID of the gamepad.
* @param Axis The axis ID
* @param Value The value of the axis represented by the given ID.
*/
public static native void onGamePadMoveEvent(String Device, int Axis, float Value);
public static native String GetUserSetting(String gameID, String Section, String Key);
public static native 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 SetUserSetting(String gameID, String Section, String Key, String Value);
public static native void InitGameIni(String gameID);
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);
/**
* 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);
/**
* 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 Dolphin version string.
*
* @return the Dolphin version string.
*/
public static native String GetVersionString();
/**
* Gets the Dolphin version string.
*
* @return the Dolphin version string.
*/
public static native String GetVersionString();
public static native String GetGitRevision();
public static native String GetGitRevision();
/**
* Saves a screen capture of the game
*/
public static native void SaveScreenShot();
/**
* 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 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);
/**
* 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 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);
/**
* 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);
/**
* 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();
/**
* Returns the current working user directory
*/
public static native String GetUserDirectory();
public static native int DefaultCPUCore();
public static native int DefaultCPUCore();
/**
* Begins emulation.
*/
public static native void Run(String path, boolean firstOpen);
/**
* Begins emulation.
*/
public static native void Run(String path, boolean firstOpen);
/**
* Begins emulation from the specified savestate.
*/
public static native void Run(String path, String savestatePath, boolean deleteSavestate);
/**
* Begins emulation from the specified savestate.
*/
public static native void Run(String path, String savestatePath, boolean deleteSavestate);
public static native void ChangeDisc(String path);
public static native void ChangeDisc(String path);
// Surface Handling
public static native void SurfaceChanged(Surface surf);
public static native void SurfaceDestroyed();
// Surface Handling
public static native void SurfaceChanged(Surface surf);
/** Unpauses emulation from a paused state. */
public static native void UnPauseEmulation();
public static native void SurfaceDestroyed();
/** Pauses emulation. */
public static native void PauseEmulation();
/**
* Unpauses emulation from a paused state.
*/
public static native void UnPauseEmulation();
/** Stops emulation. */
public static native void StopEmulation();
/**
* Pauses emulation.
*/
public static native void PauseEmulation();
/** Returns true if emulation is running (or is paused). */
public static native boolean IsRunning();
/**
* Stops emulation.
*/
public static native void StopEmulation();
/**
* Enables or disables CPU block profiling
* @param enable
*/
public static native void SetProfiling(boolean enable);
/**
* Returns true if emulation is running (or is paused).
*/
public static native boolean IsRunning();
/**
* Writes out the block profile results
*/
public static native void WriteProfileResults();
/**
* Enables or disables CPU block profiling
*
* @param enable
*/
public static native void SetProfiling(boolean enable);
/** Native EGL functions not exposed by Java bindings **/
public static native void eglBindAPI(int api);
/**
* Writes out the block profile results
*/
public static native void WriteProfileResults();
/**
* Provides a way to refresh the connections on Wiimotes
*/
public static native void RefreshWiimotes();
/**
* Native EGL functions not exposed by Java bindings
**/
public static native void eglBindAPI(int api);
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);
/**
* Provides a way to refresh the connections on Wiimotes
*/
public static native void RefreshWiimotes();
// 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;
private static boolean 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();
}
});
}
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);
// Show the AlertDialog on the main thread.
emulationActivity.runOnUiThread(() -> builder.show());
// 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;
// Wait for the lock to notify that it is complete.
synchronized (lock)
{
try
{
lock.wait();
}
catch (Exception e) { }
}
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();
}
});
}
if (yesNo)
result = alertResult;
}
return result;
}
// Show the AlertDialog on the main thread.
emulationActivity.runOnUiThread(() -> builder.show());
public static void setEmulationActivity(EmulationActivity emulationActivity)
{
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
sEmulationActivity = new WeakReference<>(emulationActivity);
}
// Wait for the lock to notify that it is complete.
synchronized (lock)
{
try
{
lock.wait();
}
catch (Exception e)
{
}
}
public static void clearEmulationActivity()
{
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.");
if (yesNo)
result = alertResult;
}
return result;
}
sEmulationActivity.clear();
}
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();
}
}

View File

@ -22,113 +22,116 @@ import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
*/
public class AppLinkActivity extends FragmentActivity
{
private static final String TAG = "AppLinkActivity";
private static final String TAG = "AppLinkActivity";
private AppLinkHelper.PlayAction playAction;
private DirectoryStateReceiver directoryStateReceiver;
private AppLinkHelper.PlayAction playAction;
private DirectoryStateReceiver directoryStateReceiver;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Uri uri = intent.getData();
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent intent = getIntent();
Uri uri = intent.getData();
Log.v(TAG, uri.toString());
Log.v(TAG, uri.toString());
if (uri.getPathSegments().isEmpty())
{
Log.e(TAG, "Invalid uri " + uri);
finish();
return;
}
if (uri.getPathSegments().isEmpty())
{
Log.e(TAG, "Invalid uri " + uri);
finish();
return;
}
AppLinkHelper.AppLinkAction action = AppLinkHelper.extractAction(uri);
switch (action.getAction())
{
case AppLinkHelper.PLAY:
playAction = (AppLinkHelper.PlayAction) action;
initResources();
break;
case AppLinkHelper.BROWSE:
browse();
break;
default:
throw new IllegalArgumentException("Invalid Action " + action);
}
}
AppLinkHelper.AppLinkAction action = AppLinkHelper.extractAction(uri);
switch (action.getAction())
{
case AppLinkHelper.PLAY:
playAction = (AppLinkHelper.PlayAction) action;
initResources();
break;
case AppLinkHelper.BROWSE:
browse();
break;
default:
throw new IllegalArgumentException("Invalid Action " + action);
}
}
/**
* Need to init these since they usually occur in the main activity.
*/
private void initResources()
{
IntentFilter statusIntentFilter = new IntentFilter(
DirectoryInitializationService.BROADCAST_ACTION);
/**
* Need to init these since they usually occur in the main activity.
*/
private void initResources()
{
IntentFilter statusIntentFilter = new IntentFilter(
DirectoryInitializationService.BROADCAST_ACTION);
directoryStateReceiver =
new DirectoryStateReceiver(directoryInitializationState ->
{
if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
{
play(playAction);
}
else if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
{
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show();
}
else if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
{
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
.show();
}
});
directoryStateReceiver =
new DirectoryStateReceiver(directoryInitializationState ->
{
if (directoryInitializationState ==
DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
{
play(playAction);
}
else if (directoryInitializationState ==
DirectoryInitializationService.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
{
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show();
}
else if (directoryInitializationState ==
DirectoryInitializationService.DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
{
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
.show();
}
});
// Registers the DirectoryStateReceiver and its intent filters
LocalBroadcastManager.getInstance(this).registerReceiver(
directoryStateReceiver,
statusIntentFilter);
DirectoryInitializationService.startService(this);
GameFileCacheService.startLoad(this);
}
// Registers the DirectoryStateReceiver and its intent filters
LocalBroadcastManager.getInstance(this).registerReceiver(
directoryStateReceiver,
statusIntentFilter);
DirectoryInitializationService.startService(this);
GameFileCacheService.startLoad(this);
}
/**
* Action if channel icon is selected
*/
private void browse()
{
Intent openApp = new Intent(this, TvMainActivity.class);
startActivity(openApp);
/**
* Action if channel icon is selected
*/
private void browse()
{
Intent openApp = new Intent(this, TvMainActivity.class);
startActivity(openApp);
finish();
}
finish();
}
/**
* Action if program(game) is selected
*/
private void play(AppLinkHelper.PlayAction action)
{
Log.d(TAG, "Playing game "
+ action.getGameId()
+ " from channel "
+ action.getChannelId());
/**
* Action if program(game) is selected
*/
private void play(AppLinkHelper.PlayAction action)
{
Log.d(TAG, "Playing game "
+ action.getGameId()
+ " from channel "
+ action.getChannelId());
GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());
if (game == null)
Log.e(TAG, "Invalid Game: " + action.getGameId());
else
startGame(game);
finish();
}
GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());
if (game == null)
Log.e(TAG, "Invalid Game: " + action.getGameId());
else
startGame(game);
finish();
}
private void startGame(GameFile game)
{
if (directoryStateReceiver != null)
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(directoryStateReceiver);
directoryStateReceiver = null;
}
EmulationActivity.launch(this, game, -1, null);
}
private void startGame(GameFile game)
{
if (directoryStateReceiver != null)
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(directoryStateReceiver);
directoryStateReceiver = null;
}
EmulationActivity.launch(this, game, -1, null);
}
}

View File

@ -13,16 +13,17 @@ 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;
}
@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;
}
}

View File

@ -12,10 +12,10 @@ import android.widget.Toast;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.utils.PicassoUtils;
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
@ -24,186 +24,195 @@ import java.util.ArrayList;
import java.util.List;
public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> implements
View.OnClickListener,
View.OnLongClickListener
View.OnClickListener,
View.OnLongClickListener
{
private List<GameFile> mGameFiles;
private List<GameFile> mGameFiles;
/**
* Initializes the adapter's observer, which watches for changes to the dataset. The adapter will
* display no data until swapDataSet is called.
*/
public GameAdapter()
{
mGameFiles = new ArrayList<>();
}
/**
* Initializes the adapter's observer, which watches for changes to the dataset. The adapter will
* display no data until swapDataSet is called.
*/
public GameAdapter()
{
mGameFiles = new ArrayList<>();
}
/**
* 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);
/**
* 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);
gameCard.setOnLongClickListener(this);
gameCard.setOnClickListener(this);
gameCard.setOnLongClickListener(this);
// Use that view to create a ViewHolder.
return new GameViewHolder(gameCard);
}
// 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)
{
GameFile gameFile = mGameFiles.get(position);
PicassoUtils.loadGameBanner(holder.imageScreenshot, gameFile);
/**
* 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)
{
GameFile gameFile = mGameFiles.get(position);
PicassoUtils.loadGameBanner(holder.imageScreenshot, gameFile);
holder.textGameTitle.setText(gameFile.getTitle());
holder.textCompany.setText(gameFile.getCompany());
holder.textGameTitle.setText(gameFile.getTitle());
holder.textCompany.setText(gameFile.getCompany());
holder.gameFile = gameFile;
}
holder.gameFile = gameFile;
}
/**
* Called by the LayoutManager to find out how much data we have.
*
* @return Size of the dataset.
*/
@Override
public int getItemCount()
{
return mGameFiles.size();
}
/**
* Called by the LayoutManager to find out how much data we have.
*
* @return Size of the dataset.
*/
@Override
public int getItemCount()
{
return mGameFiles.size();
}
/**
* Tell Android whether or not each item in the dataset has a stable identifier.
*
* @param hasStableIds ignored.
*/
@Override
public void setHasStableIds(boolean hasStableIds)
{
super.setHasStableIds(false);
}
/**
* Tell Android whether or not each item in the dataset has a stable identifier.
*
* @param hasStableIds ignored.
*/
@Override
public void setHasStableIds(boolean hasStableIds)
{
super.setHasStableIds(false);
}
/**
* When a load is finished, call this to replace the existing data
* with the newly-loaded data.
*/
public void swapDataSet(List<GameFile> gameFiles)
{
mGameFiles = gameFiles;
notifyDataSetChanged();
}
/**
* When a load is finished, call this to replace the existing data
* with the newly-loaded data.
*/
public void swapDataSet(List<GameFile> gameFiles)
{
mGameFiles = gameFiles;
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();
/**
* 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.gameFile,
holder.getAdapterPosition(),
holder.imageScreenshot);
}
EmulationActivity.launch((FragmentActivity) view.getContext(),
holder.gameFile,
holder.getAdapterPosition(),
holder.imageScreenshot);
}
/**
* Launches the details activity for this Game, using an ID stored in the
* details button's Tag.
*
* @param view The Card button that was long-clicked.
*/
@Override
public boolean onLongClick(View view)
{
FragmentActivity activity = (FragmentActivity) view.getContext();
GameViewHolder holder = (GameViewHolder) view.getTag();
String gameId = holder.gameFile.getGameId();
/**
* Launches the details activity for this Game, using an ID stored in the
* details button's Tag.
*
* @param view The Card button that was long-clicked.
*/
@Override
public boolean onLongClick(View view)
{
FragmentActivity activity = (FragmentActivity) view.getContext();
GameViewHolder holder = (GameViewHolder) view.getTag();
String gameId = holder.gameFile.getGameId();
if (gameId.isEmpty())
{
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings");
builder.setMessage("Files without game IDs don't support game-specific settings.");
if (gameId.isEmpty())
{
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings");
builder.setMessage("Files without game IDs don't support game-specific settings.");
builder.show();
return true;
}
builder.show();
return true;
}
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings")
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
SettingsActivity.launch(activity, MenuTag.CONFIG, gameId);
break;
case 1:
SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId);
break;
case 2:
String path = DirectoryInitializationService.getUserDirectory() + "/GameSettings/" + gameId + ".ini";
File gameSettingsFile = new File(path);
if (gameSettingsFile.exists())
{
if (gameSettingsFile.delete())
{
Toast.makeText(view.getContext(), "Cleared settings for " + gameId, Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(view.getContext(), "Unable to clear settings for " + gameId, Toast.LENGTH_SHORT).show();
}
}
else
{
Toast.makeText(view.getContext(), "No game settings to delete", Toast.LENGTH_SHORT).show();
}
break;
}
}
});
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings")
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
switch (which)
{
case 0:
SettingsActivity.launch(activity, MenuTag.CONFIG, gameId);
break;
case 1:
SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId);
break;
case 2:
String path =
DirectoryInitializationService.getUserDirectory() + "/GameSettings/" +
gameId + ".ini";
File gameSettingsFile = new File(path);
if (gameSettingsFile.exists())
{
if (gameSettingsFile.delete())
{
Toast.makeText(view.getContext(), "Cleared settings for " + gameId,
Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(view.getContext(), "Unable to clear settings for " + gameId,
Toast.LENGTH_SHORT).show();
}
}
else
{
Toast.makeText(view.getContext(), "No game settings to delete",
Toast.LENGTH_SHORT).show();
}
break;
}
}
});
builder.show();
return true;
}
builder.show();
return true;
}
public static class SpacesItemDecoration extends RecyclerView.ItemDecoration
{
private int space;
public static class SpacesItemDecoration extends RecyclerView.ItemDecoration
{
private int space;
public SpacesItemDecoration(int space)
{
this.space = 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;
}
}
@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;
}
}
}

View File

@ -14,11 +14,11 @@ import android.widget.ImageView;
import android.widget.Toast;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.utils.PicassoUtils;
import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder;
@ -30,117 +30,126 @@ import java.io.File;
*/
public final class GameRowPresenter extends Presenter
{
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent)
{
// Create a new view.
ImageCardView gameCard = new ImageCardView(parent.getContext());
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent)
{
// Create a new view.
ImageCardView gameCard = new ImageCardView(parent.getContext());
gameCard.setMainImageAdjustViewBounds(true);
gameCard.setMainImageDimensions(240, 336);
gameCard.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP);
gameCard.setMainImageAdjustViewBounds(true);
gameCard.setMainImageDimensions(240, 336);
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;
GameFile gameFile = (GameFile) item;
@Override
public void onBindViewHolder(ViewHolder viewHolder, Object item)
{
TvGameViewHolder holder = (TvGameViewHolder) viewHolder;
GameFile gameFile = (GameFile) item;
holder.imageScreenshot.setImageDrawable(null);
PicassoUtils.loadGameBanner(holder.imageScreenshot, gameFile);
holder.imageScreenshot.setImageDrawable(null);
PicassoUtils.loadGameBanner(holder.imageScreenshot, gameFile);
holder.cardParent.setTitleText(gameFile.getTitle());
holder.cardParent.setContentText(gameFile.getCompany());
holder.cardParent.setTitleText(gameFile.getTitle());
holder.cardParent.setContentText(gameFile.getCompany());
holder.gameFile = gameFile;
holder.gameFile = gameFile;
// Set the platform-dependent background color of the card
int backgroundId;
switch (Platform.fromNativeInt(gameFile.getPlatform()))
{
case GAMECUBE:
backgroundId = R.drawable.tv_card_background_gamecube;
break;
case WII:
backgroundId = R.drawable.tv_card_background_wii;
break;
case WIIWARE:
backgroundId = R.drawable.tv_card_background_wiiware;
break;
default:
throw new AssertionError("Not reachable.");
}
Context context = holder.cardParent.getContext();
Drawable background = ContextCompat.getDrawable(context, backgroundId);
holder.cardParent.setInfoAreaBackground(background);
holder.cardParent.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view)
{
FragmentActivity activity = (FragmentActivity) view.getContext();
String gameId = gameFile.getGameId();
// Set the platform-dependent background color of the card
int backgroundId;
switch (Platform.fromNativeInt(gameFile.getPlatform()))
{
case GAMECUBE:
backgroundId = R.drawable.tv_card_background_gamecube;
break;
case WII:
backgroundId = R.drawable.tv_card_background_wii;
break;
case WIIWARE:
backgroundId = R.drawable.tv_card_background_wiiware;
break;
default:
throw new AssertionError("Not reachable.");
}
Context context = holder.cardParent.getContext();
Drawable background = ContextCompat.getDrawable(context, backgroundId);
holder.cardParent.setInfoAreaBackground(background);
holder.cardParent.setOnLongClickListener(new View.OnLongClickListener()
{
@Override
public boolean onLongClick(View view)
{
FragmentActivity activity = (FragmentActivity) view.getContext();
String gameId = gameFile.getGameId();
if (gameId.isEmpty())
{
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings");
builder.setMessage("Files without game IDs don't support game-specific settings.");
if (gameId.isEmpty())
{
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings");
builder.setMessage("Files without game IDs don't support game-specific settings.");
builder.show();
return true;
}
builder.show();
return true;
}
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings")
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
SettingsActivity.launch(activity, MenuTag.CONFIG, gameId);
break;
case 1:
SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId);
break;
case 2:
String path = DirectoryInitializationService.getUserDirectory() + "/GameSettings/" + gameId + ".ini";
File gameSettingsFile = new File(path);
if (gameSettingsFile.exists())
{
if (gameSettingsFile.delete())
{
Toast.makeText(view.getContext(), "Cleared settings for " + gameId, Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(view.getContext(), "Unable to clear settings for " + gameId, Toast.LENGTH_SHORT).show();
}
}
else
{
Toast.makeText(view.getContext(), "No game settings to delete", Toast.LENGTH_SHORT).show();
}
break;
}
}
});
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle("Game Settings")
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
switch (which)
{
case 0:
SettingsActivity.launch(activity, MenuTag.CONFIG, gameId);
break;
case 1:
SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId);
break;
case 2:
String path = DirectoryInitializationService.getUserDirectory() +
"/GameSettings/" + gameId + ".ini";
File gameSettingsFile = new File(path);
if (gameSettingsFile.exists())
{
if (gameSettingsFile.delete())
{
Toast.makeText(view.getContext(), "Cleared settings for " + gameId,
Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(view.getContext(),
"Unable to clear settings for " + gameId, Toast.LENGTH_SHORT)
.show();
}
}
else
{
Toast.makeText(view.getContext(), "No game settings to delete",
Toast.LENGTH_SHORT).show();
}
break;
}
}
});
builder.show();
return true;
}
});
}
builder.show();
return true;
}
});
}
@Override
public void onUnbindViewHolder(ViewHolder viewHolder)
{
// no op
}
@Override
public void onUnbindViewHolder(ViewHolder viewHolder)
{
// no op
}
}

View File

@ -2,9 +2,9 @@ package org.dolphinemu.dolphinemu.adapters;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
@ -15,48 +15,48 @@ import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesFragment;
public class PlatformPagerAdapter extends FragmentPagerAdapter
{
private Context mContext;
private Context mContext;
private final static int[] TAB_ICONS =
{
R.drawable.ic_gamecube,
R.drawable.ic_wii,
R.drawable.ic_folder // WiiWare TODO Have an icon here.
};
private final static int[] TAB_ICONS =
{
R.drawable.ic_gamecube,
R.drawable.ic_wii,
R.drawable.ic_folder // WiiWare TODO Have an icon here.
};
public PlatformPagerAdapter(FragmentManager fm, Context context)
{
super(fm);
mContext = context;
}
public PlatformPagerAdapter(FragmentManager fm, Context context)
{
super(fm);
mContext = context;
}
@Override
public Fragment getItem(int position)
{
return PlatformGamesFragment.newInstance(Platform.fromPosition(position));
}
@Override
public Fragment getItem(int position)
{
return PlatformGamesFragment.newInstance(Platform.fromPosition(position));
}
@Override
public int getCount()
{
return TAB_ICONS.length;
}
@Override
public int getCount()
{
return TAB_ICONS.length;
}
@Override
public CharSequence getPageTitle(int position)
{
// Hax from https://guides.codepath.com/android/Google-Play-Style-Tabs-using-TabLayout#design-support-library
// Apparently a workaround for TabLayout not supporting icons.
// TODO This workaround will eventually not be necessary; switch to more legit methods when that is the case
// TODO Also remove additional hax from styles.xml
Drawable drawable = mContext.getResources().getDrawable(TAB_ICONS[position]);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
@Override
public CharSequence getPageTitle(int position)
{
// Hax from https://guides.codepath.com/android/Google-Play-Style-Tabs-using-TabLayout#design-support-library
// Apparently a workaround for TabLayout not supporting icons.
// TODO This workaround will eventually not be necessary; switch to more legit methods when that is the case
// TODO Also remove additional hax from styles.xml
Drawable drawable = mContext.getResources().getDrawable(TAB_ICONS[position]);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
ImageSpan imageSpan = new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM);
SpannableString sb = new SpannableString(" ");
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
SpannableString sb = new SpannableString(" ");
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return sb;
}
return sb;
}
}

View File

@ -10,37 +10,37 @@ import org.dolphinemu.dolphinemu.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 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
}
}

View File

@ -5,14 +5,12 @@ import android.app.Dialog;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.DialogFragment;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.model.GameFile;
@ -22,63 +20,64 @@ import de.hdodenhof.circleimageview.CircleImageView;
public final class GameDetailsDialog extends DialogFragment
{
private static final String ARG_GAME_PATH = "game_path";
private static final String ARG_GAME_PATH = "game_path";
public static GameDetailsDialog newInstance(String gamePath)
{
GameDetailsDialog fragment = new GameDetailsDialog();
public static GameDetailsDialog newInstance(String gamePath)
{
GameDetailsDialog fragment = new GameDetailsDialog();
Bundle arguments = new Bundle();
arguments.putString(ARG_GAME_PATH, gamePath);
fragment.setArguments(arguments);
Bundle arguments = new Bundle();
arguments.putString(ARG_GAME_PATH, gamePath);
fragment.setArguments(arguments);
return fragment;
}
return fragment;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
GameFile gameFile = GameFileCacheService.addOrGet(getArguments().getString(ARG_GAME_PATH));
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
GameFile gameFile = GameFileCacheService.addOrGet(getArguments().getString(ARG_GAME_PATH));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater().inflate(R.layout.dialog_game_details, null);
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_description);
TextView textTitle = contents.findViewById(R.id.text_game_title);
TextView textDescription = contents.findViewById(R.id.text_description);
TextView textCountry = contents.findViewById(R.id.text_country);
TextView textCompany = contents.findViewById(R.id.text_company);
TextView textCountry = contents.findViewById(R.id.text_country);
TextView textCompany = contents.findViewById(R.id.text_company);
FloatingActionButton buttonLaunch = contents.findViewById(R.id.button_launch);
FloatingActionButton buttonLaunch = contents.findViewById(R.id.button_launch);
String country = getResources().getStringArray(R.array.countryNames)[gameFile.getCountry()];
String country = getResources().getStringArray(R.array.countryNames)[gameFile.getCountry()];
textTitle.setText(gameFile.getTitle());
textDescription.setText(gameFile.getDescription());
textCountry.setText(country);
textCompany.setText(gameFile.getCompany());
textTitle.setText(gameFile.getTitle());
textDescription.setText(gameFile.getDescription());
textCountry.setText(country);
textCompany.setText(gameFile.getCompany());
buttonLaunch.setOnClickListener(view ->
{
// Start the emulation activity and send the path of the clicked ROM to it.
EmulationActivity.launch(getActivity(), gameFile, -1, imageGameScreen);
});
buttonLaunch.setOnClickListener(view ->
{
// Start the emulation activity and send the path of the clicked ROM to it.
EmulationActivity.launch(getActivity(), gameFile, -1, imageGameScreen);
});
// Fill in the view contents.
Picasso.with(imageGameScreen.getContext())
.load(getArguments().getString(gameFile.getScreenshotPath()))
.fit()
.centerCrop()
.noFade()
.noPlaceholder()
.into(imageGameScreen);
// Fill in the view contents.
Picasso.with(imageGameScreen.getContext())
.load(getArguments().getString(gameFile.getScreenshotPath()))
.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();
}
}

View File

@ -22,205 +22,209 @@ import java.util.List;
*/
public final class MotionAlertDialog extends AlertDialog
{
// The selected input preference
private final InputBindingSetting setting;
private final ArrayList<Float> mPreviousValues = new ArrayList<>();
private int mPrevDeviceId = 0;
private boolean mWaitingForEvent = true;
// The selected input preference
private final InputBindingSetting setting;
private final ArrayList<Float> mPreviousValues = new ArrayList<>();
private int mPrevDeviceId = 0;
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.setting = setting;
}
public boolean onKeyEvent(int keyCode, KeyEvent event)
{
Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
switch (event.getAction())
{
case KeyEvent.ACTION_UP:
if (!ControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode))
{
saveKeyInput(event);
}
// Even if we ignore the key, we still consume it. Thus return true regardless.
return true;
public boolean onKeyEvent(int keyCode, KeyEvent event)
{
Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
switch (event.getAction())
{
case KeyEvent.ACTION_UP:
if (!ControllerMappingHelper.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;
}
}
default:
return false;
}
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event)
{
// Option to clear by long back is only needed on the TV interface
if (TvUtil.isLeanback(getContext()))
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
clearBinding();
return true;
}
}
return super.onKeyLongPress(keyCode, event);
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event)
{
// Option to clear by long back is only needed on the TV interface
if (TvUtil.isLeanback(getContext()))
{
if (keyCode == KeyEvent.KEYCODE_BACK)
{
clearBinding();
return true;
}
}
return super.onKeyLongPress(keyCode, event);
}
@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 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);
}
@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;
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();
InputDevice input = event.getDevice();
List<InputDevice.MotionRange> motionRanges = input.getMotionRanges();
List<InputDevice.MotionRange> motionRanges = input.getMotionRanges();
if (input.getId() != mPrevDeviceId)
{
mPreviousValues.clear();
}
mPrevDeviceId = input.getId();
boolean firstEvent = mPreviousValues.isEmpty();
if (input.getId() != mPrevDeviceId)
{
mPreviousValues.clear();
}
mPrevDeviceId = input.getId();
boolean firstEvent = mPreviousValues.isEmpty();
int numMovedAxis = 0;
float axisMoveValue = 0.0f;
InputDevice.MotionRange lastMovedRange = null;
char lastMovedDir = '?';
if (mWaitingForEvent)
{
for (int i = 0; i < motionRanges.size(); i++)
{
InputDevice.MotionRange range = motionRanges.get(i);
int axis = range.getAxis();
float origValue = event.getAxisValue(axis);
float value = ControllerMappingHelper.scaleAxis(input, axis, origValue);
if (firstEvent)
{
mPreviousValues.add(value);
}
else
{
float previousValue = mPreviousValues.get(i);
int numMovedAxis = 0;
float axisMoveValue = 0.0f;
InputDevice.MotionRange lastMovedRange = null;
char lastMovedDir = '?';
if (mWaitingForEvent)
{
for (int i = 0; i < motionRanges.size(); i++)
{
InputDevice.MotionRange range = motionRanges.get(i);
int axis = range.getAxis();
float origValue = event.getAxisValue(axis);
float value = ControllerMappingHelper.scaleAxis(input, axis, origValue);
if (firstEvent)
{
mPreviousValues.add(value);
}
else
{
float previousValue = mPreviousValues.get(i);
// Only handle the axes that are not neutral (more than 0.5)
// but ignore any axis that has a constant value (e.g. always 1)
if (Math.abs(value) > 0.5f && value != previousValue)
{
// It is common to have multiple axes 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 axes 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 ? '-' : '+';
}
}
// Special case for d-pads (axis value jumps between 0 and 1 without any values
// in between). Without this, the user would need to press the d-pad twice
// due to the first press being caught by the "if (firstEvent)" case further up.
else if (Math.abs(value) < 0.25f && Math.abs(previousValue) > 0.75f)
{
numMovedAxis++;
lastMovedRange = range;
lastMovedDir = previousValue < 0.0f ? '-' : '+';
}
}
// Only handle the axes that are not neutral (more than 0.5)
// but ignore any axis that has a constant value (e.g. always 1)
if (Math.abs(value) > 0.5f && value != previousValue)
{
// It is common to have multiple axes 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 axes 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 ? '-' : '+';
}
}
// Special case for d-pads (axis value jumps between 0 and 1 without any values
// in between). Without this, the user would need to press the d-pad twice
// due to the first press being caught by the "if (firstEvent)" case further up.
else if (Math.abs(value) < 0.25f && Math.abs(previousValue) > 0.75f)
{
numMovedAxis++;
lastMovedRange = range;
lastMovedDir = previousValue < 0.0f ? '-' : '+';
}
}
mPreviousValues.set(i, value);
}
mPreviousValues.set(i, value);
}
// If only one axis moved, that's the winner.
if (numMovedAxis == 1)
{
mWaitingForEvent = false;
saveMotionInput(input, lastMovedRange, lastMovedDir);
}
}
// If only one axis moved, that's the winner.
if (numMovedAxis == 1)
{
mWaitingForEvent = false;
saveMotionInput(input, lastMovedRange, lastMovedDir);
}
}
return true;
}
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();
}
private void clearBinding()
{
setting.setValue("");
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = preferences.edit();
editor.remove(setting.getKey());
editor.apply();
dismiss();
}
private void clearBinding()
{
setting.setValue("");
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = preferences.edit();
editor.remove(setting.getKey());
editor.apply();
dismiss();
}
}

View File

@ -2,27 +2,27 @@ package org.dolphinemu.dolphinemu.features.settings.model;
public final class BooleanSetting extends Setting
{
private boolean mValue;
private boolean mValue;
public BooleanSetting(String key, String section, boolean value)
{
super(key, section);
mValue = value;
}
public BooleanSetting(String key, String section, boolean value)
{
super(key, section);
mValue = value;
}
public boolean getValue()
{
return mValue;
}
public boolean getValue()
{
return mValue;
}
public void setValue(boolean value)
{
mValue = value;
}
public void setValue(boolean value)
{
mValue = value;
}
@Override
public String getValueAsString()
{
return mValue ? "True" : "False";
}
@Override
public String getValueAsString()
{
return mValue ? "True" : "False";
}
}

View File

@ -2,27 +2,27 @@ package org.dolphinemu.dolphinemu.features.settings.model;
public final class FloatSetting extends Setting
{
private float mValue;
private float mValue;
public FloatSetting(String key, String section, float value)
{
super(key, section);
mValue = value;
}
public FloatSetting(String key, String section, float value)
{
super(key, section);
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);
}
}

View File

@ -4,41 +4,41 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class IntSetting extends Setting
{
private int mValue;
private MenuTag menuTag;
private int mValue;
private MenuTag menuTag;
public IntSetting(String key, String section, int value)
{
super(key, section);
mValue = value;
}
public IntSetting(String key, String section, int value)
{
super(key, section);
mValue = value;
}
public IntSetting(String key, String section, int value, MenuTag menuTag)
{
super(key, section);
mValue = value;
this.menuTag = menuTag;
}
public IntSetting(String key, String section, int value, MenuTag menuTag)
{
super(key, section);
mValue = value;
this.menuTag = menuTag;
}
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);
}
public MenuTag getMenuTag()
{
return menuTag;
}
public MenuTag getMenuTag()
{
return menuTag;
}
}

View File

@ -8,42 +8,40 @@ package org.dolphinemu.dolphinemu.features.settings.model;
*/
public abstract class Setting
{
private String mKey;
private String mSection;
private String mKey;
private String mSection;
/**
* 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.
*/
public Setting(String key, String section)
{
mKey = key;
mSection = section;
}
/**
* 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.
*/
public Setting(String key, String section)
{
mKey = key;
mSection = section;
}
/**
*
* @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 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();
}

View File

@ -8,56 +8,56 @@ import java.util.HashMap;
*/
public final class SettingSection
{
private String mName;
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;
}
public void mergeSection(SettingSection settingSection)
{
for (Setting setting : settingSection.mSettings.values())
{
putSetting(setting);
}
}
public void mergeSection(SettingSection settingSection)
{
for (Setting setting : settingSection.mSettings.values())
{
putSetting(setting);
}
}
}

View File

@ -14,168 +14,174 @@ import java.util.TreeMap;
public class Settings
{
public static final String SECTION_INI_CORE = "Core";
public static final String SECTION_INI_INTERFACE = "Interface";
public static final String SECTION_INI_CORE = "Core";
public static final String SECTION_INI_INTERFACE = "Interface";
public static final String SECTION_GFX_SETTINGS = "Settings";
public static final String SECTION_GFX_ENHANCEMENTS = "Enhancements";
public static final String SECTION_GFX_HACKS = "Hacks";
public static final String SECTION_GFX_SETTINGS = "Settings";
public static final String SECTION_GFX_ENHANCEMENTS = "Enhancements";
public static final String SECTION_GFX_HACKS = "Hacks";
public static final String SECTION_STEREOSCOPY = "Stereoscopy";
public static final String SECTION_STEREOSCOPY = "Stereoscopy";
public static final String SECTION_WIIMOTE = "Wiimote";
public static final String SECTION_WIIMOTE = "Wiimote";
public static final String SECTION_BINDINGS = "Android";
public static final String SECTION_BINDINGS = "Android";
public static final String SECTION_ANALYTICS = "Analytics";
public static final String SECTION_ANALYTICS = "Analytics";
private String gameId;
private String gameId;
private static final Map<String, List<String>> configFileSectionsMap = new HashMap<>();
private static final Map<String, List<String>> configFileSectionsMap = new HashMap<>();
static
static
{
configFileSectionsMap.put(SettingsFile.FILE_NAME_DOLPHIN,
Arrays.asList(SECTION_INI_CORE, SECTION_INI_INTERFACE, SECTION_BINDINGS,
SECTION_ANALYTICS));
configFileSectionsMap.put(SettingsFile.FILE_NAME_GFX,
Arrays.asList(SECTION_GFX_SETTINGS, SECTION_GFX_ENHANCEMENTS, SECTION_GFX_HACKS,
SECTION_STEREOSCOPY));
configFileSectionsMap.put(SettingsFile.FILE_NAME_WIIMOTE,
Arrays.asList(SECTION_WIIMOTE + 1, SECTION_WIIMOTE + 2, SECTION_WIIMOTE + 3,
SECTION_WIIMOTE + 4));
}
/**
* A HashMap<String, SettingSection> that constructs a new SettingSection instead of returning null
* when getting a key not already in the map
*/
public static final class SettingsSectionMap extends HashMap<String, SettingSection>
{
@Override
public SettingSection get(Object key)
{
configFileSectionsMap.put(SettingsFile.FILE_NAME_DOLPHIN, Arrays.asList(SECTION_INI_CORE, SECTION_INI_INTERFACE, SECTION_BINDINGS, SECTION_ANALYTICS));
configFileSectionsMap.put(SettingsFile.FILE_NAME_GFX, Arrays.asList(SECTION_GFX_SETTINGS, SECTION_GFX_ENHANCEMENTS, SECTION_GFX_HACKS, SECTION_STEREOSCOPY));
configFileSectionsMap.put(SettingsFile.FILE_NAME_WIIMOTE, Arrays.asList(SECTION_WIIMOTE + 1, SECTION_WIIMOTE + 2, SECTION_WIIMOTE + 3, SECTION_WIIMOTE + 4));
if (!(key instanceof String))
{
return null;
}
String stringKey = (String) key;
if (!super.containsKey(stringKey))
{
SettingSection section = new SettingSection(stringKey);
super.put(stringKey, section);
return section;
}
return super.get(key);
}
}
private HashMap<String, SettingSection> sections = new Settings.SettingsSectionMap();
public SettingSection getSection(String sectionName)
{
return sections.get(sectionName);
}
public boolean isEmpty()
{
return sections.isEmpty();
}
public HashMap<String, SettingSection> getSections()
{
return sections;
}
public void loadSettings(SettingsActivityView view)
{
sections = new Settings.SettingsSectionMap();
HashSet<String> filesToExclude = new HashSet<>();
if (!TextUtils.isEmpty(gameId))
{
// for per-game settings, don't load the WiiMoteNew.ini settings
filesToExclude.add(SettingsFile.FILE_NAME_WIIMOTE);
}
/**
* A HashMap<String, SettingSection> that constructs a new SettingSection instead of returning null
* when getting a key not already in the map
*/
public static final class SettingsSectionMap extends HashMap<String, SettingSection>
loadDolphinSettings(view, filesToExclude);
if (!TextUtils.isEmpty(gameId))
{
@Override
public SettingSection get(Object key)
loadGenericGameSettings(gameId, view);
loadCustomGameSettings(gameId, view);
}
}
private void loadDolphinSettings(SettingsActivityView view, HashSet<String> filesToExclude)
{
for (Map.Entry<String, List<String>> entry : configFileSectionsMap.entrySet())
{
String fileName = entry.getKey();
if (filesToExclude == null || !filesToExclude.contains(fileName))
{
sections.putAll(SettingsFile.readFile(fileName, view));
}
}
}
private void loadGenericGameSettings(String gameId, SettingsActivityView view)
{
// generic game settings
mergeSections(SettingsFile.readGenericGameSettings(gameId, view));
mergeSections(SettingsFile.readGenericGameSettingsForAllRegions(gameId, view));
}
private void loadCustomGameSettings(String gameId, SettingsActivityView view)
{
// custom game settings
mergeSections(SettingsFile.readCustomGameSettings(gameId, view));
}
private void mergeSections(HashMap<String, SettingSection> updatedSections)
{
for (Map.Entry<String, SettingSection> entry : updatedSections.entrySet())
{
if (sections.containsKey(entry.getKey()))
{
SettingSection originalSection = sections.get(entry.getKey());
SettingSection updatedSection = entry.getValue();
originalSection.mergeSection(updatedSection);
}
else
{
sections.put(entry.getKey(), entry.getValue());
}
}
}
public void loadSettings(String gameId, SettingsActivityView view)
{
this.gameId = gameId;
loadSettings(view);
}
public void saveSettings(SettingsActivityView view)
{
if (TextUtils.isEmpty(gameId))
{
view.showToastMessage("Saved settings to INI files");
for (Map.Entry<String, List<String>> entry : configFileSectionsMap.entrySet())
{
String fileName = entry.getKey();
List<String> sectionNames = entry.getValue();
TreeMap<String, SettingSection> iniSections = new TreeMap<>();
for (String section : sectionNames)
{
if (!(key instanceof String))
{
return null;
}
String stringKey = (String) key;
if (!super.containsKey(stringKey))
{
SettingSection section = new SettingSection(stringKey);
super.put(stringKey, section);
return section;
}
return super.get(key);
}
}
private HashMap<String, SettingSection> sections = new Settings.SettingsSectionMap();
public SettingSection getSection(String sectionName)
{
return sections.get(sectionName);
}
public boolean isEmpty()
{
return sections.isEmpty();
}
public HashMap<String, SettingSection> getSections()
{
return sections;
}
public void loadSettings(SettingsActivityView view)
{
sections = new Settings.SettingsSectionMap();
HashSet<String> filesToExclude = new HashSet<>();
if (!TextUtils.isEmpty(gameId))
{
// for per-game settings, don't load the WiiMoteNew.ini settings
filesToExclude.add(SettingsFile.FILE_NAME_WIIMOTE);
iniSections.put(section, sections.get(section));
}
loadDolphinSettings(view, filesToExclude);
if (!TextUtils.isEmpty(gameId))
{
loadGenericGameSettings(gameId, view);
loadCustomGameSettings(gameId, view);
}
SettingsFile.saveFile(fileName, iniSections, view);
}
}
private void loadDolphinSettings(SettingsActivityView view, HashSet<String> filesToExclude)
else
{
for (Map.Entry<String, List<String>> entry : configFileSectionsMap.entrySet())
{
String fileName = entry.getKey();
if(filesToExclude == null || !filesToExclude.contains(fileName))
{
sections.putAll(SettingsFile.readFile(fileName, view));
}
}
// custom game settings
view.showToastMessage("Saved settings for " + gameId);
SettingsFile.saveCustomGameSettings(gameId, sections);
}
private void loadGenericGameSettings(String gameId, SettingsActivityView view)
{
// generic game settings
mergeSections(SettingsFile.readGenericGameSettings(gameId, view));
mergeSections(SettingsFile.readGenericGameSettingsForAllRegions(gameId, view));
}
private void loadCustomGameSettings(String gameId, SettingsActivityView view)
{
// custom game settings
mergeSections(SettingsFile.readCustomGameSettings(gameId, view));
}
private void mergeSections(HashMap<String, SettingSection> updatedSections)
{
for (Map.Entry<String, SettingSection> entry : updatedSections.entrySet())
{
if (sections.containsKey(entry.getKey()))
{
SettingSection originalSection = sections.get(entry.getKey());
SettingSection updatedSection = entry.getValue();
originalSection.mergeSection(updatedSection);
}
else
{
sections.put(entry.getKey(), entry.getValue());
}
}
}
public void loadSettings(String gameId, SettingsActivityView view)
{
this.gameId = gameId;
loadSettings(view);
}
public void saveSettings(SettingsActivityView view)
{
if (TextUtils.isEmpty(gameId))
{
view.showToastMessage("Saved settings to INI files");
for (Map.Entry<String, List<String>> entry : configFileSectionsMap.entrySet())
{
String fileName = entry.getKey();
List<String> sectionNames = entry.getValue();
TreeMap<String, SettingSection> iniSections = new TreeMap<>();
for (String section : sectionNames)
{
iniSections.put(section, sections.get(section));
}
SettingsFile.saveFile(fileName, iniSections, view);
}
}
else
{
// custom game settings
view.showToastMessage("Saved settings for " + gameId);
SettingsFile.saveCustomGameSettings(gameId, sections);
}
}
}
}

View File

@ -2,27 +2,27 @@ package org.dolphinemu.dolphinemu.features.settings.model;
public final class StringSetting extends Setting
{
private String mValue;
private String mValue;
public StringSetting(String key, String section, String value)
{
super(key, section);
mValue = value;
}
public StringSetting(String key, String section, String value)
{
super(key, section);
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;
}
}

View File

@ -5,51 +5,52 @@ import org.dolphinemu.dolphinemu.features.settings.model.Setting;
public final class CheckBoxSetting extends SettingsItem
{
private boolean mDefaultValue;
private boolean mDefaultValue;
public CheckBoxSetting(String key, String section, int titleId, int descriptionId, boolean defaultValue, Setting setting)
{
super(key, section, setting, titleId, descriptionId);
mDefaultValue = defaultValue;
}
public CheckBoxSetting(String key, String section, int titleId, int descriptionId,
boolean defaultValue, Setting setting)
{
super(key, section, setting, titleId, descriptionId);
mDefaultValue = defaultValue;
}
public boolean isChecked()
{
if (getSetting() == null)
{
return mDefaultValue;
}
public boolean isChecked()
{
if (getSetting() == null)
{
return mDefaultValue;
}
BooleanSetting setting = (BooleanSetting) getSetting();
return setting.getValue();
}
BooleanSetting setting = (BooleanSetting) getSetting();
return setting.getValue();
}
/**
* 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 BooleanSetting setChecked(boolean checked)
{
if (getSetting() == null)
{
BooleanSetting setting = new BooleanSetting(getKey(), getSection(), checked);
setSetting(setting);
return setting;
}
else
{
BooleanSetting setting = (BooleanSetting) getSetting();
setting.setValue(checked);
return null;
}
}
/**
* 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 BooleanSetting setChecked(boolean checked)
{
if (getSetting() == null)
{
BooleanSetting setting = new BooleanSetting(getKey(), getSection(), checked);
setSetting(setting);
return setting;
}
else
{
BooleanSetting setting = (BooleanSetting) getSetting();
setting.setValue(checked);
return null;
}
}
@Override
public int getType()
{
return TYPE_CHECKBOX;
}
@Override
public int getType()
{
return TYPE_CHECKBOX;
}
}

View File

@ -4,14 +4,14 @@ import org.dolphinemu.dolphinemu.features.settings.model.Setting;
public final class HeaderSetting extends SettingsItem
{
public HeaderSetting(String key, Setting setting, int titleId, int descriptionId)
{
super(key, null, setting, titleId, descriptionId);
}
public HeaderSetting(String key, Setting setting, int titleId, int descriptionId)
{
super(key, null, setting, titleId, descriptionId);
}
@Override
public int getType()
{
return SettingsItem.TYPE_HEADER;
}
@Override
public int getType()
{
return SettingsItem.TYPE_HEADER;
}
}

View File

@ -5,48 +5,48 @@ import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
public final class InputBindingSetting extends SettingsItem
{
public InputBindingSetting(String key, String section, int titleId, Setting setting)
{
super(key, section, setting, titleId, 0);
}
public InputBindingSetting(String key, String section, int titleId, Setting setting)
{
super(key, section, setting, titleId, 0);
}
public String getValue()
{
if (getSetting() == null)
{
return "";
}
public String getValue()
{
if (getSetting() == null)
{
return "";
}
StringSetting setting = (StringSetting) getSetting();
return setting.getValue();
}
StringSetting setting = (StringSetting) getSetting();
return setting.getValue();
}
/**
* 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(), bind);
setSetting(setting);
return setting;
}
else
{
StringSetting setting = (StringSetting) getSetting();
setting.setValue(bind);
return null;
}
}
/**
* 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(), bind);
setSetting(setting);
return setting;
}
else
{
StringSetting setting = (StringSetting) getSetting();
setting.setValue(bind);
return null;
}
}
@Override
public int getType()
{
return TYPE_INPUT_BINDING;
}
@Override
public int getType()
{
return TYPE_INPUT_BINDING;
}
}

View File

@ -1,7 +1,7 @@
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import org.dolphinemu.dolphinemu.features.settings.model.Setting;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
/**
* ViewModel abstraction for an Item in the RecyclerView powering SettingsFragments.
@ -12,99 +12,95 @@ import org.dolphinemu.dolphinemu.features.settings.model.Setting;
*/
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_STRING_SINGLE_CHOICE = 6;
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_STRING_SINGLE_CHOICE = 6;
private String mKey;
private String mSection;
private String mKey;
private String mSection;
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, Setting setting, int nameId, int descriptionId)
{
mKey = key;
mSection = section;
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, Setting setting, int nameId, int descriptionId)
{
mKey = key;
mSection = section;
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 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 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 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();
}

View File

@ -6,80 +6,82 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class SingleChoiceSetting extends SettingsItem
{
private int mDefaultValue;
private int mDefaultValue;
private int mChoicesId;
private int mValuesId;
private MenuTag menuTag;
private int mChoicesId;
private int mValuesId;
private MenuTag menuTag;
public SingleChoiceSetting(String key, String section, int titleId, int descriptionId, int choicesId, int valuesId, int defaultValue, Setting setting, MenuTag menuTag)
{
super(key, section, setting, titleId, descriptionId);
mValuesId = valuesId;
mChoicesId = choicesId;
mDefaultValue = defaultValue;
this.menuTag = menuTag;
}
public SingleChoiceSetting(String key, String section, int titleId, int descriptionId,
int choicesId, int valuesId, int defaultValue, Setting setting, MenuTag menuTag)
{
super(key, section, setting, titleId, descriptionId);
mValuesId = valuesId;
mChoicesId = choicesId;
mDefaultValue = defaultValue;
this.menuTag = menuTag;
}
public SingleChoiceSetting(String key, String section, int titleId, int descriptionId, int choicesId, int valuesId, int defaultValue, Setting setting)
{
this(key, section, titleId, descriptionId, choicesId, valuesId, defaultValue, setting, null);
}
public SingleChoiceSetting(String key, String section, int titleId, int descriptionId,
int choicesId, int valuesId, int defaultValue, Setting setting)
{
this(key, section, titleId, descriptionId, choicesId, valuesId, defaultValue, setting, null);
}
public int getChoicesId()
{
return mChoicesId;
}
public int getChoicesId()
{
return mChoicesId;
}
public int getValuesId()
{
return mValuesId;
}
public int getValuesId()
{
return mValuesId;
}
public int getSelectedValue()
{
if (getSetting() != null)
{
IntSetting setting = (IntSetting) getSetting();
return setting.getValue();
}
else
{
return mDefaultValue;
}
}
public int getSelectedValue()
{
if (getSetting() != null)
{
IntSetting setting = (IntSetting) getSetting();
return setting.getValue();
}
else
{
return mDefaultValue;
}
}
public MenuTag getMenuTag()
{
return menuTag;
}
public MenuTag getMenuTag()
{
return menuTag;
}
/**
* 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(), selection);
setSetting(setting);
return setting;
}
else
{
IntSetting setting = (IntSetting) getSetting();
setting.setValue(selection);
return null;
}
}
/**
* 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(), selection);
setSetting(setting);
return setting;
}
else
{
IntSetting setting = (IntSetting) getSetting();
setting.setValue(selection);
return null;
}
}
@Override
public int getType()
{
return TYPE_SINGLE_CHOICE;
}
@Override
public int getType()
{
return TYPE_SINGLE_CHOICE;
}
}

View File

@ -3,117 +3,118 @@ package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.FloatSetting;
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Setting;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.utils.Log;
public final class SliderSetting extends SettingsItem
{
private int mMax;
private int mDefaultValue;
private int mMax;
private int mDefaultValue;
private String mUnits;
private String mUnits;
public SliderSetting(String key, String section, int titleId, int descriptionId, int max, String units, int defaultValue, Setting setting)
{
super(key, section, setting, titleId, descriptionId);
mMax = max;
mUnits = units;
mDefaultValue = defaultValue;
}
public SliderSetting(String key, String section, int titleId, int descriptionId, int max,
String units, int defaultValue, Setting setting)
{
super(key, section, setting, titleId, descriptionId);
mMax = max;
mUnits = units;
mDefaultValue = defaultValue;
}
public int getMax()
{
return mMax;
}
public int getMax()
{
return mMax;
}
public int getSelectedValue()
{
Setting setting = getSetting();
public int getSelectedValue()
{
Setting setting = getSetting();
if (setting == null)
{
return mDefaultValue;
}
if (setting == null)
{
return mDefaultValue;
}
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_OVERCLOCK_PERCENT)
|| floatSetting.getKey().equals(SettingsFile.KEY_SPEED_LIMIT))
{
return Math.round(floatSetting.getValue() * 100);
}
else
{
return Math.round(floatSetting.getValue());
}
}
else
{
Log.error("[SliderSetting] Error casting setting type.");
return -1;
}
}
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_OVERCLOCK_PERCENT)
|| floatSetting.getKey().equals(SettingsFile.KEY_SPEED_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(), selection);
setSetting(setting);
return setting;
}
else
{
IntSetting setting = (IntSetting) getSetting();
setting.setValue(selection);
return null;
}
}
/**
* 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(), 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(), selection);
setSetting(setting);
return setting;
}
else
{
FloatSetting setting = (FloatSetting) 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(), selection);
setSetting(setting);
return setting;
}
else
{
FloatSetting setting = (FloatSetting) getSetting();
setting.setValue(selection);
return null;
}
}
public String getUnits()
{
return mUnits;
}
public String getUnits()
{
return mUnits;
}
@Override
public int getType()
{
return TYPE_SLIDER;
}
@Override
public int getType()
{
return TYPE_SLIDER;
}
}

View File

@ -5,93 +5,98 @@ import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
public class StringSingleChoiceSetting extends SettingsItem
{
private String mDefaultValue;
private String mDefaultValue;
private String[] mChoicesId;
private String[] mValuesId;
private String[] mChoicesId;
private String[] mValuesId;
public StringSingleChoiceSetting(String key, String section, int titleId, int descriptionId, String[] choicesId, String[] valuesId, String defaultValue, Setting setting)
public StringSingleChoiceSetting(String key, String section, int titleId, int descriptionId,
String[] choicesId, String[] valuesId, String defaultValue, Setting setting)
{
super(key, section, setting, titleId, descriptionId);
mValuesId = valuesId;
mChoicesId = choicesId;
mDefaultValue = defaultValue;
}
public String[] getChoicesId()
{
return mChoicesId;
}
public String[] getValuesId()
{
return mValuesId;
}
public String getValueAt(int index)
{
if (mValuesId == null)
return null;
if (index >= 0 && index < mValuesId.length)
{
super(key, section, setting, titleId, descriptionId);
mValuesId = valuesId;
mChoicesId = choicesId;
mDefaultValue = defaultValue;
return mValuesId[index];
}
public String[] getChoicesId()
return "";
}
public String getSelectedValue()
{
if (getSetting() != null)
{
return mChoicesId;
StringSetting setting = (StringSetting) getSetting();
return setting.getValue();
}
public String[] getValuesId()
else
{
return mValuesId;
return mDefaultValue;
}
}
public String getValueAt(int index)
public int getSelectValueIndex()
{
String selectedValue = getSelectedValue();
for (int i = 0; i < mValuesId.length; i++)
{
if (mValuesId == null)
return null;
if (index >= 0 && index < mValuesId.length)
{
return mValuesId[index];
}
return "";
if (mValuesId[i].equals(selectedValue))
{
return i;
}
}
public String getSelectedValue()
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 StringSetting setSelectedValue(String selection)
{
if (getSetting() == null)
{
if (getSetting() != null)
{
StringSetting setting = (StringSetting) getSetting();
return setting.getValue();
}
else
{
return mDefaultValue;
}
StringSetting setting = new StringSetting(getKey(), getSection(), selection);
setSetting(setting);
return setting;
}
public int getSelectValueIndex() {
String selectedValue = getSelectedValue();
for(int i=0;i<mValuesId.length;i++) {
if(mValuesId[i].equals(selectedValue)) {
return i;
}
}
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 StringSetting setSelectedValue(String selection)
else
{
if (getSetting() == null)
{
StringSetting setting = new StringSetting(getKey(), getSection(), selection);
setSetting(setting);
return setting;
}
else
{
StringSetting setting = (StringSetting) getSetting();
setting.setValue(selection);
return null;
}
StringSetting setting = (StringSetting) getSetting();
setting.setValue(selection);
return null;
}
}
@Override
public int getType()
{
return TYPE_STRING_SINGLE_CHOICE;
}
@Override
public int getType()
{
return TYPE_STRING_SINGLE_CHOICE;
}
}

View File

@ -5,22 +5,23 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class SubmenuSetting extends SettingsItem
{
private MenuTag mMenuKey;
private MenuTag mMenuKey;
public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, MenuTag menuKey)
{
super(key, null, setting, titleId, descriptionId);
mMenuKey = menuKey;
}
public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId,
MenuTag menuKey)
{
super(key, null, setting, titleId, descriptionId);
mMenuKey = menuKey;
}
public MenuTag getMenuKey()
{
return mMenuKey;
}
public MenuTag getMenuKey()
{
return mMenuKey;
}
@Override
public int getType()
{
return TYPE_SUBMENU;
}
@Override
public int getType()
{
return TYPE_SUBMENU;
}
}

View File

@ -2,105 +2,105 @@ package org.dolphinemu.dolphinemu.features.settings.ui;
public enum MenuTag
{
CONFIG("config"),
CONFIG_GENERAL("config_general"),
CONFIG_INTERFACE("config_interface"),
CONFIG_GAME_CUBE("config_gamecube"),
CONFIG_WII("config_wii"),
WIIMOTE("wiimote"),
WIIMOTE_EXTENSION("wiimote_extension"),
GCPAD_TYPE("gc_pad_type"),
GRAPHICS("graphics"),
HACKS("hacks"),
ENHANCEMENTS("enhancements"),
STEREOSCOPY("stereoscopy"),
GCPAD_1("gcpad", 0),
GCPAD_2("gcpad", 1),
GCPAD_3("gcpad", 2),
GCPAD_4("gcpad", 3),
WIIMOTE_1("wiimote", 4),
WIIMOTE_2("wiimote", 5),
WIIMOTE_3("wiimote", 6),
WIIMOTE_4("wiimote", 7),
WIIMOTE_EXTENSION_1("wiimote_extension", 4),
WIIMOTE_EXTENSION_2("wiimote_extension", 5),
WIIMOTE_EXTENSION_3("wiimote_extension", 6),
WIIMOTE_EXTENSION_4("wiimote_extension", 7);
CONFIG("config"),
CONFIG_GENERAL("config_general"),
CONFIG_INTERFACE("config_interface"),
CONFIG_GAME_CUBE("config_gamecube"),
CONFIG_WII("config_wii"),
WIIMOTE("wiimote"),
WIIMOTE_EXTENSION("wiimote_extension"),
GCPAD_TYPE("gc_pad_type"),
GRAPHICS("graphics"),
HACKS("hacks"),
ENHANCEMENTS("enhancements"),
STEREOSCOPY("stereoscopy"),
GCPAD_1("gcpad", 0),
GCPAD_2("gcpad", 1),
GCPAD_3("gcpad", 2),
GCPAD_4("gcpad", 3),
WIIMOTE_1("wiimote", 4),
WIIMOTE_2("wiimote", 5),
WIIMOTE_3("wiimote", 6),
WIIMOTE_4("wiimote", 7),
WIIMOTE_EXTENSION_1("wiimote_extension", 4),
WIIMOTE_EXTENSION_2("wiimote_extension", 5),
WIIMOTE_EXTENSION_3("wiimote_extension", 6),
WIIMOTE_EXTENSION_4("wiimote_extension", 7);
private String tag;
private int subType = -1;
private String tag;
private int subType = -1;
MenuTag(String tag)
MenuTag(String tag)
{
this.tag = tag;
}
MenuTag(String tag, int subtype)
{
this.tag = tag;
this.subType = subtype;
}
@Override
public String toString()
{
if (subType != -1)
{
this.tag = tag;
return tag + subType;
}
MenuTag(String tag, int subtype)
return tag;
}
public String getTag()
{
return tag;
}
public int getSubType()
{
return subType;
}
public boolean isGCPadMenu()
{
return this == GCPAD_1 || this == GCPAD_2 || this == GCPAD_3 || this == GCPAD_4;
}
public boolean isWiimoteMenu()
{
return this == WIIMOTE_1 || this == WIIMOTE_2 || this == WIIMOTE_3 || this == WIIMOTE_4;
}
public boolean isWiimoteExtensionMenu()
{
return this == WIIMOTE_EXTENSION_1 || this == WIIMOTE_EXTENSION_2
|| this == WIIMOTE_EXTENSION_3 || this == WIIMOTE_EXTENSION_4;
}
public static MenuTag getGCPadMenuTag(int subtype)
{
return getMenuTag("gcpad", subtype);
}
public static MenuTag getWiimoteMenuTag(int subtype)
{
return getMenuTag("wiimote", subtype);
}
public static MenuTag getWiimoteExtensionMenuTag(int subtype)
{
return getMenuTag("wiimote_extension", subtype);
}
private static MenuTag getMenuTag(String tag, int subtype)
{
for (MenuTag menuTag : MenuTag.values())
{
this.tag = tag;
this.subType = subtype;
if (menuTag.tag.equals(tag) && menuTag.subType == subtype) return menuTag;
}
@Override
public String toString()
{
if (subType != -1)
{
return tag + subType;
}
return tag;
}
public String getTag()
{
return tag;
}
public int getSubType()
{
return subType;
}
public boolean isGCPadMenu()
{
return this == GCPAD_1 || this == GCPAD_2 || this == GCPAD_3 || this == GCPAD_4;
}
public boolean isWiimoteMenu()
{
return this == WIIMOTE_1 || this == WIIMOTE_2 || this == WIIMOTE_3 || this == WIIMOTE_4;
}
public boolean isWiimoteExtensionMenu()
{
return this == WIIMOTE_EXTENSION_1 || this == WIIMOTE_EXTENSION_2
|| this == WIIMOTE_EXTENSION_3 || this == WIIMOTE_EXTENSION_4;
}
public static MenuTag getGCPadMenuTag(int subtype)
{
return getMenuTag("gcpad", subtype);
}
public static MenuTag getWiimoteMenuTag(int subtype)
{
return getMenuTag("wiimote", subtype);
}
public static MenuTag getWiimoteExtensionMenuTag(int subtype)
{
return getMenuTag("wiimote_extension", subtype);
}
private static MenuTag getMenuTag(String tag, int subtype)
{
for (MenuTag menuTag : MenuTag.values())
{
if (menuTag.tag.equals(tag) && menuTag.subType == subtype) return menuTag;
}
throw new IllegalArgumentException("You are asking for a menu that is not available or " +
"passing a wrong subtype");
}
throw new IllegalArgumentException("You are asking for a menu that is not available or " +
"passing a wrong subtype");
}
}

View File

@ -15,247 +15,248 @@ import android.view.MenuItem;
import android.widget.Toast;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.SettingSection;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
import java.util.HashMap;
public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView
{
private static final String ARG_MENU_TAG = "menu_tag";
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 ARG_MENU_TAG = "menu_tag";
private static final String ARG_GAME_ID = "game_id";
private static final String FRAGMENT_TAG = "settings";
private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this);
private ProgressDialog dialog;
private ProgressDialog dialog;
public static void launch(Context context, MenuTag menuTag, String gameId)
{
Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARG_MENU_TAG, menuTag);
settings.putExtra(ARG_GAME_ID, gameId);
context.startActivity(settings);
}
public static void launch(Context context, MenuTag menuTag, String gameId)
{
Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARG_MENU_TAG, menuTag);
settings.putExtra(ARG_GAME_ID, gameId);
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 gameID = launcher.getStringExtra(ARG_GAME_ID);
MenuTag menuTag = (MenuTag) launcher.getSerializableExtra(ARG_MENU_TAG);
mPresenter.onCreate(savedInstanceState, menuTag, gameID);
}
Intent launcher = getIntent();
String gameID = launcher.getStringExtra(ARG_GAME_ID);
MenuTag menuTag = (MenuTag) launcher.getSerializableExtra(ARG_MENU_TAG);
mPresenter.onCreate(savedInstanceState, menuTag, 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(MenuTag menuTag, Bundle extras, boolean addToStack, String gameID)
{
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
@Override
public void showSettingsFragment(MenuTag menuTag, Bundle extras, 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, extras), FRAGMENT_TAG);
transaction.addToBackStack(null);
mPresenter.addToStack();
}
transaction.replace(R.id.frame_content, SettingsFragment.newInstance(menuTag, gameID, extras),
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 org.dolphinemu.dolphinemu.features.settings.model.Settings getSettings()
{
return mPresenter.getSettings();
}
@Override
public org.dolphinemu.dolphinemu.features.settings.model.Settings getSettings()
{
return mPresenter.getSettings();
}
@Override
public void setSettings(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
{
mPresenter.setSettings(settings);
}
@Override
public void setSettings(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
{
mPresenter.setSettings(settings);
}
@Override
public void onSettingsFileLoaded(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
{
SettingsFragmentView fragment = getFragment();
@Override
public void onSettingsFileLoaded(
org.dolphinemu.dolphinemu.features.settings.model.Settings 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(MenuTag key, int value)
{
mPresenter.onGcPadSettingChanged(key, value);
}
@Override
public void onGcPadSettingChanged(MenuTag key, int value)
{
mPresenter.onGcPadSettingChanged(key, value);
}
@Override
public void onWiimoteSettingChanged(MenuTag section, int value)
{
mPresenter.onWiimoteSettingChanged(section, value);
}
@Override
public void onWiimoteSettingChanged(MenuTag section, int value)
{
mPresenter.onWiimoteSettingChanged(section, value);
}
@Override
public void onExtensionSettingChanged(MenuTag menuTag, int value)
{
mPresenter.onExtensionSettingChanged(menuTag, value);
}
@Override
public void onExtensionSettingChanged(MenuTag menuTag, int value)
{
mPresenter.onExtensionSettingChanged(menuTag, value);
}
private SettingsFragment getFragment()
{
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
private SettingsFragment getFragment()
{
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
}

View File

@ -13,194 +13,197 @@ import org.dolphinemu.dolphinemu.utils.Log;
public final class SettingsActivityPresenter
{
private static final String KEY_SHOULD_SAVE = "should_save";
private static final String KEY_SHOULD_SAVE = "should_save";
private SettingsActivityView mView;
private SettingsActivityView mView;
private Settings mSettings = new Settings();
private Settings mSettings = new Settings();
private int mStackCount;
private int mStackCount;
private boolean mShouldSave;
private boolean mShouldSave;
private DirectoryStateReceiver directoryStateReceiver;
private DirectoryStateReceiver directoryStateReceiver;
private MenuTag menuTag;
private String gameId;
private MenuTag menuTag;
private String gameId;
SettingsActivityPresenter(SettingsActivityView view)
SettingsActivityPresenter(SettingsActivityView view)
{
mView = view;
}
public void onCreate(Bundle savedInstanceState, MenuTag menuTag, String gameId)
{
if (savedInstanceState == null)
{
mView = view;
this.menuTag = menuTag;
this.gameId = gameId;
}
else
{
mShouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
}
}
public void onStart()
{
prepareDolphinDirectoriesIfNeeded();
}
private void loadSettingsUI()
{
if (mSettings.isEmpty())
{
if (!TextUtils.isEmpty(gameId))
{
mSettings.loadSettings(gameId, mView);
}
else
{
mSettings.loadSettings(mView);
}
}
public void onCreate(Bundle savedInstanceState, MenuTag menuTag, String gameId)
mView.showSettingsFragment(menuTag, null, false, gameId);
mView.onSettingsFileLoaded(mSettings);
}
private void prepareDolphinDirectoriesIfNeeded()
{
if (DirectoryInitializationService.areDolphinDirectoriesReady())
{
if (savedInstanceState == null)
{
this.menuTag = menuTag;
this.gameId = gameId;
}
else
{
mShouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
}
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();
}
});
mView.startDirectoryInitializationService(directoryStateReceiver, statusIntentFilter);
}
}
public void setSettings(Settings settings)
{
mSettings = settings;
}
public Settings getSettings()
{
return mSettings;
}
public void onStop(boolean finishing)
{
if (directoryStateReceiver != null)
{
mView.stopListeningToDirectoryInitializationService(directoryStateReceiver);
directoryStateReceiver = null;
}
public void onStart()
if (mSettings != null && finishing && mShouldSave)
{
prepareDolphinDirectoriesIfNeeded();
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
mSettings.saveSettings(mView);
}
}
public void addToStack()
{
mStackCount++;
}
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;
}
private void loadSettingsUI()
return false;
}
public void onSettingChanged()
{
mShouldSave = true;
}
public void saveState(Bundle outState)
{
outState.putBoolean(KEY_SHOULD_SAVE, mShouldSave);
}
public void onGcPadSettingChanged(MenuTag key, int value)
{
if (value != 0) // Not disabled
{
if (mSettings.isEmpty())
{
if (!TextUtils.isEmpty(gameId))
{
mSettings.loadSettings(gameId, mView);
}
else
{
mSettings.loadSettings(mView);
}
}
mView.showSettingsFragment(menuTag, null, false, gameId);
mView.onSettingsFileLoaded(mSettings);
Bundle bundle = new Bundle();
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value / 6);
mView.showSettingsFragment(key, bundle, true, gameId);
}
}
private void prepareDolphinDirectoriesIfNeeded()
public void onWiimoteSettingChanged(MenuTag menuTag, int value)
{
switch (value)
{
if (DirectoryInitializationService.areDolphinDirectoriesReady())
{
loadSettingsUI();
}
else
{
mView.showLoading();
IntentFilter statusIntentFilter = new IntentFilter(
DirectoryInitializationService.BROADCAST_ACTION);
case 1:
mView.showSettingsFragment(menuTag, null, true, gameId);
break;
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);
}
case 2:
mView.showToastMessage("Please make sure Continuous Scanning is enabled in Core Settings.");
break;
}
}
public void setSettings(Settings settings)
public void onExtensionSettingChanged(MenuTag menuTag, int value)
{
if (value != 0) // None
{
mSettings = settings;
}
public Settings getSettings()
{
return mSettings;
}
public void onStop(boolean finishing)
{
if (directoryStateReceiver != null)
{
mView.stopListeningToDirectoryInitializationService(directoryStateReceiver);
directoryStateReceiver = null;
}
if (mSettings != null && finishing && mShouldSave)
{
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
mSettings.saveSettings(mView);
}
}
public void addToStack()
{
mStackCount++;
}
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;
}
return false;
}
public void onSettingChanged()
{
mShouldSave = true;
}
public void saveState(Bundle outState)
{
outState.putBoolean(KEY_SHOULD_SAVE, mShouldSave);
}
public void onGcPadSettingChanged(MenuTag key, int value)
{
if (value != 0) // Not disabled
{
Bundle bundle = new Bundle();
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value / 6);
mView.showSettingsFragment(key, bundle, true, gameId);
}
}
public void onWiimoteSettingChanged(MenuTag menuTag, int value)
{
switch (value)
{
case 1:
mView.showSettingsFragment(menuTag, null, true, gameId);
break;
case 2:
mView.showToastMessage("Please make sure Continuous Scanning is enabled in Core Settings.");
break;
}
}
public void onExtensionSettingChanged(MenuTag menuTag, int value)
{
if (value != 0) // None
{
Bundle bundle = new Bundle();
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value);
mView.showSettingsFragment(menuTag, bundle, true, gameId);
}
Bundle bundle = new Bundle();
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value);
mView.showSettingsFragment(menuTag, bundle, true, gameId);
}
}
}

View File

@ -11,126 +11,126 @@ import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
*/
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(MenuTag menuTag, Bundle extras, boolean addToStack, String gameId);
/**
* 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(MenuTag menuTag, Bundle extras, 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.
*
* @return A possibly null HashMap of Settings.
*/
Settings getSettings();
/**
* 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.
*
* @return A possibly null HashMap of Settings.
*/
Settings getSettings();
/**
* 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(Settings 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(Settings settings);
/**
* Called when an asynchronous load operation completes.
*
* @param settings The (possibly null) result of the ini load operation.
*/
void onSettingsFileLoaded(Settings settings);
/**
* Called when an asynchronous load operation completes.
*
* @param settings The (possibly null) result of the ini load operation.
*/
void onSettingsFileLoaded(Settings 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 menuTag Identifier for the GCPad that was modified.
* @param value New setting for the GCPad.
*/
void onGcPadSettingChanged(MenuTag menuTag, int value);
/**
* Called by a containing Fragment to tell the containing Activity that a GCPad's setting
* was modified.
*
* @param menuTag Identifier for the GCPad that was modified.
* @param value New setting for the GCPad.
*/
void onGcPadSettingChanged(MenuTag menuTag, int value);
/**
* Called by a containing Fragment to tell the containing Activity that a Wiimote's setting
* was modified.
*
* @param menuTag Identifier for Wiimote that was modified.
* @param value New setting for the Wiimote.
*/
void onWiimoteSettingChanged(MenuTag menuTag, int value);
/**
* Called by a containing Fragment to tell the containing Activity that a Wiimote's setting
* was modified.
*
* @param menuTag Identifier for Wiimote that was modified.
* @param value New setting for the Wiimote.
*/
void onWiimoteSettingChanged(MenuTag menuTag, int value);
/**
* Called by a containing Fragment to tell the containing Activity that an extension setting
* was modified.
*
* @param menuTag Identifier for the extension that was modified.
* @param value New setting for the extension.
*/
void onExtensionSettingChanged(MenuTag menuTag, int value);
/**
* Called by a containing Fragment to tell the containing Activity that an extension setting
* was modified.
*
* @param menuTag Identifier for the extension that was modified.
* @param value New setting for the extension.
*/
void onExtensionSettingChanged(MenuTag menuTag, 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);
}

View File

@ -33,406 +33,417 @@ import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SettingViewHold
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SingleChoiceViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SliderViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SubmenuViewHolder;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile;
import org.dolphinemu.dolphinemu.utils.Log;
import java.util.ArrayList;
public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener
{
private SettingsFragmentView mView;
private Context mContext;
private ArrayList<SettingsItem> mSettings;
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);
case SettingsItem.TYPE_CHECKBOX:
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false);
return new CheckBoxSettingViewHolder(view, this);
case SettingsItem.TYPE_STRING_SINGLE_CHOICE:
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_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);
default:
Log.error("[SettingsAdapter] Invalid view type: " + viewType);
return null;
}
}
@Override
public void onBindViewHolder(SettingViewHolder holder, int position)
{
holder.bind(getItem(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 getItemViewType(int position)
{
return getItem(position).getType();
}
public void setSettings(ArrayList<SettingsItem> settings)
{
mSettings = settings;
notifyDataSetChanged();
}
public void onBooleanClick(CheckBoxSetting item, int position, boolean checked)
{
BooleanSetting setting = item.setChecked(checked);
notifyItemChanged(position);
if (setting != null)
{
mView.putSetting(setting);
}
if (item.getKey().equals(SettingsFile.KEY_SKIP_EFB) || item.getKey().equals(SettingsFile.KEY_IGNORE_FORMAT))
{
mView.putSetting(new BooleanSetting(item.getKey(), item.getSection(), !checked));
}
mView.onSettingChanged();
}
public void onSingleChoiceClick(SingleChoiceSetting item)
{
mClickedItem = item;
int value = getSelectionForSingleChoiceValue(item);
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
builder.setTitle(item.getNameId());
builder.setSingleChoiceItems(item.getChoicesId(), value, this);
mDialog = builder.show();
}
public void onStringSingleChoiceClick(StringSingleChoiceSetting item)
{
mClickedItem = item;
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
builder.setTitle(item.getNameId());
builder.setSingleChoiceItems(item.getChoicesId(), item.getSelectValueIndex(), this);
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);
builder.setTitle(item.getNameId());
builder.setView(view);
builder.setPositiveButton(R.string.ok, this);
builder.setNegativeButton(R.string.cancel, this);
mDialog = builder.show();
mTextSliderValue = (TextView) view.findViewById(R.id.text_value);
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
TextView units = (TextView) view.findViewById(R.id.text_units);
units.setText(item.getUnits());
SeekBar seekbar = (SeekBar) view.findViewById(R.id.seekbar);
seekbar.setMax(item.getMax());
seekbar.setProgress(mSeekbarProgress);
seekbar.setKeyProgressIncrement(5);
seekbar.setOnSeekBarChangeListener(this);
}
public void onSubmenuClick(SubmenuSetting item)
{
mView.loadSubMenu(item.getMenuKey());
}
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_description), 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("");
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.getValue());
notifyItemChanged(position);
if (setting != null)
{
mView.putSetting(setting);
}
mView.onSettingChanged();
});
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
@Override
public void onClick(DialogInterface dialog, int which)
{
if (mClickedItem instanceof SingleChoiceSetting)
{
SingleChoiceSetting scSetting = (SingleChoiceSetting) mClickedItem;
int value = getValueForSingleChoiceSelection(scSetting, which);
MenuTag menuTag = scSetting.getMenuTag();
if(menuTag != null)
{
if (menuTag.isGCPadMenu())
{
mView.onGcPadSettingChanged(menuTag, value);
}
if (menuTag.isWiimoteMenu())
{
mView.onWiimoteSettingChanged(menuTag, value);
}
if (menuTag.isWiimoteExtensionMenu())
{
mView.onExtensionSettingChanged(menuTag, 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);
}
else
{
if (scSetting.getKey().equals(SettingsFile.KEY_VIDEO_BACKEND_INDEX))
{
putVideoBackendSetting(which);
}
else if (scSetting.getKey().equals(SettingsFile.KEY_WIIMOTE_EXTENSION))
{
putExtensionSetting(which, Character.getNumericValue(scSetting.getSection().charAt(scSetting.getSection().length() - 1)));
}
}
closeDialog();
}
else if (mClickedItem instanceof StringSingleChoiceSetting)
{
StringSingleChoiceSetting scSetting = (StringSingleChoiceSetting) mClickedItem;
String value = scSetting.getValueAt(which);
StringSetting setting = scSetting.setSelectedValue(value);
if (setting != null)
{
mView.putSetting(setting);
}
closeDialog();
}
else if (mClickedItem instanceof SliderSetting)
{
SliderSetting sliderSetting = (SliderSetting) mClickedItem;
if (sliderSetting.getSetting() instanceof FloatSetting)
{
float value;
if (sliderSetting.getKey().equals(SettingsFile.KEY_OVERCLOCK_PERCENT)
|| sliderSetting.getKey().equals(SettingsFile.KEY_SPEED_LIMIT))
{
value = mSeekbarProgress / 100.0f;
}
else
{
value = (float) mSeekbarProgress;
}
FloatSetting setting = sliderSetting.setSelectedValue(value);
if (setting != null)
{
mView.putSetting(setting);
}
}
else
{
IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress);
if (setting != null)
{
mView.putSetting(setting);
}
}
}
mView.onSettingChanged();
mClickedItem = null;
mSeekbarProgress = -1;
}
public void closeDialog()
{
if (mDialog != null)
{
mDialog.dismiss();
mDialog = null;
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
mSeekbarProgress = progress;
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which)
{
int valuesId = item.getValuesId();
if (valuesId > 0)
{
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
return valuesArray[which];
}
else
{
return which;
}
}
private int getSelectionForSingleChoiceValue(SingleChoiceSetting item)
{
int value = item.getSelectedValue();
int valuesId = item.getValuesId();
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;
}
private void putVideoBackendSetting(int which)
switch (viewType)
{
StringSetting gfxBackend = null;
switch (which)
{
case 0:
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "OGL");
break;
case SettingsItem.TYPE_HEADER:
view = inflater.inflate(R.layout.list_item_settings_header, parent, false);
return new HeaderViewHolder(view, this);
case 1:
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "Vulkan");
break;
case SettingsItem.TYPE_CHECKBOX:
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false);
return new CheckBoxSettingViewHolder(view, this);
case 2:
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "Software Renderer");
break;
case SettingsItem.TYPE_STRING_SINGLE_CHOICE:
case SettingsItem.TYPE_SINGLE_CHOICE:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new SingleChoiceViewHolder(view, this);
case 3:
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "Null");
break;
}
case SettingsItem.TYPE_SLIDER:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new SliderViewHolder(view, this);
mView.putSetting(gfxBackend);
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);
default:
Log.error("[SettingsAdapter] Invalid view type: " + viewType);
return null;
}
}
@Override
public void onBindViewHolder(SettingViewHolder holder, int position)
{
holder.bind(getItem(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 getItemViewType(int position)
{
return getItem(position).getType();
}
public void setSettings(ArrayList<SettingsItem> settings)
{
mSettings = settings;
notifyDataSetChanged();
}
public void onBooleanClick(CheckBoxSetting item, int position, boolean checked)
{
BooleanSetting setting = item.setChecked(checked);
notifyItemChanged(position);
if (setting != null)
{
mView.putSetting(setting);
}
private void putExtensionSetting(int which, int wiimoteNumber)
{
StringSetting extension = new StringSetting(SettingsFile.KEY_WIIMOTE_EXTENSION, Settings.SECTION_WIIMOTE + wiimoteNumber, mContext.getResources().getStringArray(R.array.wiimoteExtensionsEntries)[which]);
mView.putSetting(extension);
}
if (item.getKey().equals(SettingsFile.KEY_SKIP_EFB) ||
item.getKey().equals(SettingsFile.KEY_IGNORE_FORMAT))
{
mView.putSetting(new BooleanSetting(item.getKey(), item.getSection(), !checked));
}
mView.onSettingChanged();
}
public void onSingleChoiceClick(SingleChoiceSetting item)
{
mClickedItem = item;
int value = getSelectionForSingleChoiceValue(item);
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
builder.setTitle(item.getNameId());
builder.setSingleChoiceItems(item.getChoicesId(), value, this);
mDialog = builder.show();
}
public void onStringSingleChoiceClick(StringSingleChoiceSetting item)
{
mClickedItem = item;
AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
builder.setTitle(item.getNameId());
builder.setSingleChoiceItems(item.getChoicesId(), item.getSelectValueIndex(), this);
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);
builder.setTitle(item.getNameId());
builder.setView(view);
builder.setPositiveButton(R.string.ok, this);
builder.setNegativeButton(R.string.cancel, this);
mDialog = builder.show();
mTextSliderValue = (TextView) view.findViewById(R.id.text_value);
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
TextView units = (TextView) view.findViewById(R.id.text_units);
units.setText(item.getUnits());
SeekBar seekbar = (SeekBar) view.findViewById(R.id.seekbar);
seekbar.setMax(item.getMax());
seekbar.setProgress(mSeekbarProgress);
seekbar.setKeyProgressIncrement(5);
seekbar.setOnSeekBarChangeListener(this);
}
public void onSubmenuClick(SubmenuSetting item)
{
mView.loadSubMenu(item.getMenuKey());
}
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_description),
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("");
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.getValue());
notifyItemChanged(position);
if (setting != null)
{
mView.putSetting(setting);
}
mView.onSettingChanged();
});
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
@Override
public void onClick(DialogInterface dialog, int which)
{
if (mClickedItem instanceof SingleChoiceSetting)
{
SingleChoiceSetting scSetting = (SingleChoiceSetting) mClickedItem;
int value = getValueForSingleChoiceSelection(scSetting, which);
MenuTag menuTag = scSetting.getMenuTag();
if (menuTag != null)
{
if (menuTag.isGCPadMenu())
{
mView.onGcPadSettingChanged(menuTag, value);
}
if (menuTag.isWiimoteMenu())
{
mView.onWiimoteSettingChanged(menuTag, value);
}
if (menuTag.isWiimoteExtensionMenu())
{
mView.onExtensionSettingChanged(menuTag, 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);
}
else
{
if (scSetting.getKey().equals(SettingsFile.KEY_VIDEO_BACKEND_INDEX))
{
putVideoBackendSetting(which);
}
else if (scSetting.getKey().equals(SettingsFile.KEY_WIIMOTE_EXTENSION))
{
putExtensionSetting(which, Character.getNumericValue(
scSetting.getSection().charAt(scSetting.getSection().length() - 1)));
}
}
closeDialog();
}
else if (mClickedItem instanceof StringSingleChoiceSetting)
{
StringSingleChoiceSetting scSetting = (StringSingleChoiceSetting) mClickedItem;
String value = scSetting.getValueAt(which);
StringSetting setting = scSetting.setSelectedValue(value);
if (setting != null)
{
mView.putSetting(setting);
}
closeDialog();
}
else if (mClickedItem instanceof SliderSetting)
{
SliderSetting sliderSetting = (SliderSetting) mClickedItem;
if (sliderSetting.getSetting() instanceof FloatSetting)
{
float value;
if (sliderSetting.getKey().equals(SettingsFile.KEY_OVERCLOCK_PERCENT)
|| sliderSetting.getKey().equals(SettingsFile.KEY_SPEED_LIMIT))
{
value = mSeekbarProgress / 100.0f;
}
else
{
value = (float) mSeekbarProgress;
}
FloatSetting setting = sliderSetting.setSelectedValue(value);
if (setting != null)
{
mView.putSetting(setting);
}
}
else
{
IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress);
if (setting != null)
{
mView.putSetting(setting);
}
}
}
mView.onSettingChanged();
mClickedItem = null;
mSeekbarProgress = -1;
}
public void closeDialog()
{
if (mDialog != null)
{
mDialog.dismiss();
mDialog = null;
}
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
{
mSeekbarProgress = progress;
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar)
{
}
@Override
public void onStopTrackingTouch(SeekBar seekBar)
{
}
private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which)
{
int valuesId = item.getValuesId();
if (valuesId > 0)
{
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
return valuesArray[which];
}
else
{
return which;
}
}
private int getSelectionForSingleChoiceValue(SingleChoiceSetting item)
{
int value = item.getSelectedValue();
int valuesId = item.getValuesId();
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;
}
private void putVideoBackendSetting(int which)
{
StringSetting gfxBackend = null;
switch (which)
{
case 0:
gfxBackend =
new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "OGL");
break;
case 1:
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE,
"Vulkan");
break;
case 2:
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE,
"Software Renderer");
break;
case 3:
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE,
"Null");
break;
}
mView.putSetting(gfxBackend);
}
private void putExtensionSetting(int which, int wiimoteNumber)
{
StringSetting extension = new StringSetting(SettingsFile.KEY_WIIMOTE_EXTENSION,
Settings.SECTION_WIIMOTE + wiimoteNumber,
mContext.getResources().getStringArray(R.array.wiimoteExtensionsEntries)[which]);
mView.putSetting(extension);
}
}

View File

@ -20,170 +20,173 @@ import java.util.ArrayList;
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 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(MenuTag menuTag, String gameId, Bundle extras)
{
SettingsFragment fragment = new SettingsFragment();
public static Fragment newInstance(MenuTag menuTag, String gameId, Bundle extras)
{
SettingsFragment fragment = new SettingsFragment();
Bundle arguments = new Bundle();
if(extras != null)
{
arguments.putAll(extras);
}
Bundle arguments = new Bundle();
if (extras != null)
{
arguments.putAll(extras);
}
arguments.putSerializable(ARGUMENT_MENU_TAG, menuTag);
arguments.putString(ARGUMENT_GAME_ID, gameId);
arguments.putSerializable(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);
Bundle args = getArguments();
MenuTag menuTag = (MenuTag) args.getSerializable(ARGUMENT_MENU_TAG);
String gameId = getArguments().getString(ARGUMENT_GAME_ID);
setRetainInstance(true);
Bundle args = getArguments();
MenuTag menuTag = (MenuTag) args.getSerializable(ARGUMENT_MENU_TAG);
String gameId = getArguments().getString(ARGUMENT_GAME_ID);
mAdapter = new SettingsAdapter(this, getActivity());
mAdapter = new SettingsAdapter(this, getActivity());
mPresenter.onCreate(menuTag, gameId, args);
}
mPresenter.onCreate(menuTag, gameId, args);
}
@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 = (RecyclerView) view.findViewById(R.id.list_settings);
RecyclerView 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();
mPresenter.onViewCreated(activity.getSettings());
}
SettingsActivityView activity = (SettingsActivityView) getActivity();
mPresenter.onViewCreated(activity.getSettings());
}
@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(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
{
mPresenter.setSettings(settings);
}
@Override
public void onSettingsFileLoaded(
org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
{
mPresenter.setSettings(settings);
}
@Override
public void passSettingsToActivity(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
{
if (mActivity != null)
{
mActivity.setSettings(settings);
}
}
@Override
public void passSettingsToActivity(
org.dolphinemu.dolphinemu.features.settings.model.Settings 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(MenuTag menuKey)
{
mActivity.showSettingsFragment(menuKey, null, true, getArguments().getString(ARGUMENT_GAME_ID));
}
@Override
public void loadSubMenu(MenuTag menuKey)
{
mActivity.showSettingsFragment(menuKey, null, 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(MenuTag menuTag, int value)
{
mActivity.onGcPadSettingChanged(menuTag, value);
}
@Override
public void onGcPadSettingChanged(MenuTag menuTag, int value)
{
mActivity.onGcPadSettingChanged(menuTag, value);
}
@Override
public void onWiimoteSettingChanged(MenuTag menuTag, int value)
{
mActivity.onWiimoteSettingChanged(menuTag, value);
}
@Override
public void onWiimoteSettingChanged(MenuTag menuTag, int value)
{
mActivity.onWiimoteSettingChanged(menuTag, value);
}
@Override
public void onExtensionSettingChanged(MenuTag menuTag, int value)
{
mActivity.onExtensionSettingChanged(menuTag, value);
}
@Override
public void onExtensionSettingChanged(MenuTag menuTag, int value)
{
mActivity.onExtensionSettingChanged(menuTag, value);
}
}

View File

@ -14,89 +14,89 @@ import java.util.ArrayList;
*/
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(Settings settings);
/**
* 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(Settings 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(Settings 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(Settings 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(MenuTag 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(MenuTag 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 menuTag Identifier for the GCPad that was modified.
* @param value New setting for the GCPad.
*/
void onGcPadSettingChanged(MenuTag menuTag, int value);
/**
* Have the fragment tell the containing Activity that a GCPad's setting was modified.
*
* @param menuTag Identifier for the GCPad that was modified.
* @param value New setting for the GCPad.
*/
void onGcPadSettingChanged(MenuTag menuTag, int value);
/**
* Have the fragment tell the containing Activity that a Wiimote's setting was modified.
*
* @param menuTag Identifier for Wiimote that was modified.
* @param value New setting for the Wiimote.
*/
void onWiimoteSettingChanged(MenuTag menuTag, int value);
/**
* Have the fragment tell the containing Activity that a Wiimote's setting was modified.
*
* @param menuTag Identifier for Wiimote that was modified.
* @param value New setting for the Wiimote.
*/
void onWiimoteSettingChanged(MenuTag menuTag, int value);
/**
* Have the fragment tell the containing Activity that an extension setting was modified.
*
* @param menuTag Identifier for the extension that was modified.
* @param value New setting for the extension.
*/
void onExtensionSettingChanged(MenuTag menuTag, int value);
/**
* Have the fragment tell the containing Activity that an extension setting was modified.
*
* @param menuTag Identifier for the extension that was modified.
* @param value New setting for the extension.
*/
void onExtensionSettingChanged(MenuTag menuTag, int value);
}

View File

@ -9,48 +9,48 @@ import android.widget.FrameLayout;
*/
public final class SettingsFrameLayout extends FrameLayout
{
private float mVisibleness = 1.0f;
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);
}
}

View File

@ -11,46 +11,46 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class CheckBoxSettingViewHolder extends SettingViewHolder
{
private CheckBoxSetting mItem;
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 = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
mCheckbox = (CheckBox) root.findViewById(R.id.checkbox);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
mCheckbox = (CheckBox) 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());
}
}

View File

@ -9,29 +9,29 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class HeaderViewHolder extends SettingViewHolder
{
private TextView mHeaderName;
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 = (TextView) root.findViewById(R.id.text_header_name);
}
@Override
protected void findViews(View root)
{
mHeaderName = (TextView) 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
}
}

View File

@ -13,41 +13,41 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class InputBindingSettingViewHolder extends SettingViewHolder
{
private InputBindingSetting mItem;
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 = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) 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());
}
}

View File

@ -6,46 +6,47 @@ import android.view.View;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public abstract class SettingViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
public abstract class SettingViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener
{
private SettingsAdapter mAdapter;
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);
}

View File

@ -11,46 +11,46 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class SingleChoiceViewHolder extends SettingViewHolder
{
private SettingsItem mItem;
private SettingsItem 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 = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
@Override
public void bind(SettingsItem item)
{
mItem = item;
@Override
public void bind(SettingsItem item)
{
mItem = 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)
{
if (mItem instanceof SingleChoiceSetting)
{
getAdapter().onSingleChoiceClick((SingleChoiceSetting) mItem);
}
else if (mItem instanceof StringSingleChoiceSetting)
{
getAdapter().onStringSingleChoiceClick((StringSingleChoiceSetting) mItem);
}
}
@Override
public void onClick(View clicked)
{
if (mItem instanceof SingleChoiceSetting)
{
getAdapter().onSingleChoiceClick((SingleChoiceSetting) mItem);
}
else if (mItem instanceof StringSingleChoiceSetting)
{
getAdapter().onStringSingleChoiceClick((StringSingleChoiceSetting) mItem);
}
}
}

View File

@ -10,40 +10,40 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class SliderViewHolder extends SettingViewHolder
{
private SliderSetting mItem;
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 = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) 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);
}
}

View File

@ -10,39 +10,39 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class SubmenuViewHolder extends SettingViewHolder
{
private SubmenuSetting mItem;
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 = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
}
@Override
protected void findViews(View root)
{
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
mTextSettingDescription = (TextView) 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);
}
}

View File

@ -10,13 +10,13 @@ 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);
}
@NonNull
@Override
public Uri toUri(@NonNull final File file)
{
return FileProvider
.getUriForFile(getContext(),
getContext().getApplicationContext().getPackageName() + ".filesprovider",
file);
}
}

View File

@ -30,433 +30,438 @@ import java.io.File;
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
{
private static final String KEY_GAMEPATH = "gamepath";
private static final String KEY_GAMEPATH = "gamepath";
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;
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;
}
EmulationFragment fragment = new EmulationFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onAttach(Context context)
{
super.onAttach(context);
@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");
}
}
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);
/**
* 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);
// So this fragment doesn't restart on configuration changes; i.e. rotation.
setRetainInstance(true);
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
String gamePath = getArguments().getString(KEY_GAMEPATH);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
boolean firstOpen = preferences.getBoolean(StartupHandler.NEW_SESSION, true);
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putBoolean(StartupHandler.NEW_SESSION, false);
sPrefsEditor.apply();
mEmulationState = new EmulationState(gamePath, getTemporaryStateFilePath(), firstOpen);
}
String gamePath = getArguments().getString(KEY_GAMEPATH);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
boolean firstOpen = preferences.getBoolean(StartupHandler.NEW_SESSION, true);
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putBoolean(StartupHandler.NEW_SESSION, false);
sPrefsEditor.apply();
mEmulationState = new EmulationState(gamePath, getTemporaryStateFilePath(), firstOpen);
}
/**
* 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);
/**
* 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);
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);
}
}
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);
}
}
Button doneButton = contents.findViewById(R.id.done_control_config);
if (doneButton != null)
{
doneButton.setOnClickListener(v -> stopConfiguringControls());
}
Button doneButton = contents.findViewById(R.id.done_control_config);
if (doneButton != null)
{
doneButton.setOnClickListener(v -> stopConfiguringControls());
}
// The new Surface created here will get passed to the native code via onSurfaceChanged.
// The new Surface created here will get passed to the native code via onSurfaceChanged.
return contents;
}
return contents;
}
@Override
public void onResume()
{
super.onResume();
if (DirectoryInitializationService.areDolphinDirectoriesReady())
{
mEmulationState.run(activity.isActivityRecreated());
}
else
{
setupDolphinDirectoriesThenStartEmulation();
}
}
@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;
}
@Override
public void onPause()
{
if (directoryStateReceiver != null)
{
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
directoryStateReceiver = null;
}
mEmulationState.pause();
super.onPause();
}
mEmulationState.pause();
super.onPause();
}
@Override
public void onDetach()
{
NativeLibrary.clearEmulationActivity();
super.onDetach();
}
@Override
public void onDetach()
{
NativeLibrary.clearEmulationActivity();
super.onDetach();
}
private void setupDolphinDirectoriesThenStartEmulation() {
IntentFilter statusIntentFilter = new IntentFilter(
DirectoryInitializationService.BROADCAST_ACTION);
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();
}
});
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());
}
// Registers the DirectoryStateReceiver and its intent filters
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
directoryStateReceiver,
statusIntentFilter);
DirectoryInitializationService.startService(getActivity());
}
public void toggleInputOverlayVisibility()
{
SharedPreferences.Editor editor = mPreferences.edit();
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);
}
// 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();
}
editor.apply();
}
public void refreshInputOverlay()
{
mInputOverlay.refreshControls();
}
public void refreshInputOverlay()
{
mInputOverlay.refreshControls();
}
@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 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 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();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder)
{
mEmulationState.clearSurface();
}
public void stopEmulation()
{
mEmulationState.stop();
}
public void stopEmulation()
{
mEmulationState.stop();
}
public void startConfiguringControls()
{
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
mInputOverlay.setIsInEditMode(true);
}
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 void stopConfiguringControls()
{
getView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
mInputOverlay.setIsInEditMode(false);
}
public boolean isConfiguringControls()
{
return mInputOverlay.isInEditMode();
}
public boolean isConfiguringControls()
{
return mInputOverlay.isInEditMode();
}
private static class EmulationState
{
private enum State
{
STOPPED, RUNNING, PAUSED
}
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;
private boolean loadPreviousTemporaryState;
private boolean firstOpen;
private final String temporaryStatePath;
private final String mGamePath;
private Thread mEmulationThread;
private State state;
private Surface mSurface;
private boolean mRunWhenSurfaceIsValid;
private boolean loadPreviousTemporaryState;
private boolean firstOpen;
private final String temporaryStatePath;
EmulationState(String gamePath, String temporaryStatePath, boolean firstOpen)
{
this.firstOpen = firstOpen;
mGamePath = gamePath;
this.temporaryStatePath = temporaryStatePath;
// Starting state is stopped.
state = State.STOPPED;
}
EmulationState(String gamePath, String temporaryStatePath, boolean firstOpen)
{
this.firstOpen = firstOpen;
mGamePath = gamePath;
this.temporaryStatePath = temporaryStatePath;
// Starting state is stopped.
state = State.STOPPED;
}
// Getters for the current state
// Getters for the current state
public synchronized boolean isStopped()
{
return state == State.STOPPED;
}
public synchronized boolean isStopped()
{
return state == State.STOPPED;
}
public synchronized boolean isPaused()
{
return state == State.PAUSED;
}
public synchronized boolean isPaused()
{
return state == State.PAUSED;
}
public synchronized boolean isRunning()
{
return state == State.RUNNING;
}
public synchronized boolean isRunning()
{
return state == State.RUNNING;
}
// State changing methods
// 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 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.");
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.");
}
}
// 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())
{
loadPreviousTemporaryState = false;
state = State.PAUSED;
deleteFile(temporaryStatePath);
}
else
{
loadPreviousTemporaryState = true;
}
}
else
{
Log.debug("[EmulationFragment] activity resumed or fresh start");
loadPreviousTemporaryState = false;
// activity resumed without being killed or this is the first run
deleteFile(temporaryStatePath);
}
public synchronized void run(boolean isActivityRecreated)
{
if (isActivityRecreated)
{
if (NativeLibrary.IsRunning())
{
loadPreviousTemporaryState = false;
state = State.PAUSED;
deleteFile(temporaryStatePath);
}
else
{
loadPreviousTemporaryState = true;
}
}
else
{
Log.debug("[EmulationFragment] activity resumed or fresh start");
loadPreviousTemporaryState = false;
// activity resumed without being killed or this is the first run
deleteFile(temporaryStatePath);
}
// If the surface is set, run now. Otherwise, wait for it to get set.
if (mSurface != null)
{
runWithValidSurface();
}
else
{
mRunWhenSurfaceIsValid = true;
}
}
// 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();
}
}
// 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.");
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.");
}
}
}
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);
if (loadPreviousTemporaryState)
{
Log.debug("[EmulationFragment] Starting emulation thread from previous state.");
NativeLibrary.Run(mGamePath, temporaryStatePath, true);
}
else
{
Log.debug("[EmulationFragment] Starting emulation thread.");
NativeLibrary.Run(mGamePath, firstOpen);
}
}, "NativeEmulation");
mEmulationThread.start();
private void runWithValidSurface()
{
mRunWhenSurfaceIsValid = false;
if (state == State.STOPPED)
{
mEmulationThread = new Thread(() ->
{
NativeLibrary.SurfaceChanged(mSurface);
if (loadPreviousTemporaryState)
{
Log.debug("[EmulationFragment] Starting emulation thread from previous state.");
NativeLibrary.Run(mGamePath, temporaryStatePath, true);
}
else
{
Log.debug("[EmulationFragment] Starting emulation thread.");
NativeLibrary.Run(mGamePath, firstOpen);
}
}, "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;
}
}
}
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;
}
}
public void saveTemporaryState()
{
NativeLibrary.SaveStateAs(getTemporaryStateFilePath(), true);
}
public void saveTemporaryState()
{
NativeLibrary.SaveStateAs(getTemporaryStateFilePath(), true);
}
private String getTemporaryStateFilePath()
{
return getContext().getFilesDir() + File.separator + "temp.sav";
}
private String getTemporaryStateFilePath()
{
return getContext().getFilesDir() + File.separator + "temp.sav";
}
private static void deleteFile(String path)
{
try
{
File file = new File(path);
file.delete();
}
catch (Exception ex)
{
// fail safely
}
}
private static void deleteFile(String path)
{
try
{
File file = new File(path);
file.delete();
}
catch (Exception ex)
{
// fail safely
}
}
}

View File

@ -16,62 +16,68 @@ import org.dolphinemu.dolphinemu.activities.EmulationActivity;
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_take_screenshot, EmulationActivity.MENU_ACTION_TAKE_SCREENSHOT);
buttonsActionsMap.append(R.id.menu_quicksave, EmulationActivity.MENU_ACTION_QUICK_SAVE);
buttonsActionsMap.append(R.id.menu_quickload, EmulationActivity.MENU_ACTION_QUICK_LOAD);
buttonsActionsMap.append(R.id.menu_emulation_save_root, EmulationActivity.MENU_ACTION_SAVE_ROOT);
buttonsActionsMap.append(R.id.menu_emulation_load_root, EmulationActivity.MENU_ACTION_LOAD_ROOT);
buttonsActionsMap.append(R.id.menu_refresh_wiimotes, EmulationActivity.MENU_ACTION_REFRESH_WIIMOTES);
buttonsActionsMap.append(R.id.menu_change_disc, EmulationActivity.MENU_ACTION_CHANGE_DISC);
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
}
private static final String KEY_TITLE = "title";
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
public static MenuFragment newInstance(String title)
{
MenuFragment fragment = new MenuFragment();
static
{
buttonsActionsMap
.append(R.id.menu_take_screenshot, EmulationActivity.MENU_ACTION_TAKE_SCREENSHOT);
buttonsActionsMap.append(R.id.menu_quicksave, EmulationActivity.MENU_ACTION_QUICK_SAVE);
buttonsActionsMap.append(R.id.menu_quickload, EmulationActivity.MENU_ACTION_QUICK_LOAD);
buttonsActionsMap
.append(R.id.menu_emulation_save_root, EmulationActivity.MENU_ACTION_SAVE_ROOT);
buttonsActionsMap
.append(R.id.menu_emulation_load_root, EmulationActivity.MENU_ACTION_LOAD_ROOT);
buttonsActionsMap
.append(R.id.menu_refresh_wiimotes, EmulationActivity.MENU_ACTION_REFRESH_WIIMOTES);
buttonsActionsMap.append(R.id.menu_change_disc, EmulationActivity.MENU_ACTION_CHANGE_DISC);
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
}
Bundle arguments = new Bundle();
arguments.putSerializable(KEY_TITLE, title);
fragment.setArguments(arguments);
public static MenuFragment newInstance(String title)
{
MenuFragment fragment = new MenuFragment();
return fragment;
}
Bundle arguments = new Bundle();
arguments.putSerializable(KEY_TITLE, title);
fragment.setArguments(arguments);
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false);
return fragment;
}
LinearLayout options = (LinearLayout) rootView.findViewById(R.id.layout_options);
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++)
{
Button button = (Button) options.getChildAt(childIndex);
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false);
button.setOnClickListener(this);
}
LinearLayout options = (LinearLayout) rootView.findViewById(R.id.layout_options);
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++)
{
Button button = (Button) options.getChildAt(childIndex);
TextView titleText = rootView.findViewById(R.id.text_game_title);
String title = getArguments().getString(KEY_TITLE);
if (title != null)
{
titleText.setText(title);
}
button.setOnClickListener(this);
}
return rootView;
}
TextView titleText = rootView.findViewById(R.id.text_game_title);
String title = getArguments().getString(KEY_TITLE);
if (title != null)
{
titleText.setText(title);
}
@SuppressWarnings("WrongConstant")
@Override
public void onClick(View button)
{
int action = buttonsActionsMap.get(button.getId());
if (action >= 0)
{
((EmulationActivity) getActivity()).handleMenuAction(action);
}
}
return rootView;
}
@SuppressWarnings("WrongConstant")
@Override
public void onClick(View button)
{
int action = buttonsActionsMap.get(button.getId());
if (action >= 0)
{
((EmulationActivity) getActivity()).handleMenuAction(action);
}
}
}

View File

@ -15,86 +15,104 @@ import org.dolphinemu.dolphinemu.activities.EmulationActivity;
public final class SaveLoadStateFragment extends Fragment implements View.OnClickListener
{
public enum SaveOrLoad
{
SAVE, LOAD
}
public enum SaveOrLoad
{
SAVE, LOAD
}
private static final String KEY_SAVEORLOAD = "saveorload";
private static SparseIntArray saveButtonsActionsMap = new SparseIntArray();
static {
saveButtonsActionsMap.append(R.id.loadsave_state_button_1, EmulationActivity.MENU_ACTION_SAVE_SLOT1);
saveButtonsActionsMap.append(R.id.loadsave_state_button_2, EmulationActivity.MENU_ACTION_SAVE_SLOT2);
saveButtonsActionsMap.append(R.id.loadsave_state_button_3, EmulationActivity.MENU_ACTION_SAVE_SLOT3);
saveButtonsActionsMap.append(R.id.loadsave_state_button_4, EmulationActivity.MENU_ACTION_SAVE_SLOT4);
saveButtonsActionsMap.append(R.id.loadsave_state_button_5, EmulationActivity.MENU_ACTION_SAVE_SLOT5);
saveButtonsActionsMap.append(R.id.loadsave_state_button_6, EmulationActivity.MENU_ACTION_SAVE_SLOT6);
}
private static SparseIntArray loadButtonsActionsMap = new SparseIntArray();
static {
loadButtonsActionsMap.append(R.id.loadsave_state_button_1, EmulationActivity.MENU_ACTION_LOAD_SLOT1);
loadButtonsActionsMap.append(R.id.loadsave_state_button_2, EmulationActivity.MENU_ACTION_LOAD_SLOT2);
loadButtonsActionsMap.append(R.id.loadsave_state_button_3, EmulationActivity.MENU_ACTION_LOAD_SLOT3);
loadButtonsActionsMap.append(R.id.loadsave_state_button_4, EmulationActivity.MENU_ACTION_LOAD_SLOT4);
loadButtonsActionsMap.append(R.id.loadsave_state_button_5, EmulationActivity.MENU_ACTION_LOAD_SLOT5);
loadButtonsActionsMap.append(R.id.loadsave_state_button_6, EmulationActivity.MENU_ACTION_LOAD_SLOT6);
}
private SaveOrLoad mSaveOrLoad;
private static final String KEY_SAVEORLOAD = "saveorload";
private static SparseIntArray saveButtonsActionsMap = new SparseIntArray();
public static SaveLoadStateFragment newInstance(SaveOrLoad saveOrLoad)
{
SaveLoadStateFragment fragment = new SaveLoadStateFragment();
static
{
saveButtonsActionsMap
.append(R.id.loadsave_state_button_1, EmulationActivity.MENU_ACTION_SAVE_SLOT1);
saveButtonsActionsMap
.append(R.id.loadsave_state_button_2, EmulationActivity.MENU_ACTION_SAVE_SLOT2);
saveButtonsActionsMap
.append(R.id.loadsave_state_button_3, EmulationActivity.MENU_ACTION_SAVE_SLOT3);
saveButtonsActionsMap
.append(R.id.loadsave_state_button_4, EmulationActivity.MENU_ACTION_SAVE_SLOT4);
saveButtonsActionsMap
.append(R.id.loadsave_state_button_5, EmulationActivity.MENU_ACTION_SAVE_SLOT5);
saveButtonsActionsMap
.append(R.id.loadsave_state_button_6, EmulationActivity.MENU_ACTION_SAVE_SLOT6);
}
Bundle arguments = new Bundle();
arguments.putSerializable(KEY_SAVEORLOAD, saveOrLoad);
fragment.setArguments(arguments);
private static SparseIntArray loadButtonsActionsMap = new SparseIntArray();
return fragment;
}
static
{
loadButtonsActionsMap
.append(R.id.loadsave_state_button_1, EmulationActivity.MENU_ACTION_LOAD_SLOT1);
loadButtonsActionsMap
.append(R.id.loadsave_state_button_2, EmulationActivity.MENU_ACTION_LOAD_SLOT2);
loadButtonsActionsMap
.append(R.id.loadsave_state_button_3, EmulationActivity.MENU_ACTION_LOAD_SLOT3);
loadButtonsActionsMap
.append(R.id.loadsave_state_button_4, EmulationActivity.MENU_ACTION_LOAD_SLOT4);
loadButtonsActionsMap
.append(R.id.loadsave_state_button_5, EmulationActivity.MENU_ACTION_LOAD_SLOT5);
loadButtonsActionsMap
.append(R.id.loadsave_state_button_6, EmulationActivity.MENU_ACTION_LOAD_SLOT6);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
private SaveOrLoad mSaveOrLoad;
mSaveOrLoad = (SaveOrLoad) getArguments().getSerializable(KEY_SAVEORLOAD);
}
public static SaveLoadStateFragment newInstance(SaveOrLoad saveOrLoad)
{
SaveLoadStateFragment fragment = new SaveLoadStateFragment();
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_saveload_state, container, false);
Bundle arguments = new Bundle();
arguments.putSerializable(KEY_SAVEORLOAD, saveOrLoad);
fragment.setArguments(arguments);
GridLayout grid = (GridLayout) rootView.findViewById(R.id.grid_state_slots);
for (int childIndex = 0; childIndex < grid.getChildCount(); childIndex++)
{
Button button = (Button) grid.getChildAt(childIndex);
button.setOnClickListener(this);
}
return fragment;
}
// So that item clicked to start this Fragment is no longer the focused item.
grid.requestFocus();
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
return rootView;
}
mSaveOrLoad = (SaveOrLoad) getArguments().getSerializable(KEY_SAVEORLOAD);
}
@SuppressWarnings("WrongConstant")
@Override
public void onClick(View button)
{
int action = 0;
switch(mSaveOrLoad)
{
case SAVE:
action = saveButtonsActionsMap.get(button.getId(), -1);
break;
case LOAD:
action = loadButtonsActionsMap.get(button.getId(), -1);
}
if (action >= 0)
{
((EmulationActivity) getActivity()).handleMenuAction(action);
}
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_saveload_state, container, false);
GridLayout grid = (GridLayout) rootView.findViewById(R.id.grid_state_slots);
for (int childIndex = 0; childIndex < grid.getChildCount(); childIndex++)
{
Button button = (Button) grid.getChildAt(childIndex);
button.setOnClickListener(this);
}
// So that item clicked to start this Fragment is no longer the focused item.
grid.requestFocus();
return rootView;
}
@SuppressWarnings("WrongConstant")
@Override
public void onClick(View button)
{
int action = 0;
switch (mSaveOrLoad)
{
case SAVE:
action = saveButtonsActionsMap.get(button.getId(), -1);
break;
case LOAD:
action = loadButtonsActionsMap.get(button.getId(), -1);
}
if (action >= 0)
{
((EmulationActivity) getActivity()).handleMenuAction(action);
}
}
}

View File

@ -1,50 +1,56 @@
package org.dolphinemu.dolphinemu.model;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import org.dolphinemu.dolphinemu.utils.CoverHelper;
public class GameFile
{
private long mPointer; // Do not rename or move without editing the native code
private long mPointer; // Do not rename or move without editing the native code
private GameFile(long pointer)
{
mPointer = pointer;
}
private GameFile(long pointer)
{
mPointer = pointer;
}
@Override
public native void finalize();
@Override
public native void finalize();
public native int getPlatform();
public native String getTitle();
public native String getDescription();
public native String getCompany();
public native int getCountry();
public native int getRegion();
public native String getPath();
public native String getGameId();
public native int[] getBanner();
public native int getBannerWidth();
public native int getBannerHeight();
public native int getPlatform();
public String getCoverPath()
{
return Environment.getExternalStorageDirectory().getPath() +
"/dolphin-emu/Cache/GameCovers/" + getGameId() + ".png";
}
public native String getTitle();
public String getCustomCoverPath()
{
return getPath().substring(0, getPath().lastIndexOf(".")) + ".cover.png";
}
public native String getDescription();
public String getScreenshotPath()
{
String gameId = getGameId();
return "file://" + Environment.getExternalStorageDirectory().getPath() +
"/dolphin-emu/ScreenShots/" + gameId + "/" + gameId + "-1.png";
}
public native String getCompany();
public native int getCountry();
public native int getRegion();
public native String getPath();
public native String getGameId();
public native int[] getBanner();
public native int getBannerWidth();
public native int getBannerHeight();
public String getCoverPath()
{
return Environment.getExternalStorageDirectory().getPath() +
"/dolphin-emu/Cache/GameCovers/" + getGameId() + ".png";
}
public String getCustomCoverPath()
{
return getPath().substring(0, getPath().lastIndexOf(".")) + ".cover.png";
}
public String getScreenshotPath()
{
String gameId = getGameId();
return "file://" + Environment.getExternalStorageDirectory().getPath() +
"/dolphin-emu/ScreenShots/" + gameId + "/" + gameId + "-1.png";
}
}

View File

@ -10,80 +10,86 @@ import java.util.Set;
public class GameFileCache
{
private static final String GAME_FOLDER_PATHS_PREFERENCE = "gameFolderPaths";
private static final Set<String> EMPTY_SET = new HashSet<>();
private static final String GAME_FOLDER_PATHS_PREFERENCE = "gameFolderPaths";
private static final Set<String> EMPTY_SET = new HashSet<>();
private long mPointer; // Do not rename or move without editing the native code
private long mPointer; // Do not rename or move without editing the native code
public GameFileCache(String path)
{
mPointer = newGameFileCache(path);
}
public GameFileCache(String path)
{
mPointer = newGameFileCache(path);
}
private static native long newGameFileCache(String path);
private static native long newGameFileCache(String path);
@Override
public native void finalize();
@Override
public native void finalize();
public static void addGameFolder(String path, Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> folderPaths = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
Set<String> newFolderPaths = new HashSet<>(folderPaths);
newFolderPaths.add(path);
SharedPreferences.Editor editor = preferences.edit();
editor.putStringSet(GAME_FOLDER_PATHS_PREFERENCE, newFolderPaths);
editor.apply();
}
public static void addGameFolder(String path, Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> folderPaths = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
Set<String> newFolderPaths = new HashSet<>(folderPaths);
newFolderPaths.add(path);
SharedPreferences.Editor editor = preferences.edit();
editor.putStringSet(GAME_FOLDER_PATHS_PREFERENCE, newFolderPaths);
editor.apply();
}
private void removeNonExistentGameFolders(Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> folderPaths = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
Set<String> newFolderPaths = new HashSet<>();
for (String folderPath : folderPaths)
{
File folder = new File(folderPath);
if (folder.exists())
{
newFolderPaths.add(folderPath);
}
}
private void removeNonExistentGameFolders(Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> folderPaths = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
Set<String> newFolderPaths = new HashSet<>();
for (String folderPath : folderPaths)
{
File folder = new File(folderPath);
if (folder.exists())
{
newFolderPaths.add(folderPath);
}
}
if (folderPaths.size() != newFolderPaths.size())
{
// One or more folders are being deleted
SharedPreferences.Editor editor = preferences.edit();
editor.putStringSet(GAME_FOLDER_PATHS_PREFERENCE, newFolderPaths);
editor.apply();
}
}
if (folderPaths.size() != newFolderPaths.size())
{
// One or more folders are being deleted
SharedPreferences.Editor editor = preferences.edit();
editor.putStringSet(GAME_FOLDER_PATHS_PREFERENCE, newFolderPaths);
editor.apply();
}
}
/**
* Scans through the file system and updates the cache to match.
* @return true if the cache was modified
*/
public boolean scanLibrary(Context context)
{
removeNonExistentGameFolders(context);
/**
* Scans through the file system and updates the cache to match.
*
* @return true if the cache was modified
*/
public boolean scanLibrary(Context context)
{
removeNonExistentGameFolders(context);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> folderPathsSet = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
String[] folderPaths = folderPathsSet.toArray(new String[folderPathsSet.size()]);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Set<String> folderPathsSet = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
String[] folderPaths = folderPathsSet.toArray(new String[folderPathsSet.size()]);
boolean cacheChanged = update(folderPaths);
cacheChanged |= updateAdditionalMetadata();
if (cacheChanged)
{
save();
}
return cacheChanged;
}
boolean cacheChanged = update(folderPaths);
cacheChanged |= updateAdditionalMetadata();
if (cacheChanged)
{
save();
}
return cacheChanged;
}
public native GameFile[] getAllGames();
public native GameFile addOrGet(String gamePath);
private native boolean update(String[] folderPaths);
private native boolean updateAdditionalMetadata();
public native boolean load();
private native boolean save();
public native GameFile[] getAllGames();
public native GameFile addOrGet(String gamePath);
private native boolean update(String[] folderPaths);
private native boolean updateAdditionalMetadata();
public native boolean load();
private native boolean save();
}

View File

@ -6,59 +6,59 @@ package org.dolphinemu.dolphinemu.model;
public class HomeScreenChannel
{
private long channelId;
private String name;
private String description;
private String appLinkIntentUri;
private long channelId;
private String name;
private String description;
private String appLinkIntentUri;
public HomeScreenChannel()
{
}
public HomeScreenChannel()
{
}
public HomeScreenChannel(String name, String description, String appLinkIntentUri)
{
this.name = name;
this.description = description;
this.appLinkIntentUri = appLinkIntentUri;
}
public HomeScreenChannel(String name, String description, String appLinkIntentUri)
{
this.name = name;
this.description = description;
this.appLinkIntentUri = appLinkIntentUri;
}
public long getChannelId()
{
return channelId;
}
public long getChannelId()
{
return channelId;
}
public void setChannelId(long channelId)
{
this.channelId = channelId;
}
public void setChannelId(long channelId)
{
this.channelId = channelId;
}
public String getName()
{
return name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public void setName(String name)
{
this.name = name;
}
public String getDescription()
{
return description;
}
public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public void setDescription(String description)
{
this.description = description;
}
public String getAppLinkIntentUri()
{
return appLinkIntentUri;
}
public String getAppLinkIntentUri()
{
return appLinkIntentUri;
}
public void setAppLinkIntentUri(String appLinkIntentUri)
{
this.appLinkIntentUri = appLinkIntentUri;
}
public void setAppLinkIntentUri(String appLinkIntentUri)
{
this.appLinkIntentUri = appLinkIntentUri;
}
}

View File

@ -2,29 +2,29 @@ package org.dolphinemu.dolphinemu.model;
public final class TvSettingsItem
{
private final int mItemId;
private final int mIconId;
private final int mLabelId;
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;
}
}

View File

@ -19,117 +19,119 @@ import android.view.MotionEvent;
*/
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;
// 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;
/**
* 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();
}
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
}
/**
* Gets this InputOverlayDrawableButton's button ID.
*
* @return this InputOverlayDrawableButton's button ID.
*/
public int getId()
{
return mButtonType;
}
/**
* 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 void setTrackId(int trackId)
{
mTrackId = trackId;
}
public int getTrackId()
{
return mTrackId;
}
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 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;
}
return true;
}
}
return true;
}
public void setPosition(int x, int y)
{
mControlPositionX = x;
mControlPositionY = y;
}
public void setPosition(int x, int y)
{
mControlPositionX = x;
mControlPositionY = y;
}
public void draw(Canvas canvas)
{
getCurrentStateBitmapDrawable().draw(canvas);
}
public void draw(Canvas canvas)
{
getCurrentStateBitmapDrawable().draw(canvas);
}
private BitmapDrawable getCurrentStateBitmapDrawable()
{
return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap;
}
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 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 Rect getBounds()
{
return mDefaultStateBitmap.getBounds();
}
public int getWidth()
{
return mWidth;
}
public int getWidth()
{
return mWidth;
}
public int getHeight()
{
return mHeight;
}
public int getHeight()
{
return mHeight;
}
public void setPressedState(boolean isPressed)
{
mPressedState = isPressed;
}
public void setPressedState(boolean isPressed)
{
mPressedState = isPressed;
}
}

View File

@ -19,183 +19,188 @@ import android.view.MotionEvent;
*/
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;
// 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;
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;
}
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;
}
}
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;
}
}
/**
* Gets one of the InputOverlayDrawableDpad's button IDs.
*
* @return the requested InputOverlayDrawableDpad's button ID.
*/
public int getId(int direction)
{
return mButtonType[direction];
}
/**
* 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 void setTrackId(int trackId)
{
mTrackId = trackId;
}
public int getTrackId()
{
return mTrackId;
}
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 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;
}
return true;
}
}
return true;
}
public void setPosition(int x, int y)
{
mControlPositionX = x;
mControlPositionY = y;
}
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 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 Rect getBounds()
{
return mDefaultStateBitmap.getBounds();
}
public int getWidth() {
return mWidth;
}
public int getWidth()
{
return mWidth;
}
public int getHeight() {
return mHeight;
}
public int getHeight()
{
return mHeight;
}
public void setState(int pressState) {
mPressState = pressState;
}
public void setState(int pressState)
{
mPressState = pressState;
}
}

View File

@ -6,7 +6,6 @@
package org.dolphinemu.dolphinemu.overlay;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
@ -21,246 +20,258 @@ import android.view.MotionEvent;
*/
public final class InputOverlayDrawableJoystick
{
private SharedPreferences mPreferences;
private SharedPreferences mPreferences;
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;
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, SharedPreferences prefsHandle)
{
axisIDs[0] = joystick + 1;
axisIDs[1] = joystick + 2;
axisIDs[2] = joystick + 3;
axisIDs[3] = joystick + 4;
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, SharedPreferences prefsHandle)
{
axisIDs[0] = joystick + 1;
axisIDs[1] = joystick + 2;
axisIDs[2] = joystick + 3;
axisIDs[3] = joystick + 4;
mJoystickType = joystick;
mPreferences = prefsHandle;
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();
mPreferences = prefsHandle;
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();
}
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;
}
/**
* 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 draw(Canvas canvas)
{
mOuterBitmap.draw(canvas);
getCurrentStateBitmapDrawable().draw(canvas);
mBoundsBoxBitmap.draw(canvas);
}
public void TrackEvent(MotionEvent event)
{
boolean reCenter = mPreferences.getBoolean("joystickRelCenter", true);
int pointerIndex = event.getActionIndex();
public void TrackEvent(MotionEvent event)
{
boolean reCenter = mPreferences.getBoolean("joystickRelCenter", true);
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);
if (reCenter)
{
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;
}
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);
if (reCenter)
{
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;
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] = AxisY;
axises[1] = AxisX;
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] = AxisY;
axises[1] = AxisX;
SetInnerBounds();
}
}
}
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;
}
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;
}
public float[] getAxisValues()
{
float[] joyaxises = {0f, 0f, 0f, 0f};
joyaxises[1] = Math.min(axises[0], 1.0f);
joyaxises[0] = Math.min(axises[0], 0.0f);
joyaxises[3] = Math.min(axises[1], 1.0f);
joyaxises[2] = Math.min(axises[1], 0.0f);
return joyaxises;
}
public float[] getAxisValues()
{
float[] joyaxises = {0f, 0f, 0f, 0f};
joyaxises[1] = Math.min(axises[0], 1.0f);
joyaxises[0] = Math.min(axises[0], 0.0f);
joyaxises[3] = Math.min(axises[1], 1.0f);
joyaxises[2] = Math.min(axises[1], 0.0f);
return joyaxises;
}
public int[] getAxisIDs()
{
return axisIDs;
}
public int[] getAxisIDs()
{
return axisIDs;
}
private void SetInnerBounds()
{
int X = getVirtBounds().centerX() + (int)((axises[1]) * (getVirtBounds().width() / 2));
int Y = getVirtBounds().centerY() + (int)((axises[0]) * (getVirtBounds().height() / 2));
private void SetInnerBounds()
{
int X = getVirtBounds().centerX() + (int) ((axises[1]) * (getVirtBounds().width() / 2));
int Y = getVirtBounds().centerY() + (int) ((axises[0]) * (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 void setBounds(Rect bounds)
{
mOuterBitmap.setBounds(bounds);
}
public Rect getBounds()
{
return mOuterBitmap.getBounds();
}
public Rect getBounds()
{
return mOuterBitmap.getBounds();
}
private void setVirtBounds(Rect bounds) { mVirtBounds = 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;
}
public int getWidth()
{
return mWidth;
}
public int getWidth()
{
return mWidth;
}
public int getHeight()
{
return mHeight;
}
public int getHeight()
{
return mHeight;
}
}

View File

@ -32,231 +32,239 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
public final class DirectoryInitializationService extends IntentService
{
public static final String BROADCAST_ACTION = "org.dolphinemu.dolphinemu.DIRECTORY_INITIALIZATION";
public static final String BROADCAST_ACTION =
"org.dolphinemu.dolphinemu.DIRECTORY_INITIALIZATION";
public static final String EXTRA_STATE = "directoryState";
private static volatile DirectoryInitializationState directoryState = null;
private static String userPath;
private static String internalPath;
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 String internalPath;
private static AtomicBoolean isDolphinDirectoryInitializationRunning = new AtomicBoolean(false);
public enum DirectoryInitializationState
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 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)
{
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 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())
{
if (PermissionsHandler.hasWriteAccess(this))
{
if (setDolphinUserDirectory())
{
initializeInternalStorage();
initializeExternalStorage();
initializeInternalStorage();
initializeExternalStorage();
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
}
else
{
directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE;
}
}
else
{
directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED;
}
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
}
isDolphinDirectoryInitializationRunning.set(false);
sendBroadcastState(directoryState);
else
{
directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE;
}
}
else
{
directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED;
}
}
private boolean setDolphinUserDirectory()
isDolphinDirectoryInitializationRunning.set(false);
sendBroadcastState(directoryState);
}
private boolean setDolphinUserDirectory()
{
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
{
File externalPath = Environment.getExternalStorageDirectory();
if (externalPath != null)
{
userPath = externalPath.getAbsolutePath() + "/dolphin-emu";
Log.debug("[DirectoryInitializationService] User Dir: " + userPath);
NativeLibrary.SetUserDirectory(userPath);
return true;
}
File externalPath = Environment.getExternalStorageDirectory();
if (externalPath != null)
{
userPath = externalPath.getAbsolutePath() + "/dolphin-emu";
Log.debug("[DirectoryInitializationService] User Dir: " + userPath);
NativeLibrary.SetUserDirectory(userPath);
return true;
}
}
return false;
}
private void initializeInternalStorage()
return false;
}
private void initializeInternalStorage()
{
File sysDirectory = new File(getFilesDir(), "Sys");
internalPath = sysDirectory.getAbsolutePath();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
String revision = NativeLibrary.GetGitRevision();
if (!preferences.getString("sysDirectoryVersion", "").equals(revision))
{
File sysDirectory = new File(getFilesDir(), "Sys");
internalPath = sysDirectory.getAbsolutePath();
// 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 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());
SharedPreferences.Editor editor = preferences.edit();
editor.putString("sysDirectoryVersion", revision);
editor.apply();
}
private void initializeExternalStorage()
// Let the native code know where the Sys directory is.
SetSysDirectory(sysDirectory.getPath());
}
private void initializeExternalStorage()
{
// Create User directory structure and copy some NAND files from the extracted Sys directory.
CreateUserDirectories();
// GCPadNew.ini and WiimoteNew.ini must contain specific values in order for controller
// input to work as intended (they aren't user configurable), so we overwrite them just
// in case the user has tried to modify them manually.
//
// ...Except WiimoteNew.ini contains the user configurable settings for Wii Remote
// extensions in addition to all of its lines that aren't user configurable, so since we
// don't want to lose the selected extensions, we don't overwrite that file if it exists.
//
// TODO: Redo the Android controller system so that we don't have to extract these INIs.
String configDirectory = NativeLibrary.GetUserDirectory() + File.separator + "Config";
copyAsset("GCPadNew.ini", new File(configDirectory, "GCPadNew.ini"), true);
copyAsset("WiimoteNew.ini", new File(configDirectory, "WiimoteNew.ini"), false);
}
private static void deleteDirectoryRecursively(File file)
{
if (file.isDirectory())
{
// Create User directory structure and copy some NAND files from the extracted Sys directory.
CreateUserDirectories();
// GCPadNew.ini and WiimoteNew.ini must contain specific values in order for controller
// input to work as intended (they aren't user configurable), so we overwrite them just
// in case the user has tried to modify them manually.
//
// ...Except WiimoteNew.ini contains the user configurable settings for Wii Remote
// extensions in addition to all of its lines that aren't user configurable, so since we
// don't want to lose the selected extensions, we don't overwrite that file if it exists.
//
// TODO: Redo the Android controller system so that we don't have to extract these INIs.
String configDirectory = NativeLibrary.GetUserDirectory() + File.separator + "Config";
copyAsset("GCPadNew.ini", new File(configDirectory, "GCPadNew.ini"), true);
copyAsset("WiimoteNew.ini", new File(configDirectory,"WiimoteNew.ini"), false);
for (File child : file.listFiles())
deleteDirectoryRecursively(child);
}
file.delete();
}
private static void deleteDirectoryRecursively(File file)
public static boolean areDolphinDirectoriesReady()
{
return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
}
public static String getUserDirectory()
{
if (directoryState == null)
{
if (file.isDirectory())
{
for (File child : file.listFiles())
deleteDirectoryRecursively(child);
}
file.delete();
throw new IllegalStateException("DirectoryInitializationService has to run at least once!");
}
public static boolean areDolphinDirectoriesReady()
else if (isDolphinDirectoryInitializationRunning.get())
{
return directoryState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
throw new IllegalStateException(
"DirectoryInitializationService has to finish running first!");
}
return userPath;
public static String getUserDirectory()
}
public static String getDolphinInternalDirectory()
{
if (directoryState == null)
{
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;
throw new IllegalStateException("DirectoryInitializationService has to run at least once!");
}
public static String getDolphinInternalDirectory()
else if (isDolphinDirectoryInitializationRunning.get())
{
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 internalPath;
throw new IllegalStateException(
"DirectoryInitializationService has to finish running first!");
}
return internalPath;
private void sendBroadcastState(DirectoryInitializationState state)
}
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
{
Intent localIntent =
new Intent(BROADCAST_ACTION)
.putExtra(EXTRA_STATE, state);
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
if (!output.exists() || overwrite)
{
InputStream in = getAssets().open(asset);
OutputStream out = new FileOutputStream(output);
copyFile(in, out);
in.close();
out.close();
}
}
private void copyAsset(String asset, File output, Boolean overwrite)
catch (IOException e)
{
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());
}
Log.error("[DirectoryInitializationService] Failed to copy asset file: " + asset +
e.getMessage());
}
}
private void copyAssetFolder(String assetFolder, File outputFolder, Boolean overwrite)
private void copyAssetFolder(String assetFolder, File outputFolder, Boolean overwrite)
{
Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " +
outputFolder);
try
{
Log.verbose("[DirectoryInitializationService] Copying Folder " + assetFolder + " to " + outputFolder);
try
boolean createdFolder = false;
for (String file : getAssets().list(assetFolder))
{
if (!createdFolder)
{
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());
outputFolder.mkdir();
createdFolder = true;
}
copyAssetFolder(assetFolder + File.separator + file, new File(outputFolder, file),
overwrite);
copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), overwrite);
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException
catch (IOException e)
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
Log.error("[DirectoryInitializationService] Failed to copy asset folder: " + assetFolder +
e.getMessage());
}
}
private static native void CreateUserDirectories();
private static native void SetSysDirectory(String path);
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);
}
}
private static native void CreateUserDirectories();
private static native void SetSysDirectory(String path);
}

View File

@ -20,117 +20,117 @@ import java.util.concurrent.atomic.AtomicReference;
*/
public final class GameFileCacheService extends IntentService
{
public static final String BROADCAST_ACTION = "org.dolphinemu.dolphinemu.GAME_FILE_CACHE_UPDATED";
public static final String BROADCAST_ACTION = "org.dolphinemu.dolphinemu.GAME_FILE_CACHE_UPDATED";
private static final String ACTION_LOAD = "org.dolphinemu.dolphinemu.LOAD_GAME_FILE_CACHE";
private static final String ACTION_RESCAN = "org.dolphinemu.dolphinemu.RESCAN_GAME_FILE_CACHE";
private static final String ACTION_LOAD = "org.dolphinemu.dolphinemu.LOAD_GAME_FILE_CACHE";
private static final String ACTION_RESCAN = "org.dolphinemu.dolphinemu.RESCAN_GAME_FILE_CACHE";
private static GameFileCache gameFileCache = null;
private static AtomicReference<GameFile[]> gameFiles = new AtomicReference<>(new GameFile[]{});
private static GameFileCache gameFileCache = null;
private static AtomicReference<GameFile[]> gameFiles = new AtomicReference<>(new GameFile[]{});
public GameFileCacheService()
{
// Superclass constructor is called to name the thread on which this service executes.
super("GameFileCacheService");
}
public GameFileCacheService()
{
// Superclass constructor is called to name the thread on which this service executes.
super("GameFileCacheService");
}
public static List<GameFile> getGameFilesForPlatform(Platform platform)
{
GameFile[] allGames = gameFiles.get();
ArrayList<GameFile> platformGames = new ArrayList<>();
for (GameFile game : allGames)
{
if (Platform.fromNativeInt(game.getPlatform()) == platform)
{
platformGames.add(game);
}
}
return platformGames;
}
public static List<GameFile> getGameFilesForPlatform(Platform platform)
{
GameFile[] allGames = gameFiles.get();
ArrayList<GameFile> platformGames = new ArrayList<>();
for (GameFile game : allGames)
{
if (Platform.fromNativeInt(game.getPlatform()) == platform)
{
platformGames.add(game);
}
}
return platformGames;
}
public static GameFile getGameFileByGameId(String gameId)
{
GameFile[] allGames = gameFiles.get();
for (GameFile game : allGames)
{
if (game.getGameId().equals(gameId))
{
return game;
}
}
return null;
}
public static GameFile getGameFileByGameId(String gameId)
{
GameFile[] allGames = gameFiles.get();
for (GameFile game : allGames)
{
if (game.getGameId().equals(gameId))
{
return game;
}
}
return null;
}
private static void startService(Context context, String action)
{
Intent intent = new Intent(context, GameFileCacheService.class);
intent.setAction(action);
context.startService(intent);
}
private static void startService(Context context, String action)
{
Intent intent = new Intent(context, GameFileCacheService.class);
intent.setAction(action);
context.startService(intent);
}
/**
* Asynchronously loads the game file cache from disk without checking
* which games are present on the file system.
*/
public static void startLoad(Context context)
{
startService(context, ACTION_LOAD);
}
/**
* Asynchronously loads the game file cache from disk without checking
* which games are present on the file system.
*/
public static void startLoad(Context context)
{
startService(context, ACTION_LOAD);
}
/**
* Asynchronously scans for games in the user's configured folders,
* updating the game file cache with the results.
* If startLoad hasn't been called before this, this has no effect.
*/
public static void startRescan(Context context)
{
startService(context, ACTION_RESCAN);
}
/**
* Asynchronously scans for games in the user's configured folders,
* updating the game file cache with the results.
* If startLoad hasn't been called before this, this has no effect.
*/
public static void startRescan(Context context)
{
startService(context, ACTION_RESCAN);
}
public static GameFile addOrGet(String gamePath)
{
// The existence of this one function, which is called from one
// single place, forces us to use synchronization in onHandleIntent...
// A bit annoying, but should be good enough for now
synchronized (gameFileCache)
{
return gameFileCache.addOrGet(gamePath);
}
}
public static GameFile addOrGet(String gamePath)
{
// The existence of this one function, which is called from one
// single place, forces us to use synchronization in onHandleIntent...
// A bit annoying, but should be good enough for now
synchronized (gameFileCache)
{
return gameFileCache.addOrGet(gamePath);
}
}
@Override
protected void onHandleIntent(Intent intent)
{
// Load the game list cache if it isn't already loaded, otherwise do nothing
if (ACTION_LOAD.equals(intent.getAction()) && gameFileCache == null)
{
GameFileCache temp = new GameFileCache(getCacheDir() + File.separator + "gamelist.cache");
synchronized (temp)
{
gameFileCache = temp;
gameFileCache.load();
updateGameFileArray();
}
}
@Override
protected void onHandleIntent(Intent intent)
{
// Load the game list cache if it isn't already loaded, otherwise do nothing
if (ACTION_LOAD.equals(intent.getAction()) && gameFileCache == null)
{
GameFileCache temp = new GameFileCache(getCacheDir() + File.separator + "gamelist.cache");
synchronized (temp)
{
gameFileCache = temp;
gameFileCache.load();
updateGameFileArray();
}
}
// Rescan the file system and update the game list cache with the results
if (ACTION_RESCAN.equals(intent.getAction()) && gameFileCache != null)
{
synchronized (gameFileCache)
{
if (gameFileCache.scanLibrary(this))
{
updateGameFileArray();
}
}
}
}
// Rescan the file system and update the game list cache with the results
if (ACTION_RESCAN.equals(intent.getAction()) && gameFileCache != null)
{
synchronized (gameFileCache)
{
if (gameFileCache.scanLibrary(this))
{
updateGameFileArray();
}
}
}
}
private void updateGameFileArray()
{
GameFile[] gameFilesTemp = gameFileCache.getAllGames();
Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle()));
gameFiles.set(gameFilesTemp);
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_ACTION));
}
private void updateGameFileArray()
{
GameFile[] gameFilesTemp = gameFileCache.getAllGames();
Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle()));
gameFiles.set(gameFilesTemp);
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_ACTION));
}
}

View File

@ -25,142 +25,143 @@ import java.util.List;
public class SyncChannelJobService extends JobService
{
private static final String TAG = "ChannelJobSvc";
private static final String TAG = "ChannelJobSvc";
private SyncChannelTask mSyncChannelTask;
private SyncChannelTask mSyncChannelTask;
@Override
public boolean onStartJob(final JobParameters jobParameters)
{
Log.d(TAG, "Starting channel creation job");
mSyncChannelTask =
new SyncChannelTask(getApplicationContext())
{
@Override
protected void onPostExecute(Boolean success)
{
super.onPostExecute(success);
jobFinished(jobParameters, !success);
}
};
mSyncChannelTask.execute();
return true;
}
@Override
public boolean onStartJob(final JobParameters jobParameters)
{
Log.d(TAG, "Starting channel creation job");
mSyncChannelTask =
new SyncChannelTask(getApplicationContext())
{
@Override
protected void onPostExecute(Boolean success)
{
super.onPostExecute(success);
jobFinished(jobParameters, !success);
}
};
mSyncChannelTask.execute();
return true;
}
@Override
public boolean onStopJob(JobParameters jobParameters)
{
if (mSyncChannelTask != null)
{
mSyncChannelTask.cancel(true);
}
return true;
}
@Override
public boolean onStopJob(JobParameters jobParameters)
{
if (mSyncChannelTask != null)
{
mSyncChannelTask.cancel(true);
}
return true;
}
private static class SyncChannelTask extends AsyncTask<Void, Void, Boolean>
{
private Context context;
private static class SyncChannelTask extends AsyncTask<Void, Void, Boolean>
{
private Context context;
SyncChannelTask(Context context)
{
this.context = context;
}
SyncChannelTask(Context context)
{
this.context = context;
}
/**
* Setup channels
*/
@TargetApi(Build.VERSION_CODES.O)
@Override
protected Boolean doInBackground(Void... voids)
{
List<HomeScreenChannel> subscriptions;
List<Channel> channels = TvUtil.getAllChannels(context);
List<Long> channelIds = new ArrayList<>();
// Checks if the default channels are added.
// If not, create the channels
if (!channels.isEmpty())
{
channels.forEach(channel -> channelIds.add(channel.getId()));
}
else
{
subscriptions = TvUtil.createUniversalSubscriptions();
for (HomeScreenChannel subscription : subscriptions)
{
long channelId = createChannel(subscription);
channelIds.add(channelId);
subscription.setChannelId(channelId);
// Only the first channel added can be browsable without user intervention.
TvContractCompat.requestChannelBrowsable(context, channelId);
}
}
// Schedule triggers to update programs
channelIds.forEach(channel -> TvUtil.scheduleSyncingProgramsForChannel(context, channel));
// Update all channels
TvUtil.updateAllChannels(context);
return true;
}
/**
* Setup channels
*/
@TargetApi(Build.VERSION_CODES.O)
@Override
protected Boolean doInBackground(Void... voids)
{
List<HomeScreenChannel> subscriptions;
List<Channel> channels = TvUtil.getAllChannels(context);
List<Long> channelIds = new ArrayList<>();
// Checks if the default channels are added.
// If not, create the channels
if (!channels.isEmpty())
{
channels.forEach(channel -> channelIds.add(channel.getId()));
}
else
{
subscriptions = TvUtil.createUniversalSubscriptions();
for (HomeScreenChannel subscription : subscriptions)
{
long channelId = createChannel(subscription);
channelIds.add(channelId);
subscription.setChannelId(channelId);
// Only the first channel added can be browsable without user intervention.
TvContractCompat.requestChannelBrowsable(context, channelId);
}
}
// Schedule triggers to update programs
channelIds.forEach(channel -> TvUtil.scheduleSyncingProgramsForChannel(context, channel));
// Update all channels
TvUtil.updateAllChannels(context);
return true;
}
private long createChannel(HomeScreenChannel subscription)
{
long channelId = getChannelIdFromTvProvider(context, subscription);
if (channelId != -1L)
{
return channelId;
}
private long createChannel(HomeScreenChannel subscription)
{
long channelId = getChannelIdFromTvProvider(context, subscription);
if (channelId != -1L)
{
return channelId;
}
// Create the channel since it has not been added to the TV Provider.
Uri appLinkIntentUri = Uri.parse(subscription.getAppLinkIntentUri());
// Create the channel since it has not been added to the TV Provider.
Uri appLinkIntentUri = Uri.parse(subscription.getAppLinkIntentUri());
Channel.Builder builder = new Channel.Builder();
builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
.setDisplayName(subscription.getName())
.setDescription(subscription.getDescription())
.setAppLinkIntentUri(appLinkIntentUri);
Channel.Builder builder = new Channel.Builder();
builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
.setDisplayName(subscription.getName())
.setDescription(subscription.getDescription())
.setAppLinkIntentUri(appLinkIntentUri);
Log.d(TAG, "Creating channel: " + subscription.getName());
Uri channelUrl =
context.getContentResolver()
.insert(
TvContractCompat.Channels.CONTENT_URI,
builder.build().toContentValues());
Log.d(TAG, "Creating channel: " + subscription.getName());
Uri channelUrl =
context.getContentResolver()
.insert(
TvContractCompat.Channels.CONTENT_URI,
builder.build().toContentValues());
channelId = ContentUris.parseId(channelUrl);
Bitmap bitmap = TvUtil.convertToBitmap(context, R.drawable.ic_launcher);
ChannelLogoUtils.storeChannelLogo(context, channelId, bitmap);
channelId = ContentUris.parseId(channelUrl);
Bitmap bitmap = TvUtil.convertToBitmap(context, R.drawable.ic_launcher);
ChannelLogoUtils.storeChannelLogo(context, channelId, bitmap);
return channelId;
}
return channelId;
}
private long getChannelIdFromTvProvider(Context context, HomeScreenChannel subscription)
{
Cursor cursor =
context.getContentResolver().query(
TvContractCompat.Channels.CONTENT_URI,
new String[]{
TvContractCompat.Channels._ID,
TvContract.Channels.COLUMN_DISPLAY_NAME
},
null,
null,
null);
if (cursor != null && cursor.moveToFirst())
{
do
{
Channel channel = Channel.fromCursor(cursor);
if (subscription.getName().equals(channel.getDisplayName()))
{
Log.d(
TAG,
"Channel already exists. Returning channel "
+ channel.getId()
+ " from TV Provider.");
return channel.getId();
}
} while (cursor.moveToNext());
}
return -1L;
}
}
private long getChannelIdFromTvProvider(Context context, HomeScreenChannel subscription)
{
Cursor cursor =
context.getContentResolver().query(
TvContractCompat.Channels.CONTENT_URI,
new String[]{
TvContractCompat.Channels._ID,
TvContract.Channels.COLUMN_DISPLAY_NAME
},
null,
null,
null);
if (cursor != null && cursor.moveToFirst())
{
do
{
Channel channel = Channel.fromCursor(cursor);
if (subscription.getName().equals(channel.getDisplayName()))
{
Log.d(
TAG,
"Channel already exists. Returning channel "
+ channel.getId()
+ " from TV Provider.");
return channel.getId();
}
}
while (cursor.moveToNext());
}
return -1L;
}
}
}

View File

@ -2,9 +2,7 @@ package org.dolphinemu.dolphinemu.services;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.PersistableBundle;
@ -25,138 +23,138 @@ import java.util.List;
public class SyncProgramsJobService extends JobService
{
private static final String TAG = "SyncProgramsJobService";
private static final String TAG = "SyncProgramsJobService";
private SyncProgramsTask mSyncProgramsTask;
private SyncProgramsTask mSyncProgramsTask;
@Override
public boolean onStartJob(final JobParameters jobParameters)
{
Log.d(TAG, "onStartJob(): " + jobParameters);
final long channelId = getChannelId(jobParameters);
if (channelId == -1L)
{
Log.d(TAG, "Failed to find channel");
return false;
}
@Override
public boolean onStartJob(final JobParameters jobParameters)
{
Log.d(TAG, "onStartJob(): " + jobParameters);
final long channelId = getChannelId(jobParameters);
if (channelId == -1L)
{
Log.d(TAG, "Failed to find channel");
return false;
}
mSyncProgramsTask =
new SyncProgramsTask(getApplicationContext())
{
@Override
protected void onPostExecute(Boolean finished)
{
super.onPostExecute(finished);
mSyncProgramsTask = null;
jobFinished(jobParameters, !finished);
}
};
mSyncProgramsTask.execute(channelId);
return true;
}
mSyncProgramsTask =
new SyncProgramsTask(getApplicationContext())
{
@Override
protected void onPostExecute(Boolean finished)
{
super.onPostExecute(finished);
mSyncProgramsTask = null;
jobFinished(jobParameters, !finished);
}
};
mSyncProgramsTask.execute(channelId);
return true;
}
@Override
public boolean onStopJob(JobParameters jobParameters)
{
if (mSyncProgramsTask != null)
{
mSyncProgramsTask.cancel(true);
}
return true;
}
@Override
public boolean onStopJob(JobParameters jobParameters)
{
if (mSyncProgramsTask != null)
{
mSyncProgramsTask.cancel(true);
}
return true;
}
private long getChannelId(JobParameters jobParameters)
{
PersistableBundle extras = jobParameters.getExtras();
return extras.getLong(TvContractCompat.EXTRA_CHANNEL_ID, -1L);
}
private long getChannelId(JobParameters jobParameters)
{
PersistableBundle extras = jobParameters.getExtras();
return extras.getLong(TvContractCompat.EXTRA_CHANNEL_ID, -1L);
}
private static class SyncProgramsTask extends AsyncTask<Long, Void, Boolean>
{
private Context context;
private List<GameFile> updatePrograms;
private static class SyncProgramsTask extends AsyncTask<Long, Void, Boolean>
{
private Context context;
private List<GameFile> updatePrograms;
private SyncProgramsTask(Context context)
{
this.context = context;
updatePrograms = new ArrayList<>();
}
private SyncProgramsTask(Context context)
{
this.context = context;
updatePrograms = new ArrayList<>();
}
/**
* Determines which channel to update, get the game files for the channel,
* then updates the list
*/
@Override
protected Boolean doInBackground(Long... channelIds)
{
List<Long> params = Arrays.asList(channelIds);
if (!params.isEmpty())
{
for (Long channelId : params)
{
Channel channel = TvUtil.getChannelById(context, channelId);
for (Platform platform : Platform.values())
{
if (channel != null && channel.getDisplayName().equals(platform.getHeaderName()))
{
getGamesByPlatform(platform);
syncPrograms(channelId);
}
}
}
}
return true;
}
/**
* Determines which channel to update, get the game files for the channel,
* then updates the list
*/
@Override
protected Boolean doInBackground(Long... channelIds)
{
List<Long> params = Arrays.asList(channelIds);
if (!params.isEmpty())
{
for (Long channelId : params)
{
Channel channel = TvUtil.getChannelById(context, channelId);
for (Platform platform : Platform.values())
{
if (channel != null && channel.getDisplayName().equals(platform.getHeaderName()))
{
getGamesByPlatform(platform);
syncPrograms(channelId);
}
}
}
}
return true;
}
private void getGamesByPlatform(Platform platform)
{
updatePrograms = GameFileCacheService.getGameFilesForPlatform(platform);
}
private void getGamesByPlatform(Platform platform)
{
updatePrograms = GameFileCacheService.getGameFilesForPlatform(platform);
}
private void syncPrograms(long channelId)
{
Log.d(TAG, "Sync programs for channel: " + channelId);
deletePrograms(channelId);
createPrograms(channelId);
}
private void syncPrograms(long channelId)
{
Log.d(TAG, "Sync programs for channel: " + channelId);
deletePrograms(channelId);
createPrograms(channelId);
}
private void createPrograms(long channelId)
{
for (GameFile game : updatePrograms)
{
PreviewProgram previewProgram = buildProgram(channelId, game);
private void createPrograms(long channelId)
{
for (GameFile game : updatePrograms)
{
PreviewProgram previewProgram = buildProgram(channelId, game);
context.getContentResolver()
.insert(
TvContractCompat.PreviewPrograms.CONTENT_URI,
previewProgram.toContentValues());
}
}
context.getContentResolver()
.insert(
TvContractCompat.PreviewPrograms.CONTENT_URI,
previewProgram.toContentValues());
}
}
private void deletePrograms(long channelId)
{
context.getContentResolver().delete(
TvContractCompat.buildPreviewProgramsUriForChannel(channelId),
null,
null);
}
private void deletePrograms(long channelId)
{
context.getContentResolver().delete(
TvContractCompat.buildPreviewProgramsUriForChannel(channelId),
null,
null);
}
private PreviewProgram buildProgram(long channelId, GameFile game)
{
Uri appLinkUri = AppLinkHelper.buildGameUri(channelId, game.getGameId());
Uri banner = TvUtil.buildBanner(game, context);
if (banner == null)
banner = TvUtil.getUriToResource(context, R.drawable.banner_tv);
private PreviewProgram buildProgram(long channelId, GameFile game)
{
Uri appLinkUri = AppLinkHelper.buildGameUri(channelId, game.getGameId());
Uri banner = TvUtil.buildBanner(game, context);
if (banner == null)
banner = TvUtil.getUriToResource(context, R.drawable.banner_tv);
PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(channelId)
.setType(TvContractCompat.PreviewProgramColumns.TYPE_GAME)
.setTitle(game.getTitle())
.setDescription(game.getDescription())
.setPosterArtUri(banner)
.setPosterArtAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_2_3)
.setIntentUri(appLinkUri);
return builder.build();
}
}
PreviewProgram.Builder builder = new PreviewProgram.Builder();
builder.setChannelId(channelId)
.setType(TvContractCompat.PreviewProgramColumns.TYPE_GAME)
.setTitle(game.getTitle())
.setDescription(game.getDescription())
.setPosterArtUri(banner)
.setPosterArtAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_2_3)
.setIntentUri(appLinkUri);
return builder.build();
}
}
}

View File

@ -5,10 +5,15 @@ import android.content.Intent;
public final class USBPermService extends IntentService
{
public USBPermService() { super("USBPermService"); }
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)
{
}
}

View File

@ -17,141 +17,141 @@ import android.view.View;
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)
{
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(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)
{
mDivider = divider;
}
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
boolean showLastDivider)
{
this(divider);
mShowFirstDivider = showFirstDivider;
mShowLastDivider = showLastDivider;
}
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;
}
@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;
}
if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
{
outRect.top = mDivider.getIntrinsicHeight();
}
else
{
outRect.left = mDivider.getIntrinsicWidth();
}
}
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;
}
@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();
// 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();
}
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();
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);
}
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);
}
}
// 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.");
}
}
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.");
}
}
}

View File

@ -15,11 +15,11 @@ import android.view.View;
*/
public final class NVidiaShieldWorkaroundView extends View
{
public NVidiaShieldWorkaroundView(Context context, AttributeSet attrs)
{
super(context, attrs);
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);
}
}

View File

@ -11,70 +11,72 @@ import android.widget.TextView;
import org.dolphinemu.dolphinemu.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;
}
@Override
public void setTitle(CharSequence titleText)
{
CustomTitleView.this.setTitle(titleText);
}
@Override
public void setBadgeDrawable(Drawable drawable)
{
CustomTitleView.this.setBadgeDrawable(drawable);
}
};
public CustomTitleView(Context context)
private final TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter()
{
@Override
public View getSearchAffordanceView()
{
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 = (TextView) 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);
}
return null;
}
@Override
public TitleViewAdapter getTitleViewAdapter()
public void setTitle(CharSequence titleText)
{
return mTitleViewAdapter;
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 = (TextView) 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;
}
}

View File

@ -17,12 +17,12 @@ import android.widget.Toast;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
import org.dolphinemu.dolphinemu.utils.StartupHandler;
@ -33,206 +33,211 @@ import org.dolphinemu.dolphinemu.utils.StartupHandler;
*/
public final class MainActivity extends AppCompatActivity implements MainView
{
private ViewPager mViewPager;
private Toolbar mToolbar;
private TabLayout mTabLayout;
private FloatingActionButton mFab;
private ViewPager mViewPager;
private Toolbar mToolbar;
private TabLayout mTabLayout;
private FloatingActionButton mFab;
private MainPresenter mPresenter = new MainPresenter(this, this);
private MainPresenter mPresenter = new MainPresenter(this, 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);
mTabLayout.setupWithViewPager(mViewPager);
mTabLayout.setupWithViewPager(mViewPager);
// 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))
{
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
getSupportFragmentManager(), this);
mViewPager.setAdapter(platformPagerAdapter);
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount());
showGames();
GameFileCacheService.startLoad(this);
}
else
{
mViewPager.setVisibility(View.INVISIBLE);
}
}
if (PermissionsHandler.hasWriteAccess(this))
{
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
getSupportFragmentManager(), this);
mViewPager.setAdapter(platformPagerAdapter);
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount());
showGames();
GameFileCacheService.startLoad(this);
}
else
{
mViewPager.setVisibility(View.INVISIBLE);
}
}
@Override
protected void onResume()
{
super.onResume();
mPresenter.addDirIfNeeded(this);
}
@Override
protected void onResume()
{
super.onResume();
mPresenter.addDirIfNeeded(this);
}
@Override
protected void onDestroy()
{
super.onDestroy();
mPresenter.onDestroy();
}
@Override
protected void onDestroy()
{
super.onDestroy();
mPresenter.onDestroy();
}
@Override
protected void onStart()
{
super.onStart();
StartupHandler.checkSessionReset(this);
}
@Override
protected void onStart()
{
super.onStart();
StartupHandler.checkSessionReset(this);
}
@Override
protected void onStop()
{
super.onStop();
StartupHandler.setSessionTime(this);
}
@Override
protected void onStop()
{
super.onStop();
StartupHandler.setSessionTime(this);
}
// TODO: Replace with a ButterKnife injection.
private void findViews()
{
mToolbar = (Toolbar) findViewById(R.id.toolbar_main);
mViewPager = (ViewPager) findViewById(R.id.pager_platforms);
mTabLayout = (TabLayout) findViewById(R.id.tabs_platforms);
mFab = (FloatingActionButton) findViewById(R.id.button_add_directory);
}
// TODO: Replace with a ButterKnife injection.
private void findViews()
{
mToolbar = (Toolbar) findViewById(R.id.toolbar_main);
mViewPager = (ViewPager) findViewById(R.id.pager_platforms);
mTabLayout = (TabLayout) findViewById(R.id.tabs_platforms);
mFab = (FloatingActionButton) 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;
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_game_grid, menu);
return true;
}
/**
* MainView
*/
/**
* MainView
*/
@Override
public void setVersionString(String version)
{
mToolbar.setSubtitle(version);
}
@Override
public void setVersionString(String version)
{
mToolbar.setSubtitle(version);
}
@Override
public void refreshFragmentScreenshot(int fragmentPosition)
{
// Invalidate Picasso image so that the new screenshot is animated in.
Platform platform = Platform.fromPosition(mViewPager.getCurrentItem());
PlatformGamesView fragment = getPlatformGamesView(platform);
@Override
public void refreshFragmentScreenshot(int fragmentPosition)
{
// Invalidate Picasso image so that the new screenshot is animated in.
Platform platform = Platform.fromPosition(mViewPager.getCurrentItem());
PlatformGamesView fragment = getPlatformGamesView(platform);
if (fragment != null)
{
fragment.refreshScreenshotAtPosition(fragmentPosition);
}
}
if (fragment != null)
{
fragment.refreshScreenshotAtPosition(fragmentPosition);
}
}
@Override
public void launchSettingsActivity(MenuTag menuTag)
{
SettingsActivity.launch(this, menuTag, "");
}
@Override
public void launchSettingsActivity(MenuTag menuTag)
{
SettingsActivity.launch(this, menuTag, "");
}
@Override
public void launchFileListActivity()
{
FileBrowserHelper.openDirectoryPicker(this);
}
@Override
public void launchFileListActivity()
{
FileBrowserHelper.openDirectoryPicker(this);
}
/**
* @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;
/**
* @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;
}
}
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);
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
getSupportFragmentManager(), this);
mViewPager.setAdapter(platformPagerAdapter);
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount());
mTabLayout.setupWithViewPager(mViewPager);
mViewPager.setVisibility(View.VISIBLE);
GameFileCacheService.startLoad(this);
} else {
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
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);
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
getSupportFragmentManager(), this);
mViewPager.setAdapter(platformPagerAdapter);
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount());
mTabLayout.setupWithViewPager(mViewPager);
mViewPager.setVisibility(View.VISIBLE);
GameFileCacheService.startLoad(this);
}
else
{
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show();
}
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(), this);
}
/**
* 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(), this);
}
public void showGames()
{
for (Platform platform : Platform.values())
{
PlatformGamesView fragment = getPlatformGamesView(platform);
if (fragment != null)
{
fragment.showGames();
}
}
}
public void showGames()
{
for (Platform platform : Platform.values())
{
PlatformGamesView fragment = getPlatformGamesView(platform);
if (fragment != null)
{
fragment.showGames();
}
}
}
@Nullable
private PlatformGamesView getPlatformGamesView(Platform platform)
{
String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform.toInt();
@Nullable
private PlatformGamesView getPlatformGamesView(Platform platform)
{
String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform.toInt();
return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag);
}
return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag);
}
}

View File

@ -8,106 +8,106 @@ import android.support.v4.content.LocalBroadcastManager;
import org.dolphinemu.dolphinemu.BuildConfig;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.model.GameFileCache;
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class MainPresenter
{
public static final int REQUEST_ADD_DIRECTORY = 1;
public static final int REQUEST_EMULATE_GAME = 2;
public static final int REQUEST_ADD_DIRECTORY = 1;
public static final int REQUEST_EMULATE_GAME = 2;
private final MainView mView;
private final Context mContext;
private BroadcastReceiver mBroadcastReceiver = null;
private String mDirToAdd;
private final MainView mView;
private final Context mContext;
private BroadcastReceiver mBroadcastReceiver = null;
private String mDirToAdd;
public MainPresenter(MainView view, Context context)
{
mView = view;
mContext = context;
}
public MainPresenter(MainView view, Context context)
{
mView = view;
mContext = context;
}
public void onCreate()
{
String versionName = BuildConfig.VERSION_NAME;
mView.setVersionString(versionName);
public void onCreate()
{
String versionName = BuildConfig.VERSION_NAME;
mView.setVersionString(versionName);
IntentFilter filter = new IntentFilter();
filter.addAction(GameFileCacheService.BROADCAST_ACTION);
mBroadcastReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
mView.showGames();
}
};
LocalBroadcastManager.getInstance(mContext).registerReceiver(mBroadcastReceiver, filter);
}
IntentFilter filter = new IntentFilter();
filter.addAction(GameFileCacheService.BROADCAST_ACTION);
mBroadcastReceiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
mView.showGames();
}
};
LocalBroadcastManager.getInstance(mContext).registerReceiver(mBroadcastReceiver, filter);
}
public void onDestroy()
{
if (mBroadcastReceiver != null)
{
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mBroadcastReceiver);
}
}
public void onDestroy()
{
if (mBroadcastReceiver != null)
{
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mBroadcastReceiver);
}
}
public void onFabClick()
{
mView.launchFileListActivity();
}
public void onFabClick()
{
mView.launchFileListActivity();
}
public boolean handleOptionSelection(int itemId, Context context)
{
switch (itemId)
{
case R.id.menu_settings_core:
mView.launchSettingsActivity(MenuTag.CONFIG);
return true;
public boolean handleOptionSelection(int itemId, Context context)
{
switch (itemId)
{
case R.id.menu_settings_core:
mView.launchSettingsActivity(MenuTag.CONFIG);
return true;
case R.id.menu_settings_graphics:
mView.launchSettingsActivity(MenuTag.GRAPHICS);
return true;
case R.id.menu_settings_graphics:
mView.launchSettingsActivity(MenuTag.GRAPHICS);
return true;
case R.id.menu_settings_gcpad:
mView.launchSettingsActivity(MenuTag.GCPAD_TYPE);
return true;
case R.id.menu_settings_gcpad:
mView.launchSettingsActivity(MenuTag.GCPAD_TYPE);
return true;
case R.id.menu_settings_wiimote:
mView.launchSettingsActivity(MenuTag.WIIMOTE);
return true;
case R.id.menu_settings_wiimote:
mView.launchSettingsActivity(MenuTag.WIIMOTE);
return true;
case R.id.menu_refresh:
GameFileCacheService.startRescan(context);
return true;
case R.id.menu_refresh:
GameFileCacheService.startRescan(context);
return true;
case R.id.button_add_directory:
mView.launchFileListActivity();
return true;
}
case R.id.button_add_directory:
mView.launchFileListActivity();
return true;
}
return false;
}
return false;
}
public void addDirIfNeeded(Context context)
{
if (mDirToAdd != null)
{
GameFileCache.addGameFolder(mDirToAdd, context);
mDirToAdd = null;
GameFileCacheService.startRescan(context);
}
}
public void addDirIfNeeded(Context context)
{
if (mDirToAdd != null)
{
GameFileCache.addGameFolder(mDirToAdd, context);
mDirToAdd = null;
GameFileCacheService.startRescan(context);
}
}
public void onDirectorySelected(String dir)
{
mDirToAdd = dir;
}
public void onDirectorySelected(String dir)
{
mDirToAdd = dir;
}
public void refreshFragmentScreenshot(int resultCode)
{
mView.refreshFragmentScreenshot(resultCode);
}
public void refreshFragmentScreenshot(int resultCode)
{
mView.refreshFragmentScreenshot(resultCode);
}
}

View File

@ -9,29 +9,29 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
*/
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);
/**
* 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 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(MenuTag menuTag);
void launchSettingsActivity(MenuTag menuTag);
void launchFileListActivity();
void launchFileListActivity();
/**
* To be called when the game file cache is updated.
*/
void showGames();
/**
* To be called when the game file cache is updated.
*/
void showGames();
}

View File

@ -18,13 +18,13 @@ import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.model.TvSettingsItem;
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
import org.dolphinemu.dolphinemu.utils.StartupHandler;
@ -35,249 +35,257 @@ import java.util.Collection;
public final class TvMainActivity extends FragmentActivity implements MainView
{
private MainPresenter mPresenter = new MainPresenter(this, this);
private MainPresenter mPresenter = new MainPresenter(this, 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);
}
// Setup and/or sync channels
TvUtil.scheduleSyncingChannel(getApplicationContext());
}
// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
if (savedInstanceState == null)
{
StartupHandler.HandleInit(this);
}
// Setup and/or sync channels
TvUtil.scheduleSyncingChannel(getApplicationContext());
}
@Override
protected void onResume()
{
super.onResume();
mPresenter.addDirIfNeeded(this);
}
@Override
protected void onResume()
{
super.onResume();
mPresenter.addDirIfNeeded(this);
}
@Override
protected void onDestroy()
{
super.onDestroy();
mPresenter.onDestroy();
}
@Override
protected void onDestroy()
{
super.onDestroy();
mPresenter.onDestroy();
}
@Override
protected void onStart()
{
super.onStart();
StartupHandler.checkSessionReset(this);
}
@Override
protected void onStart()
{
super.onStart();
StartupHandler.checkSessionReset(this);
}
@Override
protected void onStop()
{
super.onStop();
StartupHandler.setSessionTime(this);
}
@Override
protected void onStop()
{
super.onStop();
StartupHandler.setSessionTime(this);
}
void setupUI() {
final FragmentManager fragmentManager = getSupportFragmentManager();
mBrowseFragment = new BrowseSupportFragment();
fragmentManager
.beginTransaction()
.add(R.id.content, mBrowseFragment, "BrowseFragment")
.commit();
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.dolphin_blue_dark));
buildRowsAdapter();
// Set display parameters for the BrowseFragment
mBrowseFragment.setHeadersState(BrowseFragment.HEADERS_ENABLED);
mBrowseFragment.setBrandColor(ContextCompat.getColor(this, R.color.dolphin_blue_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(), this);
}
else
{
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;
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(), this);
}
else
{
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;
// Start the emulation activity and send the path of the clicked ISO to it.
EmulationActivity.launch(TvMainActivity.this,
holder.gameFile,
-1,
holder.imageScreenshot);
}
});
}
/**
* MainView
*/
// Start the emulation activity and send the path of the clicked ISO to it.
EmulationActivity.launch(TvMainActivity.this,
holder.gameFile,
-1,
holder.imageScreenshot);
}
});
}
@Override
public void setVersionString(String version)
{
mBrowseFragment.setTitle(version);
}
/**
* MainView
*/
@Override
public void refreshFragmentScreenshot(int fragmentPosition)
{
mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
}
@Override
public void setVersionString(String version)
{
mBrowseFragment.setTitle(version);
}
@Override
public void launchSettingsActivity(MenuTag menuTag)
{
SettingsActivity.launch(this, menuTag, "");
}
@Override
public void refreshFragmentScreenshot(int fragmentPosition)
{
mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
}
@Override
public void launchFileListActivity()
{
FileBrowserHelper.openDirectoryPicker(this);
}
@Override
public void launchSettingsActivity(MenuTag menuTag)
{
SettingsActivity.launch(this, menuTag, "");
}
@Override
public void showGames()
{
// Kicks off the program services to update all channels
TvUtil.updateAllChannels(getApplicationContext());
@Override
public void launchFileListActivity()
{
FileBrowserHelper.openDirectoryPicker(this);
}
recreate();
}
@Override
public void showGames()
{
// Kicks off the program services to update all channels
TvUtil.updateAllChannels(getApplicationContext());
/**
* 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;
recreate();
}
case MainPresenter.REQUEST_EMULATE_GAME:
mPresenter.refreshFragmentScreenshot(resultCode);
break;
}
}
/**
* 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;
@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);
GameFileCacheService.startLoad(this);
} else {
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
}
case MainPresenter.REQUEST_EMULATE_GAME:
mPresenter.refreshFragmentScreenshot(resultCode);
break;
}
}
private void buildRowsAdapter()
{
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
@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);
GameFileCacheService.startLoad(this);
}
else
{
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
}
if (PermissionsHandler.hasWriteAccess(this))
{
GameFileCacheService.startLoad(this);
}
private void buildRowsAdapter()
{
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
for (Platform platform : Platform.values())
{
ListRow row = buildGamesRow(platform, GameFileCacheService.getGameFilesForPlatform(platform));
if (PermissionsHandler.hasWriteAccess(this))
{
GameFileCacheService.startLoad(this);
}
// Add row to the adapter only if it is not empty.
if (row != null)
{
mRowsAdapter.add(row);
}
}
for (Platform platform : Platform.values())
{
ListRow row = buildGamesRow(platform, GameFileCacheService.getGameFilesForPlatform(platform));
mRowsAdapter.add(buildSettingsRow());
// Add row to the adapter only if it is not empty.
if (row != null)
{
mRowsAdapter.add(row);
}
}
mBrowseFragment.setAdapter(mRowsAdapter);
}
mRowsAdapter.add(buildSettingsRow());
private ListRow buildGamesRow(Platform platform, Collection<GameFile> gameFiles)
{
// If there are no games, don't return a Row.
if (gameFiles.size() == 0)
{
return null;
}
mBrowseFragment.setAdapter(mRowsAdapter);
}
// Create an adapter for this row.
ArrayObjectAdapter row = new ArrayObjectAdapter(new GameRowPresenter());
row.addAll(0, gameFiles);
private ListRow buildGamesRow(Platform platform, Collection<GameFile> gameFiles)
{
// If there are no games, don't return a Row.
if (gameFiles.size() == 0)
{
return null;
}
// Create a header for this row.
HeaderItem header = new HeaderItem(platform.toInt(), platform.getHeaderName());
// Create an adapter for this row.
ArrayObjectAdapter row = new ArrayObjectAdapter(new GameRowPresenter());
row.addAll(0, gameFiles);
// Create the row, passing it the filled adapter and the header, and give it to the master adapter.
return new ListRow(header, row);
}
// Create a header for this row.
HeaderItem header = new HeaderItem(platform.toInt(), platform.getHeaderName());
private ListRow buildSettingsRow()
{
ArrayObjectAdapter rowItems = new ArrayObjectAdapter(new SettingsRowPresenter());
// Create the row, passing it the filled adapter and the header, and give it to the master adapter.
return new ListRow(header, row);
}
rowItems.add(new TvSettingsItem(R.id.menu_settings_core,
R.drawable.ic_settings_core_tv,
R.string.grid_menu_config));
private ListRow buildSettingsRow()
{
ArrayObjectAdapter rowItems = new ArrayObjectAdapter(new SettingsRowPresenter());
rowItems.add(new TvSettingsItem(R.id.menu_settings_graphics,
R.drawable.ic_settings_graphics_tv,
R.string.grid_menu_graphics_settings));
rowItems.add(new TvSettingsItem(R.id.menu_settings_core,
R.drawable.ic_settings_core_tv,
R.string.grid_menu_config));
rowItems.add(new TvSettingsItem(R.id.menu_settings_gcpad,
R.drawable.ic_settings_gcpad,
R.string.grid_menu_gcpad_settings));
rowItems.add(new TvSettingsItem(R.id.menu_settings_graphics,
R.drawable.ic_settings_graphics_tv,
R.string.grid_menu_graphics_settings));
rowItems.add(new TvSettingsItem(R.id.menu_settings_wiimote,
R.drawable.ic_settings_wiimote,
R.string.grid_menu_wiimote_settings));
rowItems.add(new TvSettingsItem(R.id.menu_settings_gcpad,
R.drawable.ic_settings_gcpad,
R.string.grid_menu_gcpad_settings));
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_settings_wiimote,
R.drawable.ic_settings_wiimote,
R.string.grid_menu_wiimote_settings));
rowItems.add(new TvSettingsItem(R.id.menu_refresh,
R.drawable.ic_refresh_tv,
R.string.grid_menu_refresh));
rowItems.add(new TvSettingsItem(R.id.button_add_directory,
R.drawable.ic_add_tv,
R.string.add_directory_title));
// 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_refresh,
R.drawable.ic_refresh_tv,
R.string.grid_menu_refresh));
return new ListRow(header, rowItems);
}
// Create a header for this row.
HeaderItem header =
new HeaderItem(R.string.preferences_settings, getString(R.string.preferences_settings));
return new ListRow(header, rowItems);
}
}

View File

@ -1,45 +1,47 @@
package org.dolphinemu.dolphinemu.ui.platform;
/** Enum to represent platform (eg GameCube, Wii). */
/**
* Enum to represent platform (eg GameCube, Wii).
*/
public enum Platform
{
GAMECUBE(0, "GameCube Games"),
WII(1, "Wii Games"),
WIIWARE(2, "WiiWare Games");
GAMECUBE(0, "GameCube Games"),
WII(1, "Wii Games"),
WIIWARE(2, "WiiWare Games");
private final int value;
private final String headerName;
private final int value;
private final String headerName;
Platform(int value, String headerName)
{
this.value = value;
this.headerName = headerName;
}
Platform(int value, String headerName)
{
this.value = value;
this.headerName = headerName;
}
public static Platform fromInt(int i)
{
return values()[i];
}
public static Platform fromInt(int i)
{
return values()[i];
}
public static Platform fromNativeInt(int i)
{
// TODO: Proper support for DOL and ELF files
boolean in_range = i >= 0 && i < values().length;
return values()[in_range ? i : WIIWARE.value];
}
public static Platform fromNativeInt(int i)
{
// TODO: Proper support for DOL and ELF files
boolean in_range = i >= 0 && i < values().length;
return values()[in_range ? i : WIIWARE.value];
}
public static Platform fromPosition(int position)
{
return values()[position];
}
public static Platform fromPosition(int position)
{
return values()[position];
}
public int toInt()
{
return value;
}
public int toInt()
{
return value;
}
public String getHeaderName()
{
return headerName;
}
public String getHeaderName()
{
return headerName;
}
}

View File

@ -11,85 +11,82 @@ import android.view.ViewGroup;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.adapters.GameAdapter;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
import java.util.List;
public final class PlatformGamesFragment extends Fragment implements PlatformGamesView
{
private static final String ARG_PLATFORM = "platform";
private static final String ARG_PLATFORM = "platform";
private GameAdapter mAdapter;
private RecyclerView mRecyclerView;
private GameAdapter mAdapter;
private RecyclerView mRecyclerView;
public static PlatformGamesFragment newInstance(Platform platform)
{
PlatformGamesFragment fragment = new PlatformGamesFragment();
public static PlatformGamesFragment newInstance(Platform platform)
{
PlatformGamesFragment fragment = new PlatformGamesFragment();
Bundle args = new Bundle();
args.putSerializable(ARG_PLATFORM, platform);
Bundle args = new Bundle();
args.putSerializable(ARG_PLATFORM, platform);
fragment.setArguments(args);
return fragment;
}
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
@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);
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_grid, container, false);
findViews(rootView);
findViews(rootView);
return rootView;
}
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();
@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.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8));
mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8));
showGames();
}
showGames();
}
@Override
public void refreshScreenshotAtPosition(int position)
{
mAdapter.notifyItemChanged(position);
}
@Override
public void refreshScreenshotAtPosition(int position)
{
mAdapter.notifyItemChanged(position);
}
@Override
public void onItemClick(String gameId)
{
// No-op for now
}
@Override
public void onItemClick(String gameId)
{
// No-op for now
}
@Override
public void showGames()
{
if (mAdapter != null)
{
Platform platform = (Platform) getArguments().getSerializable(ARG_PLATFORM);
mAdapter.swapDataSet(GameFileCacheService.getGameFilesForPlatform(platform));
}
}
@Override
public void showGames()
{
if (mAdapter != null)
{
Platform platform = (Platform) getArguments().getSerializable(ARG_PLATFORM);
mAdapter.swapDataSet(GameFileCacheService.getGameFilesForPlatform(platform));
}
}
private void findViews(View root)
{
mRecyclerView = (RecyclerView) root.findViewById(R.id.grid_games);
}
private void findViews(View root)
{
mRecyclerView = (RecyclerView) root.findViewById(R.id.grid_games);
}
}

View File

@ -1,32 +1,28 @@
package org.dolphinemu.dolphinemu.ui.platform;
import org.dolphinemu.dolphinemu.model.GameFile;
import java.util.List;
/**
* Abstraction for a screen representing a single platform's games.
*/
public interface PlatformGamesView
{
/**
* 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 the game file cache is updated.
*/
void showGames();
/**
* To be called when the game file cache is updated.
*/
void showGames();
}

View File

@ -18,108 +18,111 @@ import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
public class Analytics
{
private static DirectoryStateReceiver directoryStateReceiver;
private static DirectoryStateReceiver directoryStateReceiver;
private static final String analyticsAsked = Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_PERMISSION_ASKED;
private static final String analyticsEnabled = Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_ENABLED;
private static final String analyticsAsked =
Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_PERMISSION_ASKED;
private static final String analyticsEnabled =
Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_ENABLED;
private static final String DEVICE_MANUFACTURER = "DEVICE_MANUFACTURER";
private static final String DEVICE_OS = "DEVICE_OS";
private static final String DEVICE_MODEL = "DEVICE_MODEL";
private static final String DEVICE_TYPE = "DEVICE_TYPE";
private static final String DEVICE_MANUFACTURER = "DEVICE_MANUFACTURER";
private static final String DEVICE_OS = "DEVICE_OS";
private static final String DEVICE_MODEL = "DEVICE_MODEL";
private static final String DEVICE_TYPE = "DEVICE_TYPE";
private static String deviceType;
private static String deviceType;
public static void checkAnalyticsInit(Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (!preferences.getBoolean(analyticsAsked, false))
{
if (!DirectoryInitializationService.areDolphinDirectoriesReady())
{
// Wait for directories to get initialized
IntentFilter statusIntentFilter = new IntentFilter(
DirectoryInitializationService.BROADCAST_ACTION);
public static void checkAnalyticsInit(Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
if (!preferences.getBoolean(analyticsAsked, false))
{
if (!DirectoryInitializationService.areDolphinDirectoriesReady())
{
// Wait for directories to get initialized
IntentFilter statusIntentFilter = new IntentFilter(
DirectoryInitializationService.BROADCAST_ACTION);
directoryStateReceiver = new DirectoryStateReceiver(directoryInitializationState ->
{
if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
{
LocalBroadcastManager.getInstance(context).unregisterReceiver(directoryStateReceiver);
directoryStateReceiver = null;
showMessage(context, preferences);
}
});
// Registers the DirectoryStateReceiver and its intent filters
LocalBroadcastManager.getInstance(context).registerReceiver(
directoryStateReceiver,
statusIntentFilter);
}
else
{
showMessage(context, preferences);
}
}
// Get device type now since we have a context
deviceType = TvUtil.isLeanback(context) ? "android-tv" : "android-mobile";
}
directoryStateReceiver = new DirectoryStateReceiver(directoryInitializationState ->
{
if (directoryInitializationState ==
DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
{
LocalBroadcastManager.getInstance(context).unregisterReceiver(directoryStateReceiver);
directoryStateReceiver = null;
showMessage(context, preferences);
}
});
// Registers the DirectoryStateReceiver and its intent filters
LocalBroadcastManager.getInstance(context).registerReceiver(
directoryStateReceiver,
statusIntentFilter);
}
else
{
showMessage(context, preferences);
}
}
// Get device type now since we have a context
deviceType = TvUtil.isLeanback(context) ? "android-tv" : "android-mobile";
}
private static void showMessage(Context context, SharedPreferences preferences)
{
// We asked, set to true regardless of answer
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putBoolean(analyticsAsked, true);
sPrefsEditor.apply();
private static void showMessage(Context context, SharedPreferences preferences)
{
// We asked, set to true regardless of answer
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putBoolean(analyticsAsked, true);
sPrefsEditor.apply();
new AlertDialog.Builder(context)
.setTitle(context.getString(R.string.analytics))
.setMessage(context.getString(R.string.analytics_desc))
.setPositiveButton(R.string.yes, (dialogInterface, i) ->
{
sPrefsEditor.putBoolean(analyticsEnabled, true);
sPrefsEditor.apply();
SettingsFile.firstAnalyticsAdd(true);
})
.setNegativeButton(R.string.no, (dialogInterface, i) ->
{
sPrefsEditor.putBoolean(analyticsEnabled, false);
sPrefsEditor.apply();
SettingsFile.firstAnalyticsAdd(false);
})
.create()
.show();
}
new AlertDialog.Builder(context)
.setTitle(context.getString(R.string.analytics))
.setMessage(context.getString(R.string.analytics_desc))
.setPositiveButton(R.string.yes, (dialogInterface, i) ->
{
sPrefsEditor.putBoolean(analyticsEnabled, true);
sPrefsEditor.apply();
SettingsFile.firstAnalyticsAdd(true);
})
.setNegativeButton(R.string.no, (dialogInterface, i) ->
{
sPrefsEditor.putBoolean(analyticsEnabled, false);
sPrefsEditor.apply();
SettingsFile.firstAnalyticsAdd(false);
})
.create()
.show();
}
public static void sendReport(String endpoint, byte[] data)
{
StringRequest request = new StringRequest(Request.Method.POST, endpoint,
null, error -> Log.debug("Send Report Failure code: "
+ error.networkResponse.statusCode))
{
@Override
public byte[] getBody()
{
return data;
}
};
public static void sendReport(String endpoint, byte[] data)
{
StringRequest request = new StringRequest(Request.Method.POST, endpoint,
null, error -> Log.debug("Send Report Failure code: "
+ error.networkResponse.statusCode))
{
@Override
public byte[] getBody()
{
return data;
}
};
VolleyUtil.getQueue().add(request);
}
VolleyUtil.getQueue().add(request);
}
public static String getValue(String key)
{
switch (key)
{
case DEVICE_MODEL:
return Build.MODEL;
case DEVICE_MANUFACTURER:
return Build.MANUFACTURER;
case DEVICE_OS:
return String.valueOf(Build.VERSION.SDK_INT);
case DEVICE_TYPE:
return deviceType;
default:
return "";
}
}
public static String getValue(String key)
{
switch (key)
{
case DEVICE_MODEL:
return Build.MODEL;
case DEVICE_MANUFACTURER:
return Build.MANUFACTURER;
case DEVICE_OS:
return String.valueOf(Build.VERSION.SDK_INT);
case DEVICE_TYPE:
return deviceType;
default:
return "";
}
}
}

View File

@ -5,25 +5,25 @@ import android.view.ViewPropertyAnimator;
public final class Animations
{
private 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);
}
}

View File

@ -10,150 +10,150 @@ import java.util.List;
*/
public class AppLinkHelper
{
public static final String PLAY = "play";
public static final String BROWSE = "browse";
private static final String SCHEMA_URI_PREFIX = "dolphinemu://app/";
private static final String URI_PLAY = SCHEMA_URI_PREFIX + PLAY;
private static final String URI_VIEW = SCHEMA_URI_PREFIX + BROWSE;
private static final int URI_INDEX_OPTION = 0;
private static final int URI_INDEX_CHANNEL = 1;
private static final int URI_INDEX_GAME = 2;
public static final String PLAY = "play";
public static final String BROWSE = "browse";
private static final String SCHEMA_URI_PREFIX = "dolphinemu://app/";
private static final String URI_PLAY = SCHEMA_URI_PREFIX + PLAY;
private static final String URI_VIEW = SCHEMA_URI_PREFIX + BROWSE;
private static final int URI_INDEX_OPTION = 0;
private static final int URI_INDEX_CHANNEL = 1;
private static final int URI_INDEX_GAME = 2;
public static Uri buildGameUri(long channelId, String gameId)
{
return Uri.parse(URI_PLAY)
.buildUpon()
.appendPath(String.valueOf(channelId))
.appendPath(String.valueOf(gameId))
.build();
}
public static Uri buildGameUri(long channelId, String gameId)
{
return Uri.parse(URI_PLAY)
.buildUpon()
.appendPath(String.valueOf(channelId))
.appendPath(String.valueOf(gameId))
.build();
}
public static Uri buildBrowseUri(String subscriptionName)
{
return Uri.parse(URI_VIEW).buildUpon().appendPath(subscriptionName).build();
}
public static Uri buildBrowseUri(String subscriptionName)
{
return Uri.parse(URI_VIEW).buildUpon().appendPath(subscriptionName).build();
}
public static AppLinkAction extractAction(Uri uri)
{
if (isGameUri(uri))
return new PlayAction(extractChannelId(uri), extractGameId(uri));
else if (isBrowseUri(uri))
return new BrowseAction(extractSubscriptionName(uri));
public static AppLinkAction extractAction(Uri uri)
{
if (isGameUri(uri))
return new PlayAction(extractChannelId(uri), extractGameId(uri));
else if (isBrowseUri(uri))
return new BrowseAction(extractSubscriptionName(uri));
throw new IllegalArgumentException("No action found for uri " + uri);
}
throw new IllegalArgumentException("No action found for uri " + uri);
}
private static boolean isGameUri(Uri uri)
{
if (uri.getPathSegments().isEmpty())
{
return false;
}
String option = uri.getPathSegments().get(URI_INDEX_OPTION);
return PLAY.equals(option);
}
private static boolean isGameUri(Uri uri)
{
if (uri.getPathSegments().isEmpty())
{
return false;
}
String option = uri.getPathSegments().get(URI_INDEX_OPTION);
return PLAY.equals(option);
}
private static boolean isBrowseUri(Uri uri)
{
if (uri.getPathSegments().isEmpty())
return false;
private static boolean isBrowseUri(Uri uri)
{
if (uri.getPathSegments().isEmpty())
return false;
String option = uri.getPathSegments().get(URI_INDEX_OPTION);
return BROWSE.equals(option);
}
String option = uri.getPathSegments().get(URI_INDEX_OPTION);
return BROWSE.equals(option);
}
private static String extractSubscriptionName(Uri uri)
{
return extract(uri, URI_INDEX_CHANNEL);
}
private static String extractSubscriptionName(Uri uri)
{
return extract(uri, URI_INDEX_CHANNEL);
}
private static long extractChannelId(Uri uri)
{
return extractLong(uri, URI_INDEX_CHANNEL);
}
private static long extractChannelId(Uri uri)
{
return extractLong(uri, URI_INDEX_CHANNEL);
}
private static String extractGameId(Uri uri)
{
return extract(uri, URI_INDEX_GAME);
}
private static String extractGameId(Uri uri)
{
return extract(uri, URI_INDEX_GAME);
}
private static long extractLong(Uri uri, int index)
{
return Long.valueOf(extract(uri, index));
}
private static long extractLong(Uri uri, int index)
{
return Long.valueOf(extract(uri, index));
}
private static String extract(Uri uri, int index)
{
List<String> pathSegments = uri.getPathSegments();
if (pathSegments.isEmpty() || pathSegments.size() < index)
return null;
return pathSegments.get(index);
}
private static String extract(Uri uri, int index)
{
List<String> pathSegments = uri.getPathSegments();
if (pathSegments.isEmpty() || pathSegments.size() < index)
return null;
return pathSegments.get(index);
}
@StringDef({BROWSE, PLAY})
public @interface ActionFlags
{
}
@StringDef({BROWSE, PLAY})
public @interface ActionFlags
{
}
/**
* Action for deep linking.
*/
public interface AppLinkAction
{
/**
* Returns an string representation of the action.
*/
@ActionFlags
String getAction();
}
/**
* Action for deep linking.
*/
public interface AppLinkAction
{
/**
* Returns an string representation of the action.
*/
@ActionFlags
String getAction();
}
/**
* Action when clicking the channel icon
*/
public static class BrowseAction implements AppLinkAction
{
private final String mSubscriptionName;
/**
* Action when clicking the channel icon
*/
public static class BrowseAction implements AppLinkAction
{
private final String mSubscriptionName;
private BrowseAction(String subscriptionName)
{
this.mSubscriptionName = subscriptionName;
}
private BrowseAction(String subscriptionName)
{
this.mSubscriptionName = subscriptionName;
}
@Override
public String getAction()
{
return BROWSE;
}
}
@Override
public String getAction()
{
return BROWSE;
}
}
/**
* Action when clicking a program(game)
*/
public static class PlayAction implements AppLinkAction
{
private final long channelId;
private final String gameId;
/**
* Action when clicking a program(game)
*/
public static class PlayAction implements AppLinkAction
{
private final long channelId;
private final String gameId;
private PlayAction(long channelId, String gameId)
{
this.channelId = channelId;
this.gameId = gameId;
}
private PlayAction(long channelId, String gameId)
{
this.channelId = channelId;
this.gameId = gameId;
}
public long getChannelId()
{
return channelId;
}
public long getChannelId()
{
return channelId;
}
public String getGameId()
{
return gameId;
}
public String getGameId()
{
return gameId;
}
@Override
public String getAction()
{
return PLAY;
}
}
@Override
public String getAction()
{
return PLAY;
}
}
}

View File

@ -6,22 +6,22 @@ import java.util.Map;
public class BiMap<K, V>
{
private Map<K, V> forward = new HashMap<K, V>();
private Map<V, K> backward = new HashMap<V, K>();
private Map<K, V> forward = new HashMap<K, V>();
private Map<V, K> backward = new HashMap<V, K>();
public synchronized void add(K key, V value)
{
forward.put(key, value);
backward.put(value, key);
}
public synchronized void add(K key, V value)
{
forward.put(key, value);
backward.put(value, key);
}
public synchronized V getForward(K key)
{
return forward.get(key);
}
public synchronized V getForward(K key)
{
return forward.get(key);
}
public synchronized K getBackward(V key)
{
return backward.get(key);
}
public synchronized K getBackward(V key)
{
return backward.get(key);
}
}

View File

@ -4,54 +4,61 @@ import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
/** Some controllers have incorrect mappings. This class has special-case fixes for them. */
/**
* 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 static 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;
}
/**
* Some controllers report extra button presses that can be ignored.
*/
public static 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;
}
/** Scale an axis to be zero-centered with a proper range. */
public static 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;
}
}
return value;
}
/**
* Scale an axis to be zero-centered with a proper range.
*/
public static 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;
}
}
return value;
}
private static boolean isDualShock4(InputDevice inputDevice)
{
// Sony DualShock 4 controller
return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc;
}
private static boolean isDualShock4(InputDevice inputDevice)
{
// Sony DualShock 4 controller
return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc;
}
private static boolean isXboxOneWireless(InputDevice inputDevice)
{
// Microsoft Xbox One controller
return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0;
}
private static boolean isXboxOneWireless(InputDevice inputDevice)
{
// Microsoft Xbox One controller
return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0;
}
}

View File

@ -3,79 +3,78 @@ package org.dolphinemu.dolphinemu.utils;
import android.graphics.Bitmap;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import java.io.FileOutputStream;
public final class CoverHelper
{
private static String baseUrl = "https://art.gametdb.com/wii/cover/%s/%s.png";
private static String baseUrl = "https://art.gametdb.com/wii/cover/%s/%s.png";
public static String buildGameTDBUrl(GameFile game, String region)
{
String gameId = game.getGameId();
if(game.getPlatform() == 2) // WiiWare
gameId = gameId.substring(0,4);
return String.format(baseUrl, region, gameId);
}
public static String buildGameTDBUrl(GameFile game, String region)
{
String gameId = game.getGameId();
if (game.getPlatform() == 2) // WiiWare
gameId = gameId.substring(0, 4);
return String.format(baseUrl, region, gameId);
}
public static String getRegion(GameFile game)
{
String region;
switch(game.getRegion())
{
case 0: // NTSC_J
region = "JA";
break;
case 1: // NTSC_U
region = "US";
break;
case 4: // NTSC_K
region = "KO";
break;
case 2: // PAL
switch (game.getCountry())
{
case 2: // German
region = "DE";
break;
case 3: // French
region = "FR";
break;
case 4: // Spanish
region = "ES";
break;
case 5: // Italian
region = "IT";
break;
case 6: // Dutch
region = "NL";
break;
case 1: // English
default:
region = "EN";
break;
}
break;
case 3: // Unknown
default:
region = "EN";
break;
}
return region;
}
public static String getRegion(GameFile game)
{
String region;
switch (game.getRegion())
{
case 0: // NTSC_J
region = "JA";
break;
case 1: // NTSC_U
region = "US";
break;
case 4: // NTSC_K
region = "KO";
break;
case 2: // PAL
switch (game.getCountry())
{
case 2: // German
region = "DE";
break;
case 3: // French
region = "FR";
break;
case 4: // Spanish
region = "ES";
break;
case 5: // Italian
region = "IT";
break;
case 6: // Dutch
region = "NL";
break;
case 1: // English
default:
region = "EN";
break;
}
break;
case 3: // Unknown
default:
region = "EN";
break;
}
return region;
}
public static void saveCover(Bitmap cover, String path)
{
try
{
FileOutputStream out = new FileOutputStream(path);
cover.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
}
catch (Exception e)
{
// Do nothing
}
}
public static void saveCover(Bitmap cover, String path)
{
try
{
FileOutputStream out = new FileOutputStream(path);
cover.compress(Bitmap.CompressFormat.PNG, 100, out);
out.close();
}
catch (Exception e)
{
// Do nothing
}
}
}

View File

@ -9,16 +9,20 @@ import org.dolphinemu.dolphinemu.services.DirectoryInitializationService.Directo
import rx.functions.Action1;
public class DirectoryStateReceiver extends BroadcastReceiver {
Action1<DirectoryInitializationState> callback;
public DirectoryStateReceiver(Action1<DirectoryInitializationState> callback) {
this.callback = callback;
}
public class DirectoryStateReceiver extends BroadcastReceiver
{
Action1<DirectoryInitializationState> callback;
@Override
public void onReceive(Context context, Intent intent)
{
DirectoryInitializationState state = (DirectoryInitializationState) intent.getSerializableExtra(DirectoryInitializationService.EXTRA_STATE);
callback.call(state);
}
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);
}
}

View File

@ -24,367 +24,366 @@ import javax.microedition.khronos.opengles.GL10;
*/
public final class EGLHelper
{
private final EGL10 mEGL;
private final EGLDisplay mDisplay;
private EGLConfig[] mEGLConfigs;
private EGLContext mEGLContext;
private EGLSurface mEGLSurface;
private GL10 mGL;
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;
// 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;
// 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
* <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);
/**
* 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();
// 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.");
}
}
// 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);
}
/**
* 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),
};
}
/**
* 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.
*
* @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 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;
}
/**
* 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 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 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 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 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 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;
}
/**
* 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;
}
// 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;
}
// 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;
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_ES2_BIT) != 0)
supportGLES2 = true;
if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0)
supportGLES3 = true;
}
}
if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0)
supportGLES3 = true;
}
}
return true;
}
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
};
// 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
};
// 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;
// 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_BIT:
ctx_attribs[0] = EGL10.EGL_NONE;
break;
case EGL_OPENGL_ES3_BIT_KHR:
ctx_attribs[1] = 3;
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);
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();
}
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 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);
}
/**
* 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);
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;
}
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;
}
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];
}
/**
* 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];
}
}

View File

@ -17,41 +17,43 @@ import java.util.List;
public final class FileBrowserHelper
{
public static void openDirectoryPicker(FragmentActivity activity)
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());
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())
{
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());
activity.startActivityForResult(i, MainPresenter.REQUEST_ADD_DIRECTORY);
File file = Utils.getFileForUri(files.get(0));
return file.getAbsolutePath();
}
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;
}
return null;
}
}

View File

@ -19,134 +19,143 @@ import org.dolphinemu.dolphinemu.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);
}
}
}
}
else
{
Log.warning("Cannot request GameCube Adapter permission as EmulationActivity is null.");
}
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.");
}
}
}
public static void Shutdown()
{
usb_con.close();
}
public static int GetFD() { return usb_con.getFileDescriptor(); }
public static void Shutdown()
{
usb_con.close();
}
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();
}
}
return false;
}
public static int GetFD()
{
return usb_con.getFileDescriptor();
}
public static void InitAdapter()
{
byte[] init = { 0x13 };
usb_con.bulkTransfer(usb_in, init, init.length, 0);
}
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();
}
}
return false;
}
public static int Input() {
return usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 16);
}
public static void InitAdapter()
{
byte[] init = {0x13};
usb_con.bulkTransfer(usb_in, init, init.length, 0);
}
public static int Output(byte[] rumble) {
return usb_con.bulkTransfer(usb_out, rumble, 5, 16);
}
public static int Input()
{
return usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 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);
public static int Output(byte[] rumble)
{
return usb_con.bulkTransfer(usb_out, rumble, 5, 16);
}
Log.info("GCAdapter: Number of configurations: " + dev.getConfigurationCount());
Log.info("GCAdapter: Number of interfaces: " + dev.getInterfaceCount());
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);
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 configurations: " + dev.getConfigurationCount());
Log.info("GCAdapter: Number of interfaces: " + dev.getInterfaceCount());
Log.info("GCAdapter: Number of endpoints: " + usb_intf.getEndpointCount());
if (dev.getConfigurationCount() > 0 && dev.getInterfaceCount() > 0)
{
UsbConfiguration conf = dev.getConfiguration(0);
usb_intf = conf.getInterface(0);
usb_con.claimInterface(usb_intf, true);
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);
Log.info("GCAdapter: Number of endpoints: " + usb_intf.getEndpointCount());
InitAdapter();
return true;
}
else
{
usb_con.releaseInterface(usb_intf);
}
}
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);
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;
}
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;
}
}

View File

@ -19,145 +19,148 @@ import java.util.Map;
public class Java_WiimoteAdapter
{
final static int MAX_PAYLOAD = 23;
final static int MAX_WIIMOTES = 4;
final static int TIMEOUT = 200;
final static short NINTENDO_VENDOR_ID = 0x057e;
final static short NINTENDO_WIIMOTE_PRODUCT_ID = 0x0306;
public static UsbManager manager;
final static int MAX_PAYLOAD = 23;
final static int MAX_WIIMOTES = 4;
final static int TIMEOUT = 200;
final static short NINTENDO_VENDOR_ID = 0x057e;
final static short NINTENDO_WIIMOTE_PRODUCT_ID = 0x0306;
public static UsbManager manager;
static UsbDeviceConnection usb_con;
static UsbInterface[] usb_intf = new UsbInterface[MAX_WIIMOTES];
static UsbEndpoint[] usb_in = new UsbEndpoint[MAX_WIIMOTES];
static UsbDeviceConnection usb_con;
static UsbInterface[] usb_intf = new UsbInterface[MAX_WIIMOTES];
static UsbEndpoint[] usb_in = new UsbEndpoint[MAX_WIIMOTES];
public static byte[][] wiimote_payload = new byte[MAX_WIIMOTES][MAX_PAYLOAD];
public static byte[][] wiimote_payload = new byte[MAX_WIIMOTES][MAX_PAYLOAD];
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() == NINTENDO_WIIMOTE_PRODUCT_ID && dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (!manager.hasPermission(dev))
{
Log.warning("Requesting permission for Wii Remote adapter");
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 Wiimote adapter permission as EmulationActivity is null.");
}
}
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() == NINTENDO_WIIMOTE_PRODUCT_ID &&
dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (!manager.hasPermission(dev))
{
Log.warning("Requesting permission for Wii Remote adapter");
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 Wiimote adapter permission as EmulationActivity is null.");
}
}
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() == NINTENDO_WIIMOTE_PRODUCT_ID && dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (manager.hasPermission(dev))
return true;
else
RequestPermission();
}
}
return false;
}
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() == NINTENDO_WIIMOTE_PRODUCT_ID &&
dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (manager.hasPermission(dev))
return true;
else
RequestPermission();
}
}
return false;
}
public static int Input(int index)
{
return usb_con.bulkTransfer(usb_in[index], wiimote_payload[index], MAX_PAYLOAD, TIMEOUT);
}
public static int Input(int index)
{
return usb_con.bulkTransfer(usb_in[index], wiimote_payload[index], MAX_PAYLOAD, TIMEOUT);
}
public static int Output(int index, byte[] buf, int size)
{
byte report_number = buf[0];
public static int Output(int index, byte[] buf, int size)
{
byte report_number = buf[0];
// Remove the report number from the buffer
buf = Arrays.copyOfRange(buf, 1, buf.length);
size--;
// Remove the report number from the buffer
buf = Arrays.copyOfRange(buf, 1, buf.length);
size--;
final int LIBUSB_REQUEST_TYPE_CLASS = (1 << 5);
final int LIBUSB_RECIPIENT_INTERFACE = 0x1;
final int LIBUSB_ENDPOINT_OUT = 0;
final int LIBUSB_REQUEST_TYPE_CLASS = (1 << 5);
final int LIBUSB_RECIPIENT_INTERFACE = 0x1;
final int LIBUSB_ENDPOINT_OUT = 0;
final int HID_SET_REPORT = 0x9;
final int HID_OUTPUT = (2 << 8);
final int HID_SET_REPORT = 0x9;
final int HID_OUTPUT = (2 << 8);
int write = usb_con.controlTransfer(
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
HID_SET_REPORT,
HID_OUTPUT | report_number,
index,
buf, size,
1000);
int write = usb_con.controlTransfer(
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
HID_SET_REPORT,
HID_OUTPUT | report_number,
index,
buf, size,
1000);
if (write < 0)
return 0;
if (write < 0)
return 0;
return write + 1;
}
return write + 1;
}
public static boolean OpenAdapter()
{
// If the adapter is already open. Don't attempt to do it again
if (usb_con != null && usb_con.getFileDescriptor() != -1)
return true;
public static boolean OpenAdapter()
{
// If the adapter is already open. Don't attempt to do it again
if (usb_con != null && usb_con.getFileDescriptor() != -1)
return true;
HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
{
UsbDevice dev = pair.getValue();
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID && dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (manager.hasPermission(dev))
{
usb_con = manager.openDevice(dev);
UsbConfiguration conf = dev.getConfiguration(0);
HashMap<String, UsbDevice> devices = manager.getDeviceList();
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
{
UsbDevice dev = pair.getValue();
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID &&
dev.getVendorId() == NINTENDO_VENDOR_ID)
{
if (manager.hasPermission(dev))
{
usb_con = manager.openDevice(dev);
UsbConfiguration conf = dev.getConfiguration(0);
Log.info("Number of configurations: " + dev.getConfigurationCount());
Log.info("Number of Interfaces: " + dev.getInterfaceCount());
Log.info("Number of Interfaces from conf: " + conf.getInterfaceCount());
Log.info("Number of configurations: " + dev.getConfigurationCount());
Log.info("Number of Interfaces: " + dev.getInterfaceCount());
Log.info("Number of Interfaces from conf: " + conf.getInterfaceCount());
// Sometimes the interface count is returned as zero.
// Means the device needs to be unplugged and plugged back in again
if (dev.getInterfaceCount() > 0)
{
for (int i = 0; i < MAX_WIIMOTES; ++i)
{
// One interface per Wii Remote
usb_intf[i] = dev.getInterface(i);
usb_con.claimInterface(usb_intf[i], true);
// Sometimes the interface count is returned as zero.
// Means the device needs to be unplugged and plugged back in again
if (dev.getInterfaceCount() > 0)
{
for (int i = 0; i < MAX_WIIMOTES; ++i)
{
// One interface per Wii Remote
usb_intf[i] = dev.getInterface(i);
usb_con.claimInterface(usb_intf[i], true);
// One endpoint per Wii Remote. Input only
// Output reports go through the control channel.
usb_in[i] = usb_intf[i].getEndpoint(0);
Log.info("Interface " + i + " endpoint count:" + usb_intf[i].getEndpointCount());
}
return true;
}
else
{
// XXX: Message that the device was found, but it needs to be unplugged and plugged back in?
usb_con.close();
}
}
}
}
return false;
}
// One endpoint per Wii Remote. Input only
// Output reports go through the control channel.
usb_in[i] = usb_intf[i].getEndpoint(0);
Log.info("Interface " + i + " endpoint count:" + usb_intf[i].getEndpointCount());
}
return true;
}
else
{
// XXX: Message that the device was found, but it needs to be unplugged and plugged back in?
usb_con.close();
}
}
}
}
return false;
}
}

View File

@ -9,45 +9,45 @@ import org.dolphinemu.dolphinemu.BuildConfig;
*/
public final class Log
{
private static final String TAG = "Dolphin";
private static final String TAG = "Dolphin";
private Log()
{
}
private Log()
{
}
public static void verbose(String message)
{
if (BuildConfig.DEBUG)
{
android.util.Log.v(TAG, message);
}
}
public static void verbose(String message)
{
if (BuildConfig.DEBUG)
{
android.util.Log.v(TAG, message);
}
}
public static void debug(String message)
{
if (BuildConfig.DEBUG)
{
android.util.Log.d(TAG, message);
}
}
public static void debug(String message)
{
if (BuildConfig.DEBUG)
{
android.util.Log.d(TAG, message);
}
}
public static void info(String message)
{
android.util.Log.i(TAG, message);
}
public static void info(String message)
{
android.util.Log.i(TAG, message);
}
public static void warning(String message)
{
android.util.Log.w(TAG, message);
}
public static void warning(String message)
{
android.util.Log.w(TAG, message);
}
public static void error(String message)
{
android.util.Log.e(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);
}
public static void wtf(String message)
{
android.util.Log.wtf(TAG, message);
}
}

View File

@ -14,49 +14,59 @@ import org.dolphinemu.dolphinemu.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);
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;
}
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;
}
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;
}
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;
}
return true;
}
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();
}
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();
}
}

View File

@ -12,98 +12,105 @@ import org.dolphinemu.dolphinemu.model.GameFile;
import java.io.File;
public class PicassoUtils {
public static void loadGameBanner(ImageView imageView, GameFile gameFile)
{
File cover = new File(gameFile.getCustomCoverPath());
if (cover.exists())
{
Picasso.with(imageView.getContext())
.load(cover)
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView);
}
else if ((cover = new File(gameFile.getCoverPath())).exists())
{
Picasso.with(imageView.getContext())
.load(cover)
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView);
}
/**
* GameTDB has a pretty close to complete collection for US/EN covers. First pass at getting
* the cover will be by the disk's region, second will be the US cover, and third EN.
*/
else
{
Picasso.with(imageView.getContext())
.load(CoverHelper.buildGameTDBUrl(gameFile, CoverHelper.getRegion(gameFile)))
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView, new Callback()
{
@Override
public void onSuccess()
{
CoverHelper.saveCover(((BitmapDrawable) imageView.getDrawable()).getBitmap(),
gameFile.getCoverPath());
}
@Override
public void onError() // Second pass using US region
{
Picasso.with(imageView.getContext())
.load(CoverHelper.buildGameTDBUrl(gameFile, "US"))
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView, new Callback()
{
@Override
public void onSuccess()
{
CoverHelper.saveCover(((BitmapDrawable) imageView.getDrawable()).getBitmap(),
gameFile.getCoverPath());
}
@Override
public void onError() // Third and last pass using EN region
{
Picasso.with(imageView.getContext())
.load(CoverHelper.buildGameTDBUrl(gameFile, "EN"))
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView, new Callback()
{
@Override
public void onSuccess()
{
CoverHelper.saveCover(((BitmapDrawable) imageView.getDrawable()).getBitmap(),
gameFile.getCoverPath());
}
@Override
public void onError()
{
}
});
}
});
}
});
}
}
public class PicassoUtils
{
public static void loadGameBanner(ImageView imageView, GameFile gameFile)
{
File cover = new File(gameFile.getCustomCoverPath());
if (cover.exists())
{
Picasso.with(imageView.getContext())
.load(cover)
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView);
}
else if ((cover = new File(gameFile.getCoverPath())).exists())
{
Picasso.with(imageView.getContext())
.load(cover)
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView);
}
/**
* GameTDB has a pretty close to complete collection for US/EN covers. First pass at getting
* the cover will be by the disk's region, second will be the US cover, and third EN.
*/
else
{
Picasso.with(imageView.getContext())
.load(CoverHelper.buildGameTDBUrl(gameFile, CoverHelper.getRegion(gameFile)))
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView, new Callback()
{
@Override
public void onSuccess()
{
CoverHelper.saveCover(((BitmapDrawable) imageView.getDrawable()).getBitmap(),
gameFile.getCoverPath());
}
@Override
public void onError() // Second pass using US region
{
Picasso.with(imageView.getContext())
.load(CoverHelper.buildGameTDBUrl(gameFile, "US"))
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView, new Callback()
{
@Override
public void onSuccess()
{
CoverHelper.saveCover(
((BitmapDrawable) imageView.getDrawable()).getBitmap(),
gameFile.getCoverPath());
}
@Override
public void onError() // Third and last pass using EN region
{
Picasso.with(imageView.getContext())
.load(CoverHelper.buildGameTDBUrl(gameFile, "EN"))
.fit()
.noFade()
.noPlaceholder()
.config(Bitmap.Config.ARGB_8888)
.error(R.drawable.no_banner)
.into(imageView, new Callback()
{
@Override
public void onSuccess()
{
CoverHelper.saveCover(
((BitmapDrawable) imageView.getDrawable())
.getBitmap(),
gameFile.getCoverPath());
}
@Override
public void onError()
{
}
});
}
});
}
});
}
}
}

View File

@ -14,61 +14,61 @@ import java.util.Date;
public final class StartupHandler
{
public static final String NEW_SESSION = "NEW_SESSION";
public static final String LAST_CLOSED = "LAST_CLOSED";
public static final Long SESSION_TIMEOUT = 21600000L; // 6 hours in milliseconds
public static final String NEW_SESSION = "NEW_SESSION";
public static final String LAST_CLOSED = "LAST_CLOSED";
public static final Long SESSION_TIMEOUT = 21600000L; // 6 hours in milliseconds
public static void HandleInit(FragmentActivity parent)
{
// Ask the user to grant write permission if it's not already granted
PermissionsHandler.checkWritePermission(parent);
public static void HandleInit(FragmentActivity parent)
{
// Ask the user to grant write permission if it's not already granted
PermissionsHandler.checkWritePermission(parent);
// Ask the user if he wants to enable analytics if we haven't yet.
Analytics.checkAnalyticsInit(parent);
// Ask the user if he wants to enable analytics if we haven't yet.
Analytics.checkAnalyticsInit(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();
}
}
/**
* There isn't a good way to determine a new session. setSessionTime is called if the main
* activity goes into the background.
*/
public static void setSessionTime(Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putLong(LAST_CLOSED, new Date(System.currentTimeMillis()).getTime());
sPrefsEditor.apply();
}
/**
* There isn't a good way to determine a new session. setSessionTime is called if the main
* activity goes into the background.
*/
public static void setSessionTime(Context context)
{
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putLong(LAST_CLOSED, new Date(System.currentTimeMillis()).getTime());
sPrefsEditor.apply();
}
/**
* Called to determine if we treat this activity start as a new session.
*/
public static void checkSessionReset(Context context)
{
Long currentTime = new Date(System.currentTimeMillis()).getTime();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Long lastOpen = preferences.getLong(LAST_CLOSED, 0);
if (currentTime > (lastOpen + SESSION_TIMEOUT))
{
// Passed at emulation start to trigger first open event.
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putBoolean(NEW_SESSION, true);
sPrefsEditor.apply();
}
}
/**
* Called to determine if we treat this activity start as a new session.
*/
public static void checkSessionReset(Context context)
{
Long currentTime = new Date(System.currentTimeMillis()).getTime();
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
Long lastOpen = preferences.getLong(LAST_CLOSED, 0);
if (currentTime > (lastOpen + SESSION_TIMEOUT))
{
// Passed at emulation start to trigger first open event.
SharedPreferences.Editor sPrefsEditor = preferences.edit();
sPrefsEditor.putBoolean(NEW_SESSION, true);
sPrefsEditor.apply();
}
}
}

View File

@ -17,7 +17,6 @@ import android.graphics.drawable.VectorDrawable;
import android.media.tv.TvContract;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.PersistableBundle;
import android.support.annotation.AnyRes;
import android.support.annotation.NonNull;
@ -25,7 +24,6 @@ import android.support.media.tv.Channel;
import android.support.media.tv.TvContractCompat;
import android.util.Log;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.model.GameFile;
import org.dolphinemu.dolphinemu.model.HomeScreenChannel;
import org.dolphinemu.dolphinemu.services.SyncChannelJobService;
@ -33,7 +31,6 @@ import org.dolphinemu.dolphinemu.services.SyncProgramsJobService;
import org.dolphinemu.dolphinemu.ui.platform.Platform;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;
@ -45,232 +42,234 @@ import static android.support.v4.content.FileProvider.getUriForFile;
*/
public class TvUtil
{
private static final String TAG = "TvUtil";
private static final long CHANNEL_JOB_ID_OFFSET = 1000;
private static final String TAG = "TvUtil";
private static final long CHANNEL_JOB_ID_OFFSET = 1000;
private static final String[] CHANNELS_PROJECTION = {
TvContractCompat.Channels._ID,
TvContract.Channels.COLUMN_DISPLAY_NAME,
TvContractCompat.Channels.COLUMN_BROWSABLE
};
private static final String LEANBACK_PACKAGE = "com.google.android.tvlauncher";
private static final String[] CHANNELS_PROJECTION = {
TvContractCompat.Channels._ID,
TvContract.Channels.COLUMN_DISPLAY_NAME,
TvContractCompat.Channels.COLUMN_BROWSABLE
};
private static final String LEANBACK_PACKAGE = "com.google.android.tvlauncher";
public static int getNumberOfChannels(Context context)
{
Cursor cursor =
context.getContentResolver()
.query(
TvContractCompat.Channels.CONTENT_URI,
CHANNELS_PROJECTION,
null,
null,
null);
return cursor != null ? cursor.getCount() : 0;
}
public static int getNumberOfChannels(Context context)
{
Cursor cursor =
context.getContentResolver()
.query(
TvContractCompat.Channels.CONTENT_URI,
CHANNELS_PROJECTION,
null,
null,
null);
return cursor != null ? cursor.getCount() : 0;
}
public static List<Channel> getAllChannels(Context context)
{
List<Channel> channels = new ArrayList<>();
Cursor cursor =
context.getContentResolver()
.query(
TvContractCompat.Channels.CONTENT_URI,
CHANNELS_PROJECTION,
null,
null,
null);
if (cursor != null && cursor.moveToFirst())
{
do
{
channels.add(Channel.fromCursor(cursor));
} while (cursor.moveToNext());
}
return channels;
}
public static List<Channel> getAllChannels(Context context)
{
List<Channel> channels = new ArrayList<>();
Cursor cursor =
context.getContentResolver()
.query(
TvContractCompat.Channels.CONTENT_URI,
CHANNELS_PROJECTION,
null,
null,
null);
if (cursor != null && cursor.moveToFirst())
{
do
{
channels.add(Channel.fromCursor(cursor));
}
while (cursor.moveToNext());
}
return channels;
}
public static Channel getChannelById(Context context, long channelId)
{
for (Channel channel : getAllChannels(context))
{
if (channel.getId() == channelId)
{
return channel;
}
}
return null;
}
public static Channel getChannelById(Context context, long channelId)
{
for (Channel channel : getAllChannels(context))
{
if (channel.getId() == channelId)
{
return channel;
}
}
return null;
}
/**
* Updates all Leanback homescreen channels
*/
public static void updateAllChannels(Context context)
{
if (Build.VERSION.SDK_INT < 26)
return;
for (Channel channel : getAllChannels(context))
{
context.getContentResolver()
.update(
TvContractCompat.buildChannelUri(channel.getId()),
channel.toContentValues(),
null,
null);
}
}
/**
* Updates all Leanback homescreen channels
*/
public static void updateAllChannels(Context context)
{
if (Build.VERSION.SDK_INT < 26)
return;
for (Channel channel : getAllChannels(context))
{
context.getContentResolver()
.update(
TvContractCompat.buildChannelUri(channel.getId()),
channel.toContentValues(),
null,
null);
}
}
public static Uri getUriToResource(Context context, @AnyRes int resId)
throws Resources.NotFoundException
{
Resources res = context.getResources();
Uri resUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
"://" + res.getResourcePackageName(resId)
+ '/' + res.getResourceTypeName(resId)
+ '/' + res.getResourceEntryName(resId));
return resUri;
}
public static Uri getUriToResource(Context context, @AnyRes int resId)
throws Resources.NotFoundException
{
Resources res = context.getResources();
Uri resUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
"://" + res.getResourcePackageName(resId)
+ '/' + res.getResourceTypeName(resId)
+ '/' + res.getResourceEntryName(resId));
return resUri;
}
/**
* Converts a resource into a {@link Bitmap}. If the resource is a vector drawable, it will be
* drawn into a new Bitmap. Otherwise the {@link BitmapFactory} will decode the resource.
*/
@NonNull
public static Bitmap convertToBitmap(Context context, int resourceId)
{
Drawable drawable = context.getDrawable(resourceId);
if (drawable instanceof VectorDrawable)
{
Bitmap bitmap =
Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
return BitmapFactory.decodeResource(context.getResources(), resourceId);
}
/**
* Converts a resource into a {@link Bitmap}. If the resource is a vector drawable, it will be
* drawn into a new Bitmap. Otherwise the {@link BitmapFactory} will decode the resource.
*/
@NonNull
public static Bitmap convertToBitmap(Context context, int resourceId)
{
Drawable drawable = context.getDrawable(resourceId);
if (drawable instanceof VectorDrawable)
{
Bitmap bitmap =
Bitmap.createBitmap(
drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
}
return BitmapFactory.decodeResource(context.getResources(), resourceId);
}
/**
* Leanback lanucher requires a uri for poster art so we create a contentUri and
* pass that to LEANBACK_PACKAGE
*/
public static Uri buildBanner(GameFile game, Context context)
{
Uri contentUri = null;
/**
* Leanback lanucher requires a uri for poster art so we create a contentUri and
* pass that to LEANBACK_PACKAGE
*/
public static Uri buildBanner(GameFile game, Context context)
{
Uri contentUri = null;
try
{
File cover = new File(game.getCustomCoverPath());
if(cover.exists())
{
contentUri = getUriForFile(context, getFileProvider(context), cover);
}
else if ((cover = new File(game.getCoverPath())).exists())
{
contentUri = getUriForFile(context, getFileProvider(context), cover);
}
context.grantUriPermission(LEANBACK_PACKAGE, contentUri,
FLAG_GRANT_READ_URI_PERMISSION);
}
catch (Exception e)
{
Log.e(TAG, "Failed to create banner");
Log.e(TAG, e.getMessage());
}
try
{
File cover = new File(game.getCustomCoverPath());
if (cover.exists())
{
contentUri = getUriForFile(context, getFileProvider(context), cover);
}
else if ((cover = new File(game.getCoverPath())).exists())
{
contentUri = getUriForFile(context, getFileProvider(context), cover);
}
context.grantUriPermission(LEANBACK_PACKAGE, contentUri,
FLAG_GRANT_READ_URI_PERMISSION);
}
catch (Exception e)
{
Log.e(TAG, "Failed to create banner");
Log.e(TAG, e.getMessage());
}
return contentUri;
}
return contentUri;
}
/**
* Needed since debug builds append '.debug' to the end of the package
*/
private static String getFileProvider(Context context)
{
return context.getPackageName() + ".filesprovider";
}
/**
* Needed since debug builds append '.debug' to the end of the package
*/
private static String getFileProvider(Context context)
{
return context.getPackageName() + ".filesprovider";
}
/**
* Schedules syncing channels via a {@link JobScheduler}.
*
* @param context for accessing the {@link JobScheduler}.
*/
public static void scheduleSyncingChannel(Context context)
{
ComponentName componentName = new ComponentName(context, SyncChannelJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(1, componentName);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
/**
* Schedules syncing channels via a {@link JobScheduler}.
*
* @param context for accessing the {@link JobScheduler}.
*/
public static void scheduleSyncingChannel(Context context)
{
ComponentName componentName = new ComponentName(context, SyncChannelJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(1, componentName);
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
JobScheduler scheduler =
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobScheduler scheduler =
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
Log.d(TAG, "Scheduled channel creation.");
scheduler.schedule(builder.build());
}
Log.d(TAG, "Scheduled channel creation.");
scheduler.schedule(builder.build());
}
/**
* Schedulers syncing programs for a channel. The scheduler will listen to a {@link Uri} for a
* particular channel.
*
* @param context for accessing the {@link JobScheduler}.
* @param channelId for the channel to listen for changes.
*/
@TargetApi(Build.VERSION_CODES.O)
public static void scheduleSyncingProgramsForChannel(Context context, long channelId)
{
Log.d(TAG, "ProgramsRefresh job");
ComponentName componentName = new ComponentName(context, SyncProgramsJobService.class);
JobInfo.Builder builder =
new JobInfo.Builder(getJobIdForChannelId(channelId), componentName);
JobInfo.TriggerContentUri triggerContentUri =
new JobInfo.TriggerContentUri(
TvContractCompat.buildChannelUri(channelId),
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS);
builder.addTriggerContentUri(triggerContentUri);
builder.setTriggerContentMaxDelay(0L);
builder.setTriggerContentUpdateDelay(0L);
/**
* Schedulers syncing programs for a channel. The scheduler will listen to a {@link Uri} for a
* particular channel.
*
* @param context for accessing the {@link JobScheduler}.
* @param channelId for the channel to listen for changes.
*/
@TargetApi(Build.VERSION_CODES.O)
public static void scheduleSyncingProgramsForChannel(Context context, long channelId)
{
Log.d(TAG, "ProgramsRefresh job");
ComponentName componentName = new ComponentName(context, SyncProgramsJobService.class);
JobInfo.Builder builder =
new JobInfo.Builder(getJobIdForChannelId(channelId), componentName);
JobInfo.TriggerContentUri triggerContentUri =
new JobInfo.TriggerContentUri(
TvContractCompat.buildChannelUri(channelId),
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS);
builder.addTriggerContentUri(triggerContentUri);
builder.setTriggerContentMaxDelay(0L);
builder.setTriggerContentUpdateDelay(0L);
PersistableBundle bundle = new PersistableBundle();
bundle.putLong(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
builder.setExtras(bundle);
PersistableBundle bundle = new PersistableBundle();
bundle.putLong(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
builder.setExtras(bundle);
JobScheduler scheduler =
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.cancel(getJobIdForChannelId(channelId));
scheduler.schedule(builder.build());
}
JobScheduler scheduler =
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
scheduler.cancel(getJobIdForChannelId(channelId));
scheduler.schedule(builder.build());
}
private static int getJobIdForChannelId(long channelId)
{
return (int) (CHANNEL_JOB_ID_OFFSET + channelId);
}
private static int getJobIdForChannelId(long channelId)
{
return (int) (CHANNEL_JOB_ID_OFFSET + channelId);
}
/**
* Generates all subscriptions for homescreen channels.
*/
public static List<HomeScreenChannel> createUniversalSubscriptions()
{
//Leaving the subs local variable in case more channels are created other than platforms.
List<HomeScreenChannel> subs = new ArrayList<>(createPlatformSubscriptions());
return subs;
}
/**
* Generates all subscriptions for homescreen channels.
*/
public static List<HomeScreenChannel> createUniversalSubscriptions()
{
//Leaving the subs local variable in case more channels are created other than platforms.
List<HomeScreenChannel> subs = new ArrayList<>(createPlatformSubscriptions());
return subs;
}
private static List<HomeScreenChannel> createPlatformSubscriptions()
{
List<HomeScreenChannel> subs = new ArrayList<>();
for (Platform platform : Platform.values())
{
subs.add(new HomeScreenChannel(
platform.getHeaderName(),
platform.getHeaderName(),
AppLinkHelper.buildBrowseUri(platform.getHeaderName()).toString()));
}
return subs;
}
public static Boolean isLeanback(Context context)
{
return(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK));
}
private static List<HomeScreenChannel> createPlatformSubscriptions()
{
List<HomeScreenChannel> subs = new ArrayList<>();
for (Platform platform : Platform.values())
{
subs.add(new HomeScreenChannel(
platform.getHeaderName(),
platform.getHeaderName(),
AppLinkHelper.buildBrowseUri(platform.getHeaderName()).toString()));
}
return subs;
}
public static Boolean isLeanback(Context context)
{
return (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK));
}
}

View File

@ -7,16 +7,16 @@ import com.android.volley.toolbox.Volley;
public class VolleyUtil
{
private static RequestQueue queue;
private static RequestQueue queue;
public static void init(Context context)
{
if (queue == null)
queue = Volley.newRequestQueue(context);
}
public static void init(Context context)
{
if (queue == null)
queue = Volley.newRequestQueue(context);
}
public static RequestQueue getQueue()
{
return queue;
}
public static RequestQueue getQueue()
{
return queue;
}
}

View File

@ -13,18 +13,18 @@ import org.dolphinemu.dolphinemu.R;
*/
public class FileViewHolder extends RecyclerView.ViewHolder
{
public View itemView;
public View itemView;
public TextView textFileName;
public ImageView imageType;
public TextView textFileName;
public ImageView imageType;
public FileViewHolder(View itemView)
{
super(itemView);
public FileViewHolder(View itemView)
{
super(itemView);
this.itemView = itemView;
this.itemView = itemView;
textFileName = (TextView) itemView.findViewById(R.id.text_file_name);
imageType = (ImageView) itemView.findViewById(R.id.image_type);
}
textFileName = (TextView) itemView.findViewById(R.id.text_file_name);
imageType = (ImageView) itemView.findViewById(R.id.image_type);
}
}

View File

@ -14,20 +14,20 @@ import org.dolphinemu.dolphinemu.model.GameFile;
*/
public class GameViewHolder extends RecyclerView.ViewHolder
{
public ImageView imageScreenshot;
public TextView textGameTitle;
public TextView textCompany;
public ImageView imageScreenshot;
public TextView textGameTitle;
public TextView textCompany;
public GameFile gameFile;
public GameFile gameFile;
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);
}
}

View File

@ -13,19 +13,19 @@ import org.dolphinemu.dolphinemu.model.GameFile;
*/
public final class TvGameViewHolder extends Presenter.ViewHolder
{
public ImageCardView cardParent;
public ImageCardView cardParent;
public ImageView imageScreenshot;
public ImageView imageScreenshot;
public GameFile gameFile;
public GameFile gameFile;
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();
}
}

View File

@ -6,17 +6,17 @@ import android.view.View;
public final class TvSettingsViewHolder extends Presenter.ViewHolder
{
public ImageCardView cardParent;
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;
}
}

View File

@ -3,19 +3,19 @@
<!-- This animation is used ONLY when a submenu is replaced. -->
<objectAnimator
android:propertyName="translationX"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="-1280dp"
android:interpolator="@android:interpolator/decelerate_quad"
android:duration="200"/>
android:propertyName="translationX"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="-1280dp"
android:interpolator="@android:interpolator/decelerate_quad"
android:duration="200"/>
<objectAnimator
android:propertyName="alpha"
android:valueType="floatType"
android:valueFrom="1"
android:valueTo="0"
android:interpolator="@android:interpolator/decelerate_quad"
android:duration="200"/>
android:propertyName="alpha"
android:valueType="floatType"
android:valueFrom="1"
android:valueTo="0"
android:interpolator="@android:interpolator/decelerate_quad"
android:duration="200"/>
</set>

View File

@ -3,19 +3,19 @@
<!-- This animation is used ONLY when a submenu is replaced. -->
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="translationX"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="1280dp"
android:interpolator="@android:interpolator/decelerate_quad"
android:duration="200"/>
android:propertyName="translationX"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="1280dp"
android:interpolator="@android:interpolator/decelerate_quad"
android:duration="200"/>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="alpha"
android:valueType="floatType"
android:valueFrom="1"
android:valueTo="0"
android:interpolator="@android:interpolator/decelerate_quad"
android:duration="200"/>
android:propertyName="alpha"
android:valueType="floatType"
android:valueFrom="1"
android:valueTo="0"
android:interpolator="@android:interpolator/decelerate_quad"
android:duration="200"/>
</set>

View File

@ -2,7 +2,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="true"
android:drawable="@color/dolphin_accent_gamecube" />
android:drawable="@color/dolphin_accent_gamecube"/>
<item
android:drawable="@color/tv_card_unselected" />
android:drawable="@color/tv_card_unselected"/>
</selector>

View File

@ -2,7 +2,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="true"
android:drawable="@color/dolphin_accent_wii" />
android:drawable="@color/dolphin_accent_wii"/>
<item
android:drawable="@color/tv_card_unselected" />
android:drawable="@color/tv_card_unselected"/>
</selector>

View File

@ -2,7 +2,7 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="true"
android:drawable="@color/dolphin_accent_wiiware" />
android:drawable="@color/dolphin_accent_wiiware"/>
<item
android:drawable="@color/tv_card_unselected" />
android:drawable="@color/tv_card_unselected"/>
</selector>

View File

@ -1,7 +1,7 @@
<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/surface_emulation"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:focusable="false"
android:focusableInTouchMode="false"
android:id="@+id/surface_emulation"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:focusable="false"
android:focusableInTouchMode="false"
/>

View File

@ -1,11 +1,11 @@
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/grid_state_slots"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnCount="3"
android:rowCount="2"
android:layout_gravity="center"
android:background="#af000000">
android:id="@+id/grid_state_slots"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnCount="3"
android:rowCount="2"
android:layout_gravity="center"
android:background="#af000000">
<Button
android:id="@+id/loadsave_state_button_1"

Some files were not shown because too many files have changed in this diff Show More