Reformat Android code
This commit is contained in:
parent
ab76631a7f
commit
248ee12aed
|
@ -67,7 +67,8 @@ android {
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
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"
|
abiFilters "arm64-v8a", "x86_64" //, "armeabi-v7a", "x86"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
android:name="android.software.leanback"
|
android:name="android.software.leanback"
|
||||||
android:required="false"/>
|
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.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<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.READ_EPG_DATA"/>
|
||||||
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
|
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".DolphinApplication"
|
android:name=".DolphinApplication"
|
||||||
|
@ -27,7 +27,9 @@
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:isGame="true"
|
android:isGame="true"
|
||||||
android:banner="@drawable/banner_tv">
|
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
|
<activity
|
||||||
android:name=".ui.main.MainActivity"
|
android:name=".ui.main.MainActivity"
|
||||||
|
@ -67,18 +69,18 @@
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/FilePickerTheme">
|
android:theme="@style/FilePickerTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.GET_CONTENT" />
|
<action android:name="android.intent.action.GET_CONTENT"/>
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".activities.AppLinkActivity" >
|
<activity android:name=".activities.AppLinkActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
<data
|
<data
|
||||||
android:host="@string/host"
|
android:host="@string/host"
|
||||||
android:scheme="@string/scheme" />
|
android:scheme="@string/scheme"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
@ -87,11 +89,11 @@
|
||||||
<service
|
<service
|
||||||
android:name=".services.SyncChannelJobService"
|
android:name=".services.SyncChannelJobService"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
android:permission="android.permission.BIND_JOB_SERVICE"/>
|
||||||
<service
|
<service
|
||||||
android:name=".services.SyncProgramsJobService"
|
android:name=".services.SyncProgramsJobService"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
android:permission="android.permission.BIND_JOB_SERVICE" />
|
android:permission="android.permission.BIND_JOB_SERVICE"/>
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="android.support.v4.content.FileProvider"
|
android:name="android.support.v4.content.FileProvider"
|
||||||
|
@ -100,7 +102,7 @@
|
||||||
android:grantUriPermissions="true">
|
android:grantUriPermissions="true">
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
android:resource="@xml/nnf_provider_paths" />
|
android:resource="@xml/nnf_provider_paths"/>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
|
@ -8,15 +8,15 @@ import org.dolphinemu.dolphinemu.utils.VolleyUtil;
|
||||||
|
|
||||||
public class DolphinApplication extends Application
|
public class DolphinApplication extends Application
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void onCreate()
|
public void onCreate()
|
||||||
{
|
{
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
VolleyUtil.init(getApplicationContext());
|
VolleyUtil.init(getApplicationContext());
|
||||||
System.loadLibrary("main");
|
System.loadLibrary("main");
|
||||||
|
|
||||||
if (PermissionsHandler.hasWriteAccess(getApplicationContext()))
|
if (PermissionsHandler.hasWriteAccess(getApplicationContext()))
|
||||||
DirectoryInitializationService.startService(getApplicationContext());
|
DirectoryInitializationService.startService(getApplicationContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,7 @@
|
||||||
package org.dolphinemu.dolphinemu;
|
package org.dolphinemu.dolphinemu;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
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.view.Surface;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
import org.dolphinemu.dolphinemu.utils.Log;
|
import org.dolphinemu.dolphinemu.utils.Log;
|
||||||
|
@ -26,433 +20,448 @@ import java.lang.ref.WeakReference;
|
||||||
*/
|
*/
|
||||||
public final class NativeLibrary
|
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
|
* Button type for use in onTouchEvent
|
||||||
*/
|
*/
|
||||||
public static final class ButtonType
|
public static final class ButtonType
|
||||||
{
|
{
|
||||||
public static final int BUTTON_A = 0;
|
public static final int BUTTON_A = 0;
|
||||||
public static final int BUTTON_B = 1;
|
public static final int BUTTON_B = 1;
|
||||||
public static final int BUTTON_START = 2;
|
public static final int BUTTON_START = 2;
|
||||||
public static final int BUTTON_X = 3;
|
public static final int BUTTON_X = 3;
|
||||||
public static final int BUTTON_Y = 4;
|
public static final int BUTTON_Y = 4;
|
||||||
public static final int BUTTON_Z = 5;
|
public static final int BUTTON_Z = 5;
|
||||||
public static final int BUTTON_UP = 6;
|
public static final int BUTTON_UP = 6;
|
||||||
public static final int BUTTON_DOWN = 7;
|
public static final int BUTTON_DOWN = 7;
|
||||||
public static final int BUTTON_LEFT = 8;
|
public static final int BUTTON_LEFT = 8;
|
||||||
public static final int BUTTON_RIGHT = 9;
|
public static final int BUTTON_RIGHT = 9;
|
||||||
public static final int STICK_MAIN = 10;
|
public static final int STICK_MAIN = 10;
|
||||||
public static final int STICK_MAIN_UP = 11;
|
public static final int STICK_MAIN_UP = 11;
|
||||||
public static final int STICK_MAIN_DOWN = 12;
|
public static final int STICK_MAIN_DOWN = 12;
|
||||||
public static final int STICK_MAIN_LEFT = 13;
|
public static final int STICK_MAIN_LEFT = 13;
|
||||||
public static final int STICK_MAIN_RIGHT = 14;
|
public static final int STICK_MAIN_RIGHT = 14;
|
||||||
public static final int STICK_C = 15;
|
public static final int STICK_C = 15;
|
||||||
public static final int STICK_C_UP = 16;
|
public static final int STICK_C_UP = 16;
|
||||||
public static final int STICK_C_DOWN = 17;
|
public static final int STICK_C_DOWN = 17;
|
||||||
public static final int STICK_C_LEFT = 18;
|
public static final int STICK_C_LEFT = 18;
|
||||||
public static final int STICK_C_RIGHT = 19;
|
public static final int STICK_C_RIGHT = 19;
|
||||||
public static final int TRIGGER_L = 20;
|
public static final int TRIGGER_L = 20;
|
||||||
public static final int TRIGGER_R = 21;
|
public static final int TRIGGER_R = 21;
|
||||||
public static final int WIIMOTE_BUTTON_A = 100;
|
public static final int WIIMOTE_BUTTON_A = 100;
|
||||||
public static final int WIIMOTE_BUTTON_B = 101;
|
public static final int WIIMOTE_BUTTON_B = 101;
|
||||||
public static final int WIIMOTE_BUTTON_MINUS = 102;
|
public static final int WIIMOTE_BUTTON_MINUS = 102;
|
||||||
public static final int WIIMOTE_BUTTON_PLUS = 103;
|
public static final int WIIMOTE_BUTTON_PLUS = 103;
|
||||||
public static final int WIIMOTE_BUTTON_HOME = 104;
|
public static final int WIIMOTE_BUTTON_HOME = 104;
|
||||||
public static final int WIIMOTE_BUTTON_1 = 105;
|
public static final int WIIMOTE_BUTTON_1 = 105;
|
||||||
public static final int WIIMOTE_BUTTON_2 = 106;
|
public static final int WIIMOTE_BUTTON_2 = 106;
|
||||||
public static final int WIIMOTE_UP = 107;
|
public static final int WIIMOTE_UP = 107;
|
||||||
public static final int WIIMOTE_DOWN = 108;
|
public static final int WIIMOTE_DOWN = 108;
|
||||||
public static final int WIIMOTE_LEFT = 109;
|
public static final int WIIMOTE_LEFT = 109;
|
||||||
public static final int WIIMOTE_RIGHT = 110;
|
public static final int WIIMOTE_RIGHT = 110;
|
||||||
public static final int WIIMOTE_IR = 111;
|
public static final int WIIMOTE_IR = 111;
|
||||||
public static final int WIIMOTE_IR_UP = 112;
|
public static final int WIIMOTE_IR_UP = 112;
|
||||||
public static final int WIIMOTE_IR_DOWN = 113;
|
public static final int WIIMOTE_IR_DOWN = 113;
|
||||||
public static final int WIIMOTE_IR_LEFT = 114;
|
public static final int WIIMOTE_IR_LEFT = 114;
|
||||||
public static final int WIIMOTE_IR_RIGHT = 115;
|
public static final int WIIMOTE_IR_RIGHT = 115;
|
||||||
public static final int WIIMOTE_IR_FORWARD = 116;
|
public static final int WIIMOTE_IR_FORWARD = 116;
|
||||||
public static final int WIIMOTE_IR_BACKWARD = 117;
|
public static final int WIIMOTE_IR_BACKWARD = 117;
|
||||||
public static final int WIIMOTE_IR_HIDE = 118;
|
public static final int WIIMOTE_IR_HIDE = 118;
|
||||||
public static final int WIIMOTE_SWING = 119;
|
public static final int WIIMOTE_SWING = 119;
|
||||||
public static final int WIIMOTE_SWING_UP = 120;
|
public static final int WIIMOTE_SWING_UP = 120;
|
||||||
public static final int WIIMOTE_SWING_DOWN = 121;
|
public static final int WIIMOTE_SWING_DOWN = 121;
|
||||||
public static final int WIIMOTE_SWING_LEFT = 122;
|
public static final int WIIMOTE_SWING_LEFT = 122;
|
||||||
public static final int WIIMOTE_SWING_RIGHT = 123;
|
public static final int WIIMOTE_SWING_RIGHT = 123;
|
||||||
public static final int WIIMOTE_SWING_FORWARD = 124;
|
public static final int WIIMOTE_SWING_FORWARD = 124;
|
||||||
public static final int WIIMOTE_SWING_BACKWARD = 125;
|
public static final int WIIMOTE_SWING_BACKWARD = 125;
|
||||||
public static final int WIIMOTE_TILT = 126;
|
public static final int WIIMOTE_TILT = 126;
|
||||||
public static final int WIIMOTE_TILT_FORWARD = 127;
|
public static final int WIIMOTE_TILT_FORWARD = 127;
|
||||||
public static final int WIIMOTE_TILT_BACKWARD = 128;
|
public static final int WIIMOTE_TILT_BACKWARD = 128;
|
||||||
public static final int WIIMOTE_TILT_LEFT = 129;
|
public static final int WIIMOTE_TILT_LEFT = 129;
|
||||||
public static final int WIIMOTE_TILT_RIGHT = 130;
|
public static final int WIIMOTE_TILT_RIGHT = 130;
|
||||||
public static final int WIIMOTE_TILT_MODIFIER = 131;
|
public static final int WIIMOTE_TILT_MODIFIER = 131;
|
||||||
public static final int WIIMOTE_SHAKE_X = 132;
|
public static final int WIIMOTE_SHAKE_X = 132;
|
||||||
public static final int WIIMOTE_SHAKE_Y = 133;
|
public static final int WIIMOTE_SHAKE_Y = 133;
|
||||||
public static final int WIIMOTE_SHAKE_Z = 134;
|
public static final int WIIMOTE_SHAKE_Z = 134;
|
||||||
public static final int NUNCHUK_BUTTON_C = 200;
|
public static final int NUNCHUK_BUTTON_C = 200;
|
||||||
public static final int NUNCHUK_BUTTON_Z = 201;
|
public static final int NUNCHUK_BUTTON_Z = 201;
|
||||||
public static final int NUNCHUK_STICK = 202;
|
public static final int NUNCHUK_STICK = 202;
|
||||||
public static final int NUNCHUK_STICK_UP = 203;
|
public static final int NUNCHUK_STICK_UP = 203;
|
||||||
public static final int NUNCHUK_STICK_DOWN = 204;
|
public static final int NUNCHUK_STICK_DOWN = 204;
|
||||||
public static final int NUNCHUK_STICK_LEFT = 205;
|
public static final int NUNCHUK_STICK_LEFT = 205;
|
||||||
public static final int NUNCHUK_STICK_RIGHT = 206;
|
public static final int NUNCHUK_STICK_RIGHT = 206;
|
||||||
public static final int NUNCHUK_SWING = 207;
|
public static final int NUNCHUK_SWING = 207;
|
||||||
public static final int NUNCHUK_SWING_UP = 208;
|
public static final int NUNCHUK_SWING_UP = 208;
|
||||||
public static final int NUNCHUK_SWING_DOWN = 209;
|
public static final int NUNCHUK_SWING_DOWN = 209;
|
||||||
public static final int NUNCHUK_SWING_LEFT = 210;
|
public static final int NUNCHUK_SWING_LEFT = 210;
|
||||||
public static final int NUNCHUK_SWING_RIGHT = 221;
|
public static final int NUNCHUK_SWING_RIGHT = 221;
|
||||||
public static final int NUNCHUK_SWING_FORWARD = 212;
|
public static final int NUNCHUK_SWING_FORWARD = 212;
|
||||||
public static final int NUNCHUK_SWING_BACKWARD = 213;
|
public static final int NUNCHUK_SWING_BACKWARD = 213;
|
||||||
public static final int NUNCHUK_TILT = 214;
|
public static final int NUNCHUK_TILT = 214;
|
||||||
public static final int NUNCHUK_TILT_FORWARD = 215;
|
public static final int NUNCHUK_TILT_FORWARD = 215;
|
||||||
public static final int NUNCHUK_TILT_BACKWARD = 216;
|
public static final int NUNCHUK_TILT_BACKWARD = 216;
|
||||||
public static final int NUNCHUK_TILT_LEFT = 217;
|
public static final int NUNCHUK_TILT_LEFT = 217;
|
||||||
public static final int NUNCHUK_TILT_RIGHT = 218;
|
public static final int NUNCHUK_TILT_RIGHT = 218;
|
||||||
public static final int NUNCHUK_TILT_MODIFIER = 219;
|
public static final int NUNCHUK_TILT_MODIFIER = 219;
|
||||||
public static final int NUNCHUK_SHAKE_X = 220;
|
public static final int NUNCHUK_SHAKE_X = 220;
|
||||||
public static final int NUNCHUK_SHAKE_Y = 221;
|
public static final int NUNCHUK_SHAKE_Y = 221;
|
||||||
public static final int NUNCHUK_SHAKE_Z = 222;
|
public static final int NUNCHUK_SHAKE_Z = 222;
|
||||||
public static final int CLASSIC_BUTTON_A = 300;
|
public static final int CLASSIC_BUTTON_A = 300;
|
||||||
public static final int CLASSIC_BUTTON_B = 301;
|
public static final int CLASSIC_BUTTON_B = 301;
|
||||||
public static final int CLASSIC_BUTTON_X = 302;
|
public static final int CLASSIC_BUTTON_X = 302;
|
||||||
public static final int CLASSIC_BUTTON_Y = 303;
|
public static final int CLASSIC_BUTTON_Y = 303;
|
||||||
public static final int CLASSIC_BUTTON_MINUS = 304;
|
public static final int CLASSIC_BUTTON_MINUS = 304;
|
||||||
public static final int CLASSIC_BUTTON_PLUS = 305;
|
public static final int CLASSIC_BUTTON_PLUS = 305;
|
||||||
public static final int CLASSIC_BUTTON_HOME = 306;
|
public static final int CLASSIC_BUTTON_HOME = 306;
|
||||||
public static final int CLASSIC_BUTTON_ZL = 307;
|
public static final int CLASSIC_BUTTON_ZL = 307;
|
||||||
public static final int CLASSIC_BUTTON_ZR = 308;
|
public static final int CLASSIC_BUTTON_ZR = 308;
|
||||||
public static final int CLASSIC_DPAD_UP = 309;
|
public static final int CLASSIC_DPAD_UP = 309;
|
||||||
public static final int CLASSIC_DPAD_DOWN = 310;
|
public static final int CLASSIC_DPAD_DOWN = 310;
|
||||||
public static final int CLASSIC_DPAD_LEFT = 311;
|
public static final int CLASSIC_DPAD_LEFT = 311;
|
||||||
public static final int CLASSIC_DPAD_RIGHT = 312;
|
public static final int CLASSIC_DPAD_RIGHT = 312;
|
||||||
public static final int CLASSIC_STICK_LEFT = 313;
|
public static final int CLASSIC_STICK_LEFT = 313;
|
||||||
public static final int CLASSIC_STICK_LEFT_UP = 314;
|
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_DOWN = 315;
|
||||||
public static final int CLASSIC_STICK_LEFT_LEFT = 316;
|
public static final int CLASSIC_STICK_LEFT_LEFT = 316;
|
||||||
public static final int CLASSIC_STICK_LEFT_RIGHT = 317;
|
public static final int CLASSIC_STICK_LEFT_RIGHT = 317;
|
||||||
public static final int CLASSIC_STICK_RIGHT = 318;
|
public static final int CLASSIC_STICK_RIGHT = 318;
|
||||||
public static final int CLASSIC_STICK_RIGHT_UP = 319;
|
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_DOWN = 100;
|
||||||
public static final int CLASSIC_STICK_RIGHT_LEFT = 321;
|
public static final int CLASSIC_STICK_RIGHT_LEFT = 321;
|
||||||
public static final int CLASSIC_STICK_RIGHT_RIGHT = 322;
|
public static final int CLASSIC_STICK_RIGHT_RIGHT = 322;
|
||||||
public static final int CLASSIC_TRIGGER_L = 323;
|
public static final int CLASSIC_TRIGGER_L = 323;
|
||||||
public static final int CLASSIC_TRIGGER_R = 324;
|
public static final int CLASSIC_TRIGGER_R = 324;
|
||||||
public static final int GUITAR_BUTTON_MINUS = 400;
|
public static final int GUITAR_BUTTON_MINUS = 400;
|
||||||
public static final int GUITAR_BUTTON_PLUS = 401;
|
public static final int GUITAR_BUTTON_PLUS = 401;
|
||||||
public static final int GUITAR_FRET_GREEN = 402;
|
public static final int GUITAR_FRET_GREEN = 402;
|
||||||
public static final int GUITAR_FRET_RED = 403;
|
public static final int GUITAR_FRET_RED = 403;
|
||||||
public static final int GUITAR_FRET_YELLOW = 404;
|
public static final int GUITAR_FRET_YELLOW = 404;
|
||||||
public static final int GUITAR_FRET_BLUE = 405;
|
public static final int GUITAR_FRET_BLUE = 405;
|
||||||
public static final int GUITAR_FRET_ORANGE = 406;
|
public static final int GUITAR_FRET_ORANGE = 406;
|
||||||
public static final int GUITAR_STRUM_UP = 407;
|
public static final int GUITAR_STRUM_UP = 407;
|
||||||
public static final int GUITAR_STRUM_DOWN = 408;
|
public static final int GUITAR_STRUM_DOWN = 408;
|
||||||
public static final int GUITAR_STICK = 409;
|
public static final int GUITAR_STICK = 409;
|
||||||
public static final int GUITAR_STICK_UP = 410;
|
public static final int GUITAR_STICK_UP = 410;
|
||||||
public static final int GUITAR_STICK_DOWN = 411;
|
public static final int GUITAR_STICK_DOWN = 411;
|
||||||
public static final int GUITAR_STICK_LEFT = 412;
|
public static final int GUITAR_STICK_LEFT = 412;
|
||||||
public static final int GUITAR_STICK_RIGHT = 413;
|
public static final int GUITAR_STICK_RIGHT = 413;
|
||||||
public static final int GUITAR_WHAMMY_BAR = 414;
|
public static final int GUITAR_WHAMMY_BAR = 414;
|
||||||
public static final int DRUMS_BUTTON_MINUS = 500;
|
public static final int DRUMS_BUTTON_MINUS = 500;
|
||||||
public static final int DRUMS_BUTTON_PLUS = 501;
|
public static final int DRUMS_BUTTON_PLUS = 501;
|
||||||
public static final int DRUMS_PAD_RED = 502;
|
public static final int DRUMS_PAD_RED = 502;
|
||||||
public static final int DRUMS_PAD_YELLOW = 503;
|
public static final int DRUMS_PAD_YELLOW = 503;
|
||||||
public static final int DRUMS_PAD_BLUE = 504;
|
public static final int DRUMS_PAD_BLUE = 504;
|
||||||
public static final int DRUMS_PAD_GREEN = 505;
|
public static final int DRUMS_PAD_GREEN = 505;
|
||||||
public static final int DRUMS_PAD_ORANGE = 506;
|
public static final int DRUMS_PAD_ORANGE = 506;
|
||||||
public static final int DRUMS_PAD_BASS = 507;
|
public static final int DRUMS_PAD_BASS = 507;
|
||||||
public static final int DRUMS_STICK = 508;
|
public static final int DRUMS_STICK = 508;
|
||||||
public static final int DRUMS_STICK_UP = 509;
|
public static final int DRUMS_STICK_UP = 509;
|
||||||
public static final int DRUMS_STICK_DOWN = 510;
|
public static final int DRUMS_STICK_DOWN = 510;
|
||||||
public static final int DRUMS_STICK_LEFT = 511;
|
public static final int DRUMS_STICK_LEFT = 511;
|
||||||
public static final int DRUMS_STICK_RIGHT = 512;
|
public static final int DRUMS_STICK_RIGHT = 512;
|
||||||
public static final int TURNTABLE_BUTTON_GREEN_LEFT = 600;
|
public static final int TURNTABLE_BUTTON_GREEN_LEFT = 600;
|
||||||
public static final int TURNTABLE_BUTTON_RED_LEFT = 601;
|
public static final int TURNTABLE_BUTTON_RED_LEFT = 601;
|
||||||
public static final int TURNTABLE_BUTTON_BLUE_LEFT = 602;
|
public static final int TURNTABLE_BUTTON_BLUE_LEFT = 602;
|
||||||
public static final int TURNTABLE_BUTTON_GREEN_RIGHT = 603;
|
public static final int TURNTABLE_BUTTON_GREEN_RIGHT = 603;
|
||||||
public static final int TURNTABLE_BUTTON_RED_RIGHT = 604;
|
public static final int TURNTABLE_BUTTON_RED_RIGHT = 604;
|
||||||
public static final int TURNTABLE_BUTTON_BLUE_RIGHT = 605;
|
public static final int TURNTABLE_BUTTON_BLUE_RIGHT = 605;
|
||||||
public static final int TURNTABLE_BUTTON_MINUS = 606;
|
public static final int TURNTABLE_BUTTON_MINUS = 606;
|
||||||
public static final int TURNTABLE_BUTTON_PLUS = 607;
|
public static final int TURNTABLE_BUTTON_PLUS = 607;
|
||||||
public static final int TURNTABLE_BUTTON_HOME = 608;
|
public static final int TURNTABLE_BUTTON_HOME = 608;
|
||||||
public static final int TURNTABLE_BUTTON_EUPHORIA = 609;
|
public static final int TURNTABLE_BUTTON_EUPHORIA = 609;
|
||||||
public static final int TURNTABLE_TABLE_LEFT = 610;
|
public static final int TURNTABLE_TABLE_LEFT = 610;
|
||||||
public static final int TURNTABLE_TABLE_LEFT_LEFT = 611;
|
public static final int TURNTABLE_TABLE_LEFT_LEFT = 611;
|
||||||
public static final int TURNTABLE_TABLE_LEFT_RIGHT = 612;
|
public static final int TURNTABLE_TABLE_LEFT_RIGHT = 612;
|
||||||
public static final int TURNTABLE_TABLE_RIGHT = 613;
|
public static final int TURNTABLE_TABLE_RIGHT = 613;
|
||||||
public static final int TURNTABLE_TABLE_RIGHT_LEFT = 614;
|
public static final int TURNTABLE_TABLE_RIGHT_LEFT = 614;
|
||||||
public static final int TURNTABLE_TABLE_RIGHT_RIGHT = 615;
|
public static final int TURNTABLE_TABLE_RIGHT_RIGHT = 615;
|
||||||
public static final int TURNTABLE_STICK = 616;
|
public static final int TURNTABLE_STICK = 616;
|
||||||
public static final int TURNTABLE_STICK_UP = 617;
|
public static final int TURNTABLE_STICK_UP = 617;
|
||||||
public static final int TURNTABLE_STICK_DOWN = 618;
|
public static final int TURNTABLE_STICK_DOWN = 618;
|
||||||
public static final int TURNTABLE_STICK_LEFT = 619;
|
public static final int TURNTABLE_STICK_LEFT = 619;
|
||||||
public static final int TURNTABLE_STICK_RIGHT = 620;
|
public static final int TURNTABLE_STICK_RIGHT = 620;
|
||||||
public static final int TURNTABLE_EFFECT_DIAL = 621;
|
public static final int TURNTABLE_EFFECT_DIAL = 621;
|
||||||
public static final int TURNTABLE_CROSSFADE = 622;
|
public static final int TURNTABLE_CROSSFADE = 622;
|
||||||
public static final int TURNTABLE_CROSSFADE_LEFT = 623;
|
public static final int TURNTABLE_CROSSFADE_LEFT = 623;
|
||||||
public static final int TURNTABLE_CROSSFADE_RIGHT = 624;
|
public static final int TURNTABLE_CROSSFADE_RIGHT = 624;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Button states
|
* Button states
|
||||||
*/
|
*/
|
||||||
public static final class ButtonState
|
public static final class ButtonState
|
||||||
{
|
{
|
||||||
public static final int RELEASED = 0;
|
public static final int RELEASED = 0;
|
||||||
public static final int PRESSED = 1;
|
public static final int PRESSED = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private NativeLibrary()
|
private NativeLibrary()
|
||||||
{
|
{
|
||||||
// Disallows instantiation.
|
// Disallows instantiation.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default touchscreen device
|
* Default touchscreen device
|
||||||
*/
|
*/
|
||||||
public static final String TouchScreenDevice = "Touchscreen";
|
public static final String TouchScreenDevice = "Touchscreen";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles button press events for a gamepad.
|
* Handles button press events for a gamepad.
|
||||||
*
|
*
|
||||||
* @param Device The input descriptor of the gamepad.
|
* @param Device The input descriptor of the gamepad.
|
||||||
* @param Button Key code identifying which button was pressed.
|
* @param Button Key code identifying which button was pressed.
|
||||||
* @param Action Mask identifying which action is happening (button pressed down, or button released).
|
* @param Action Mask identifying which action is happening (button pressed down, or button released).
|
||||||
*
|
* @return If we handled the button press.
|
||||||
* @return If we handled the button press.
|
*/
|
||||||
*/
|
public static native boolean onGamePadEvent(String Device, int Button, int Action);
|
||||||
public static native boolean onGamePadEvent(String Device, int Button, int Action);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles gamepad movement events.
|
* Handles gamepad movement events.
|
||||||
*
|
*
|
||||||
* @param Device The device ID of the gamepad.
|
* @param Device The device ID of the gamepad.
|
||||||
* @param Axis The axis ID
|
* @param Axis The axis ID
|
||||||
* @param Value The value of the axis represented by the given 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 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.
|
* 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 configFile The ini-based config file to get the value from.
|
||||||
* @param Section The section key that the actual key is in.
|
* @param Section The section key that the actual key is in.
|
||||||
* @param Key The key to get the value from.
|
* @param Key The key to get the value from.
|
||||||
* @param Default The value to return in the event the given key doesn't exist.
|
* @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.
|
||||||
* @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,
|
||||||
public static native String GetConfig(String configFile, String Section, String Key, String Default);
|
String Default);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a value to a key in the given ini config file.
|
* 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 configFile The ini-based config file to add the value to.
|
||||||
* @param Section The section key for the ini key
|
* @param Section The section key for the ini key
|
||||||
* @param Key The actual ini key to set.
|
* @param Key The actual ini key to set.
|
||||||
* @param Value The string to set the ini key to.
|
* @param Value The string to set the ini key to.
|
||||||
*/
|
*/
|
||||||
public static native void SetConfig(String configFile, String Section, String Key, String Value);
|
public static native void SetConfig(String configFile, String Section, String Key, String Value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Dolphin version string.
|
* Gets the Dolphin version string.
|
||||||
*
|
*
|
||||||
* @return the Dolphin version string.
|
* @return the Dolphin version string.
|
||||||
*/
|
*/
|
||||||
public static native String GetVersionString();
|
public static native String GetVersionString();
|
||||||
|
|
||||||
public static native String GetGitRevision();
|
public static native String GetGitRevision();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a screen capture of the game
|
* Saves a screen capture of the game
|
||||||
*/
|
*/
|
||||||
public static native void SaveScreenShot();
|
public static native void SaveScreenShot();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a game state to the slot number.
|
* Saves a game state to the slot number.
|
||||||
*
|
*
|
||||||
* @param slot The slot location to save state to.
|
* @param slot The slot location to save state to.
|
||||||
* @param wait If false, returns as early as possible.
|
* @param wait If false, returns as early as possible.
|
||||||
* If true, returns once the savestate has been written to disk.
|
* If true, returns once the savestate has been written to disk.
|
||||||
*/
|
*/
|
||||||
public static native void SaveState(int slot, boolean wait);
|
public static native void SaveState(int slot, boolean wait);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves a game state to the specified path.
|
* Saves a game state to the specified path.
|
||||||
*
|
*
|
||||||
* @param path The path to save state to.
|
* @param path The path to save state to.
|
||||||
* @param wait If false, returns as early as possible.
|
* @param wait If false, returns as early as possible.
|
||||||
* If true, returns once the savestate has been written to disk.
|
* If true, returns once the savestate has been written to disk.
|
||||||
*/
|
*/
|
||||||
public static native void SaveStateAs(String path, boolean wait);
|
public static native void SaveStateAs(String path, boolean wait);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a game state from the slot number.
|
* Loads a game state from the slot number.
|
||||||
*
|
*
|
||||||
* @param slot The slot location to load state from.
|
* @param slot The slot location to load state from.
|
||||||
*/
|
*/
|
||||||
public static native void LoadState(int slot);
|
public static native void LoadState(int slot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a game state from the specified path.
|
* Loads a game state from the specified path.
|
||||||
*
|
*
|
||||||
* @param path The path to load state from.
|
* @param path The path to load state from.
|
||||||
*/
|
*/
|
||||||
public static native void LoadStateAs(String path);
|
public static native void LoadStateAs(String path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current working user directory
|
* Sets the current working user directory
|
||||||
* If not set, it auto-detects a location
|
* If not set, it auto-detects a location
|
||||||
*/
|
*/
|
||||||
public static native void SetUserDirectory(String directory);
|
public static native void SetUserDirectory(String directory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current working user directory
|
* Returns the current working user directory
|
||||||
*/
|
*/
|
||||||
public static native String GetUserDirectory();
|
public static native String GetUserDirectory();
|
||||||
|
|
||||||
public static native int DefaultCPUCore();
|
public static native int DefaultCPUCore();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begins emulation.
|
* Begins emulation.
|
||||||
*/
|
*/
|
||||||
public static native void Run(String path, boolean firstOpen);
|
public static native void Run(String path, boolean firstOpen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Begins emulation from the specified savestate.
|
* Begins emulation from the specified savestate.
|
||||||
*/
|
*/
|
||||||
public static native void Run(String path, String savestatePath, boolean deleteSavestate);
|
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
|
// Surface Handling
|
||||||
public static native void SurfaceChanged(Surface surf);
|
public static native void SurfaceChanged(Surface surf);
|
||||||
public static native void SurfaceDestroyed();
|
|
||||||
|
|
||||||
/** Unpauses emulation from a paused state. */
|
public static native void SurfaceDestroyed();
|
||||||
public static native void UnPauseEmulation();
|
|
||||||
|
|
||||||
/** 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
|
* Returns true if emulation is running (or is paused).
|
||||||
* @param enable
|
*/
|
||||||
*/
|
public static native boolean IsRunning();
|
||||||
public static native void SetProfiling(boolean enable);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes out the block profile results
|
* Enables or disables CPU block profiling
|
||||||
*/
|
*
|
||||||
public static native void WriteProfileResults();
|
* @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
|
* Native EGL functions not exposed by Java bindings
|
||||||
*/
|
**/
|
||||||
public static native void RefreshWiimotes();
|
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)
|
* Provides a way to refresh the connections on Wiimotes
|
||||||
{
|
*/
|
||||||
Log.error("[NativeLibrary] Alert: " + text);
|
public static native void RefreshWiimotes();
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
|
||||||
boolean result = false;
|
|
||||||
if (emulationActivity == null)
|
|
||||||
{
|
|
||||||
Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Create object used for waiting.
|
|
||||||
final Object lock = new Object();
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
|
|
||||||
.setTitle(caption)
|
|
||||||
.setMessage(text);
|
|
||||||
|
|
||||||
// If not yes/no dialog just have one button that dismisses modal,
|
private static boolean alertResult = false;
|
||||||
// otherwise have a yes and no button that sets alertResult accordingly.
|
|
||||||
if (!yesNo)
|
|
||||||
{
|
|
||||||
builder
|
|
||||||
.setCancelable(false)
|
|
||||||
.setPositiveButton("OK", (dialog, whichButton) ->
|
|
||||||
{
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (lock)
|
|
||||||
{
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
alertResult = false;
|
|
||||||
|
|
||||||
builder
|
public static boolean displayAlertMsg(final String caption, final String text,
|
||||||
.setPositiveButton("Yes", (dialog, whichButton) ->
|
final boolean yesNo)
|
||||||
{
|
{
|
||||||
alertResult = true;
|
Log.error("[NativeLibrary] Alert: " + text);
|
||||||
dialog.dismiss();
|
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
||||||
synchronized (lock)
|
boolean result = false;
|
||||||
{
|
if (emulationActivity == null)
|
||||||
lock.notify();
|
{
|
||||||
}
|
Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert.");
|
||||||
})
|
}
|
||||||
.setNegativeButton("No", (dialog, whichButton) ->
|
else
|
||||||
{
|
{
|
||||||
alertResult = false;
|
// Create object used for waiting.
|
||||||
dialog.dismiss();
|
final Object lock = new Object();
|
||||||
synchronized (lock)
|
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity)
|
||||||
{
|
.setTitle(caption)
|
||||||
lock.notify();
|
.setMessage(text);
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the AlertDialog on the main thread.
|
// If not yes/no dialog just have one button that dismisses modal,
|
||||||
emulationActivity.runOnUiThread(() -> builder.show());
|
// 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.
|
builder
|
||||||
synchronized (lock)
|
.setPositiveButton("Yes", (dialog, whichButton) ->
|
||||||
{
|
{
|
||||||
try
|
alertResult = true;
|
||||||
{
|
dialog.dismiss();
|
||||||
lock.wait();
|
synchronized (lock)
|
||||||
}
|
{
|
||||||
catch (Exception e) { }
|
lock.notify();
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton("No", (dialog, whichButton) ->
|
||||||
|
{
|
||||||
|
alertResult = false;
|
||||||
|
dialog.dismiss();
|
||||||
|
synchronized (lock)
|
||||||
|
{
|
||||||
|
lock.notify();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (yesNo)
|
// Show the AlertDialog on the main thread.
|
||||||
result = alertResult;
|
emulationActivity.runOnUiThread(() -> builder.show());
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setEmulationActivity(EmulationActivity emulationActivity)
|
// Wait for the lock to notify that it is complete.
|
||||||
{
|
synchronized (lock)
|
||||||
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
|
{
|
||||||
sEmulationActivity = new WeakReference<>(emulationActivity);
|
try
|
||||||
}
|
{
|
||||||
|
lock.wait();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void clearEmulationActivity()
|
if (yesNo)
|
||||||
{
|
result = alertResult;
|
||||||
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.");
|
}
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,113 +22,116 @@ import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
|
||||||
*/
|
*/
|
||||||
public class AppLinkActivity extends FragmentActivity
|
public class AppLinkActivity extends FragmentActivity
|
||||||
{
|
{
|
||||||
private static final String TAG = "AppLinkActivity";
|
private static final String TAG = "AppLinkActivity";
|
||||||
|
|
||||||
private AppLinkHelper.PlayAction playAction;
|
private AppLinkHelper.PlayAction playAction;
|
||||||
private DirectoryStateReceiver directoryStateReceiver;
|
private DirectoryStateReceiver directoryStateReceiver;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
Uri uri = intent.getData();
|
Uri uri = intent.getData();
|
||||||
|
|
||||||
Log.v(TAG, uri.toString());
|
Log.v(TAG, uri.toString());
|
||||||
|
|
||||||
if (uri.getPathSegments().isEmpty())
|
if (uri.getPathSegments().isEmpty())
|
||||||
{
|
{
|
||||||
Log.e(TAG, "Invalid uri " + uri);
|
Log.e(TAG, "Invalid uri " + uri);
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AppLinkHelper.AppLinkAction action = AppLinkHelper.extractAction(uri);
|
AppLinkHelper.AppLinkAction action = AppLinkHelper.extractAction(uri);
|
||||||
switch (action.getAction())
|
switch (action.getAction())
|
||||||
{
|
{
|
||||||
case AppLinkHelper.PLAY:
|
case AppLinkHelper.PLAY:
|
||||||
playAction = (AppLinkHelper.PlayAction) action;
|
playAction = (AppLinkHelper.PlayAction) action;
|
||||||
initResources();
|
initResources();
|
||||||
break;
|
break;
|
||||||
case AppLinkHelper.BROWSE:
|
case AppLinkHelper.BROWSE:
|
||||||
browse();
|
browse();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Invalid Action " + action);
|
throw new IllegalArgumentException("Invalid Action " + action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Need to init these since they usually occur in the main activity.
|
* Need to init these since they usually occur in the main activity.
|
||||||
*/
|
*/
|
||||||
private void initResources()
|
private void initResources()
|
||||||
{
|
{
|
||||||
IntentFilter statusIntentFilter = new IntentFilter(
|
IntentFilter statusIntentFilter = new IntentFilter(
|
||||||
DirectoryInitializationService.BROADCAST_ACTION);
|
DirectoryInitializationService.BROADCAST_ACTION);
|
||||||
|
|
||||||
directoryStateReceiver =
|
directoryStateReceiver =
|
||||||
new DirectoryStateReceiver(directoryInitializationState ->
|
new DirectoryStateReceiver(directoryInitializationState ->
|
||||||
{
|
{
|
||||||
if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
if (directoryInitializationState ==
|
||||||
{
|
DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
||||||
play(playAction);
|
{
|
||||||
}
|
play(playAction);
|
||||||
else if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
}
|
||||||
{
|
else if (directoryInitializationState ==
|
||||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
DirectoryInitializationService.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
||||||
.show();
|
{
|
||||||
}
|
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||||
else if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
|
.show();
|
||||||
{
|
}
|
||||||
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
|
else if (directoryInitializationState ==
|
||||||
.show();
|
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
|
// Registers the DirectoryStateReceiver and its intent filters
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||||
directoryStateReceiver,
|
directoryStateReceiver,
|
||||||
statusIntentFilter);
|
statusIntentFilter);
|
||||||
DirectoryInitializationService.startService(this);
|
DirectoryInitializationService.startService(this);
|
||||||
GameFileCacheService.startLoad(this);
|
GameFileCacheService.startLoad(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action if channel icon is selected
|
* Action if channel icon is selected
|
||||||
*/
|
*/
|
||||||
private void browse()
|
private void browse()
|
||||||
{
|
{
|
||||||
Intent openApp = new Intent(this, TvMainActivity.class);
|
Intent openApp = new Intent(this, TvMainActivity.class);
|
||||||
startActivity(openApp);
|
startActivity(openApp);
|
||||||
|
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action if program(game) is selected
|
* Action if program(game) is selected
|
||||||
*/
|
*/
|
||||||
private void play(AppLinkHelper.PlayAction action)
|
private void play(AppLinkHelper.PlayAction action)
|
||||||
{
|
{
|
||||||
Log.d(TAG, "Playing game "
|
Log.d(TAG, "Playing game "
|
||||||
+ action.getGameId()
|
+ action.getGameId()
|
||||||
+ " from channel "
|
+ " from channel "
|
||||||
+ action.getChannelId());
|
+ action.getChannelId());
|
||||||
|
|
||||||
GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());
|
GameFile game = GameFileCacheService.getGameFileByGameId(action.getGameId());
|
||||||
if (game == null)
|
if (game == null)
|
||||||
Log.e(TAG, "Invalid Game: " + action.getGameId());
|
Log.e(TAG, "Invalid Game: " + action.getGameId());
|
||||||
else
|
else
|
||||||
startGame(game);
|
startGame(game);
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startGame(GameFile game)
|
private void startGame(GameFile game)
|
||||||
{
|
{
|
||||||
if (directoryStateReceiver != null)
|
if (directoryStateReceiver != null)
|
||||||
{
|
{
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(directoryStateReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(directoryStateReceiver);
|
||||||
directoryStateReceiver = null;
|
directoryStateReceiver = null;
|
||||||
}
|
}
|
||||||
EmulationActivity.launch(this, game, -1, null);
|
EmulationActivity.launch(this, game, -1, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,16 +13,17 @@ import java.io.File;
|
||||||
public class CustomFilePickerActivity extends FilePickerActivity
|
public class CustomFilePickerActivity extends FilePickerActivity
|
||||||
|
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected AbstractFilePickerFragment<File> getFragment(
|
protected AbstractFilePickerFragment<File> getFragment(
|
||||||
@Nullable final String startPath, final int mode, final boolean allowMultiple,
|
@Nullable final String startPath, final int mode, final boolean allowMultiple,
|
||||||
final boolean allowCreateDir, final boolean allowExistingFile,
|
final boolean allowCreateDir, final boolean allowExistingFile,
|
||||||
final boolean singleClick)
|
final boolean singleClick)
|
||||||
{
|
{
|
||||||
AbstractFilePickerFragment<File> fragment = new CustomFilePickerFragment();
|
AbstractFilePickerFragment<File> fragment = new CustomFilePickerFragment();
|
||||||
// startPath is allowed to be null. In that case, default folder should be SD-card and not "/"
|
// 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(),
|
fragment.setArgs(
|
||||||
mode, allowMultiple, allowCreateDir, allowExistingFile, singleClick);
|
startPath != null ? startPath : Environment.getExternalStorageDirectory().getPath(),
|
||||||
return fragment;
|
mode, allowMultiple, allowCreateDir, allowExistingFile, singleClick);
|
||||||
}
|
return fragment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,10 +12,10 @@ import android.widget.Toast;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
import org.dolphinemu.dolphinemu.model.GameFile;
|
|
||||||
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
|
||||||
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
|
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.utils.PicassoUtils;
|
||||||
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
|
import org.dolphinemu.dolphinemu.viewholders.GameViewHolder;
|
||||||
|
|
||||||
|
@ -24,186 +24,195 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> implements
|
public final class GameAdapter extends RecyclerView.Adapter<GameViewHolder> implements
|
||||||
View.OnClickListener,
|
View.OnClickListener,
|
||||||
View.OnLongClickListener
|
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
|
* Initializes the adapter's observer, which watches for changes to the dataset. The adapter will
|
||||||
* display no data until swapDataSet is called.
|
* display no data until swapDataSet is called.
|
||||||
*/
|
*/
|
||||||
public GameAdapter()
|
public GameAdapter()
|
||||||
{
|
{
|
||||||
mGameFiles = new ArrayList<>();
|
mGameFiles = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the LayoutManager when it is necessary to create a new view.
|
* 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 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.
|
* @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.
|
* @return The created ViewHolder with references to all the child view's members.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
|
public GameViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
|
||||||
{
|
{
|
||||||
// Create a new view.
|
// Create a new view.
|
||||||
View gameCard = LayoutInflater.from(parent.getContext())
|
View gameCard = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.card_game, parent, false);
|
.inflate(R.layout.card_game, parent, false);
|
||||||
|
|
||||||
gameCard.setOnClickListener(this);
|
gameCard.setOnClickListener(this);
|
||||||
gameCard.setOnLongClickListener(this);
|
gameCard.setOnLongClickListener(this);
|
||||||
|
|
||||||
// Use that view to create a ViewHolder.
|
// Use that view to create a ViewHolder.
|
||||||
return new GameViewHolder(gameCard);
|
return new GameViewHolder(gameCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the LayoutManager when a new view is not necessary because we can recycle
|
* 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
|
* 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.)
|
* 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 holder A ViewHolder representing the view we're recycling.
|
||||||
* @param position The position of the 'new' view in the dataset.
|
* @param position The position of the 'new' view in the dataset.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(GameViewHolder holder, int position)
|
public void onBindViewHolder(GameViewHolder holder, int position)
|
||||||
{
|
{
|
||||||
GameFile gameFile = mGameFiles.get(position);
|
GameFile gameFile = mGameFiles.get(position);
|
||||||
PicassoUtils.loadGameBanner(holder.imageScreenshot, gameFile);
|
PicassoUtils.loadGameBanner(holder.imageScreenshot, gameFile);
|
||||||
|
|
||||||
holder.textGameTitle.setText(gameFile.getTitle());
|
holder.textGameTitle.setText(gameFile.getTitle());
|
||||||
holder.textCompany.setText(gameFile.getCompany());
|
holder.textCompany.setText(gameFile.getCompany());
|
||||||
|
|
||||||
holder.gameFile = gameFile;
|
holder.gameFile = gameFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the LayoutManager to find out how much data we have.
|
* Called by the LayoutManager to find out how much data we have.
|
||||||
*
|
*
|
||||||
* @return Size of the dataset.
|
* @return Size of the dataset.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount()
|
public int getItemCount()
|
||||||
{
|
{
|
||||||
return mGameFiles.size();
|
return mGameFiles.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell Android whether or not each item in the dataset has a stable identifier.
|
* Tell Android whether or not each item in the dataset has a stable identifier.
|
||||||
*
|
*
|
||||||
* @param hasStableIds ignored.
|
* @param hasStableIds ignored.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setHasStableIds(boolean hasStableIds)
|
public void setHasStableIds(boolean hasStableIds)
|
||||||
{
|
{
|
||||||
super.setHasStableIds(false);
|
super.setHasStableIds(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a load is finished, call this to replace the existing data
|
* When a load is finished, call this to replace the existing data
|
||||||
* with the newly-loaded data.
|
* with the newly-loaded data.
|
||||||
*/
|
*/
|
||||||
public void swapDataSet(List<GameFile> gameFiles)
|
public void swapDataSet(List<GameFile> gameFiles)
|
||||||
{
|
{
|
||||||
mGameFiles = gameFiles;
|
mGameFiles = gameFiles;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launches the game that was clicked on.
|
* Launches the game that was clicked on.
|
||||||
*
|
*
|
||||||
* @param view The card representing the game the user wants to play.
|
* @param view The card representing the game the user wants to play.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view)
|
public void onClick(View view)
|
||||||
{
|
{
|
||||||
GameViewHolder holder = (GameViewHolder) view.getTag();
|
GameViewHolder holder = (GameViewHolder) view.getTag();
|
||||||
|
|
||||||
EmulationActivity.launch((FragmentActivity) view.getContext(),
|
EmulationActivity.launch((FragmentActivity) view.getContext(),
|
||||||
holder.gameFile,
|
holder.gameFile,
|
||||||
holder.getAdapterPosition(),
|
holder.getAdapterPosition(),
|
||||||
holder.imageScreenshot);
|
holder.imageScreenshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Launches the details activity for this Game, using an ID stored in the
|
* Launches the details activity for this Game, using an ID stored in the
|
||||||
* details button's Tag.
|
* details button's Tag.
|
||||||
*
|
*
|
||||||
* @param view The Card button that was long-clicked.
|
* @param view The Card button that was long-clicked.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onLongClick(View view)
|
public boolean onLongClick(View view)
|
||||||
{
|
{
|
||||||
FragmentActivity activity = (FragmentActivity) view.getContext();
|
FragmentActivity activity = (FragmentActivity) view.getContext();
|
||||||
GameViewHolder holder = (GameViewHolder) view.getTag();
|
GameViewHolder holder = (GameViewHolder) view.getTag();
|
||||||
String gameId = holder.gameFile.getGameId();
|
String gameId = holder.gameFile.getGameId();
|
||||||
|
|
||||||
if (gameId.isEmpty())
|
if (gameId.isEmpty())
|
||||||
{
|
{
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle("Game Settings");
|
builder.setTitle("Game Settings");
|
||||||
builder.setMessage("Files without game IDs don't support game-specific settings.");
|
builder.setMessage("Files without game IDs don't support game-specific settings.");
|
||||||
|
|
||||||
builder.show();
|
builder.show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle("Game Settings")
|
builder.setTitle("Game Settings")
|
||||||
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener() {
|
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener()
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
{
|
||||||
switch (which) {
|
public void onClick(DialogInterface dialog, int which)
|
||||||
case 0:
|
{
|
||||||
SettingsActivity.launch(activity, MenuTag.CONFIG, gameId);
|
switch (which)
|
||||||
break;
|
{
|
||||||
case 1:
|
case 0:
|
||||||
SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId);
|
SettingsActivity.launch(activity, MenuTag.CONFIG, gameId);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 1:
|
||||||
String path = DirectoryInitializationService.getUserDirectory() + "/GameSettings/" + gameId + ".ini";
|
SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId);
|
||||||
File gameSettingsFile = new File(path);
|
break;
|
||||||
if (gameSettingsFile.exists())
|
case 2:
|
||||||
{
|
String path =
|
||||||
if (gameSettingsFile.delete())
|
DirectoryInitializationService.getUserDirectory() + "/GameSettings/" +
|
||||||
{
|
gameId + ".ini";
|
||||||
Toast.makeText(view.getContext(), "Cleared settings for " + gameId, Toast.LENGTH_SHORT).show();
|
File gameSettingsFile = new File(path);
|
||||||
}
|
if (gameSettingsFile.exists())
|
||||||
else
|
{
|
||||||
{
|
if (gameSettingsFile.delete())
|
||||||
Toast.makeText(view.getContext(), "Unable to clear settings for " + gameId, Toast.LENGTH_SHORT).show();
|
{
|
||||||
}
|
Toast.makeText(view.getContext(), "Cleared settings for " + gameId,
|
||||||
}
|
Toast.LENGTH_SHORT).show();
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
Toast.makeText(view.getContext(), "No game settings to delete", Toast.LENGTH_SHORT).show();
|
{
|
||||||
}
|
Toast.makeText(view.getContext(), "Unable to clear settings for " + gameId,
|
||||||
break;
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
else
|
||||||
|
{
|
||||||
|
Toast.makeText(view.getContext(), "No game settings to delete",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
builder.show();
|
builder.show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SpacesItemDecoration extends RecyclerView.ItemDecoration
|
public static class SpacesItemDecoration extends RecyclerView.ItemDecoration
|
||||||
{
|
{
|
||||||
private int space;
|
private int space;
|
||||||
|
|
||||||
public SpacesItemDecoration(int space)
|
public SpacesItemDecoration(int space)
|
||||||
{
|
{
|
||||||
this.space = space;
|
this.space = space;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state)
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||||
{
|
RecyclerView.State state)
|
||||||
outRect.left = space;
|
{
|
||||||
outRect.right = space;
|
outRect.left = space;
|
||||||
outRect.bottom = space;
|
outRect.right = space;
|
||||||
outRect.top = space;
|
outRect.bottom = space;
|
||||||
}
|
outRect.top = space;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ import android.widget.ImageView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
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.model.GameFile;
|
||||||
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
||||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
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.utils.PicassoUtils;
|
||||||
import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder;
|
import org.dolphinemu.dolphinemu.viewholders.TvGameViewHolder;
|
||||||
|
|
||||||
|
@ -30,117 +30,126 @@ import java.io.File;
|
||||||
*/
|
*/
|
||||||
public final class GameRowPresenter extends Presenter
|
public final class GameRowPresenter extends Presenter
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public ViewHolder onCreateViewHolder(ViewGroup parent)
|
public ViewHolder onCreateViewHolder(ViewGroup parent)
|
||||||
{
|
{
|
||||||
// Create a new view.
|
// Create a new view.
|
||||||
ImageCardView gameCard = new ImageCardView(parent.getContext());
|
ImageCardView gameCard = new ImageCardView(parent.getContext());
|
||||||
|
|
||||||
gameCard.setMainImageAdjustViewBounds(true);
|
gameCard.setMainImageAdjustViewBounds(true);
|
||||||
gameCard.setMainImageDimensions(240, 336);
|
gameCard.setMainImageDimensions(240, 336);
|
||||||
gameCard.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP);
|
gameCard.setMainImageScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||||
|
|
||||||
gameCard.setFocusable(true);
|
gameCard.setFocusable(true);
|
||||||
gameCard.setFocusableInTouchMode(true);
|
gameCard.setFocusableInTouchMode(true);
|
||||||
|
|
||||||
// Use that view to create a ViewHolder.
|
// Use that view to create a ViewHolder.
|
||||||
return new TvGameViewHolder(gameCard);
|
return new TvGameViewHolder(gameCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ViewHolder viewHolder, Object item)
|
public void onBindViewHolder(ViewHolder viewHolder, Object item)
|
||||||
{
|
{
|
||||||
TvGameViewHolder holder = (TvGameViewHolder) viewHolder;
|
TvGameViewHolder holder = (TvGameViewHolder) viewHolder;
|
||||||
GameFile gameFile = (GameFile) item;
|
GameFile gameFile = (GameFile) item;
|
||||||
|
|
||||||
holder.imageScreenshot.setImageDrawable(null);
|
holder.imageScreenshot.setImageDrawable(null);
|
||||||
PicassoUtils.loadGameBanner(holder.imageScreenshot, gameFile);
|
PicassoUtils.loadGameBanner(holder.imageScreenshot, gameFile);
|
||||||
|
|
||||||
holder.cardParent.setTitleText(gameFile.getTitle());
|
holder.cardParent.setTitleText(gameFile.getTitle());
|
||||||
holder.cardParent.setContentText(gameFile.getCompany());
|
holder.cardParent.setContentText(gameFile.getCompany());
|
||||||
|
|
||||||
holder.gameFile = gameFile;
|
holder.gameFile = gameFile;
|
||||||
|
|
||||||
// Set the platform-dependent background color of the card
|
// Set the platform-dependent background color of the card
|
||||||
int backgroundId;
|
int backgroundId;
|
||||||
switch (Platform.fromNativeInt(gameFile.getPlatform()))
|
switch (Platform.fromNativeInt(gameFile.getPlatform()))
|
||||||
{
|
{
|
||||||
case GAMECUBE:
|
case GAMECUBE:
|
||||||
backgroundId = R.drawable.tv_card_background_gamecube;
|
backgroundId = R.drawable.tv_card_background_gamecube;
|
||||||
break;
|
break;
|
||||||
case WII:
|
case WII:
|
||||||
backgroundId = R.drawable.tv_card_background_wii;
|
backgroundId = R.drawable.tv_card_background_wii;
|
||||||
break;
|
break;
|
||||||
case WIIWARE:
|
case WIIWARE:
|
||||||
backgroundId = R.drawable.tv_card_background_wiiware;
|
backgroundId = R.drawable.tv_card_background_wiiware;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new AssertionError("Not reachable.");
|
throw new AssertionError("Not reachable.");
|
||||||
}
|
}
|
||||||
Context context = holder.cardParent.getContext();
|
Context context = holder.cardParent.getContext();
|
||||||
Drawable background = ContextCompat.getDrawable(context, backgroundId);
|
Drawable background = ContextCompat.getDrawable(context, backgroundId);
|
||||||
holder.cardParent.setInfoAreaBackground(background);
|
holder.cardParent.setInfoAreaBackground(background);
|
||||||
holder.cardParent.setOnLongClickListener(new View.OnLongClickListener() {
|
holder.cardParent.setOnLongClickListener(new View.OnLongClickListener()
|
||||||
@Override
|
{
|
||||||
public boolean onLongClick(View view)
|
@Override
|
||||||
{
|
public boolean onLongClick(View view)
|
||||||
FragmentActivity activity = (FragmentActivity) view.getContext();
|
{
|
||||||
String gameId = gameFile.getGameId();
|
FragmentActivity activity = (FragmentActivity) view.getContext();
|
||||||
|
String gameId = gameFile.getGameId();
|
||||||
|
|
||||||
if (gameId.isEmpty())
|
if (gameId.isEmpty())
|
||||||
{
|
{
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle("Game Settings");
|
builder.setTitle("Game Settings");
|
||||||
builder.setMessage("Files without game IDs don't support game-specific settings.");
|
builder.setMessage("Files without game IDs don't support game-specific settings.");
|
||||||
|
|
||||||
builder.show();
|
builder.show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setTitle("Game Settings")
|
builder.setTitle("Game Settings")
|
||||||
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener() {
|
.setItems(R.array.gameSettingsMenus, new DialogInterface.OnClickListener()
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
{
|
||||||
switch (which) {
|
public void onClick(DialogInterface dialog, int which)
|
||||||
case 0:
|
{
|
||||||
SettingsActivity.launch(activity, MenuTag.CONFIG, gameId);
|
switch (which)
|
||||||
break;
|
{
|
||||||
case 1:
|
case 0:
|
||||||
SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId);
|
SettingsActivity.launch(activity, MenuTag.CONFIG, gameId);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 1:
|
||||||
String path = DirectoryInitializationService.getUserDirectory() + "/GameSettings/" + gameId + ".ini";
|
SettingsActivity.launch(activity, MenuTag.GRAPHICS, gameId);
|
||||||
File gameSettingsFile = new File(path);
|
break;
|
||||||
if (gameSettingsFile.exists())
|
case 2:
|
||||||
{
|
String path = DirectoryInitializationService.getUserDirectory() +
|
||||||
if (gameSettingsFile.delete())
|
"/GameSettings/" + gameId + ".ini";
|
||||||
{
|
File gameSettingsFile = new File(path);
|
||||||
Toast.makeText(view.getContext(), "Cleared settings for " + gameId, Toast.LENGTH_SHORT).show();
|
if (gameSettingsFile.exists())
|
||||||
}
|
{
|
||||||
else
|
if (gameSettingsFile.delete())
|
||||||
{
|
{
|
||||||
Toast.makeText(view.getContext(), "Unable to clear settings for " + gameId, Toast.LENGTH_SHORT).show();
|
Toast.makeText(view.getContext(), "Cleared settings for " + gameId,
|
||||||
}
|
Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Toast.makeText(view.getContext(), "No game settings to delete", Toast.LENGTH_SHORT).show();
|
Toast.makeText(view.getContext(),
|
||||||
}
|
"Unable to clear settings for " + gameId, Toast.LENGTH_SHORT)
|
||||||
break;
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
else
|
||||||
|
{
|
||||||
|
Toast.makeText(view.getContext(), "No game settings to delete",
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
builder.show();
|
builder.show();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUnbindViewHolder(ViewHolder viewHolder)
|
public void onUnbindViewHolder(ViewHolder viewHolder)
|
||||||
{
|
{
|
||||||
// no op
|
// no op
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ package org.dolphinemu.dolphinemu.adapters;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.support.v4.app.FragmentPagerAdapter;
|
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
|
import android.support.v4.app.FragmentPagerAdapter;
|
||||||
import android.text.Spannable;
|
import android.text.Spannable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.style.ImageSpan;
|
import android.text.style.ImageSpan;
|
||||||
|
@ -15,48 +15,48 @@ import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesFragment;
|
||||||
|
|
||||||
public class PlatformPagerAdapter extends FragmentPagerAdapter
|
public class PlatformPagerAdapter extends FragmentPagerAdapter
|
||||||
{
|
{
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
private final static int[] TAB_ICONS =
|
private final static int[] TAB_ICONS =
|
||||||
{
|
{
|
||||||
R.drawable.ic_gamecube,
|
R.drawable.ic_gamecube,
|
||||||
R.drawable.ic_wii,
|
R.drawable.ic_wii,
|
||||||
R.drawable.ic_folder // WiiWare TODO Have an icon here.
|
R.drawable.ic_folder // WiiWare TODO Have an icon here.
|
||||||
};
|
};
|
||||||
|
|
||||||
public PlatformPagerAdapter(FragmentManager fm, Context context)
|
public PlatformPagerAdapter(FragmentManager fm, Context context)
|
||||||
{
|
{
|
||||||
super(fm);
|
super(fm);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Fragment getItem(int position)
|
public Fragment getItem(int position)
|
||||||
{
|
{
|
||||||
return PlatformGamesFragment.newInstance(Platform.fromPosition(position));
|
return PlatformGamesFragment.newInstance(Platform.fromPosition(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount()
|
public int getCount()
|
||||||
{
|
{
|
||||||
return TAB_ICONS.length;
|
return TAB_ICONS.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CharSequence getPageTitle(int position)
|
public CharSequence getPageTitle(int position)
|
||||||
{
|
{
|
||||||
// Hax from https://guides.codepath.com/android/Google-Play-Style-Tabs-using-TabLayout#design-support-library
|
// Hax from https://guides.codepath.com/android/Google-Play-Style-Tabs-using-TabLayout#design-support-library
|
||||||
// Apparently a workaround for TabLayout not supporting icons.
|
// 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 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
|
// TODO Also remove additional hax from styles.xml
|
||||||
Drawable drawable = mContext.getResources().getDrawable(TAB_ICONS[position]);
|
Drawable drawable = mContext.getResources().getDrawable(TAB_ICONS[position]);
|
||||||
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
|
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(" ");
|
SpannableString sb = new SpannableString(" ");
|
||||||
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
sb.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
return sb;
|
return sb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,37 +10,37 @@ import org.dolphinemu.dolphinemu.viewholders.TvSettingsViewHolder;
|
||||||
|
|
||||||
public final class SettingsRowPresenter extends Presenter
|
public final class SettingsRowPresenter extends Presenter
|
||||||
{
|
{
|
||||||
public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent)
|
public Presenter.ViewHolder onCreateViewHolder(ViewGroup parent)
|
||||||
{
|
{
|
||||||
// Create a new view.
|
// Create a new view.
|
||||||
ImageCardView settingsCard = new ImageCardView(parent.getContext());
|
ImageCardView settingsCard = new ImageCardView(parent.getContext());
|
||||||
|
|
||||||
settingsCard.setMainImageAdjustViewBounds(true);
|
settingsCard.setMainImageAdjustViewBounds(true);
|
||||||
settingsCard.setMainImageDimensions(192, 160);
|
settingsCard.setMainImageDimensions(192, 160);
|
||||||
|
|
||||||
|
|
||||||
settingsCard.setFocusable(true);
|
settingsCard.setFocusable(true);
|
||||||
settingsCard.setFocusableInTouchMode(true);
|
settingsCard.setFocusableInTouchMode(true);
|
||||||
|
|
||||||
// Use that view to create a ViewHolder.
|
// Use that view to create a ViewHolder.
|
||||||
return new TvSettingsViewHolder(settingsCard);
|
return new TvSettingsViewHolder(settingsCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item)
|
public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item)
|
||||||
{
|
{
|
||||||
TvSettingsViewHolder holder = (TvSettingsViewHolder) viewHolder;
|
TvSettingsViewHolder holder = (TvSettingsViewHolder) viewHolder;
|
||||||
TvSettingsItem settingsItem = (TvSettingsItem) item;
|
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.setTitleText(resources.getString(settingsItem.getLabelId()));
|
||||||
holder.cardParent.setMainImage(resources.getDrawable(settingsItem.getIconId(), null));
|
holder.cardParent.setMainImage(resources.getDrawable(settingsItem.getIconId(), null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder)
|
public void onUnbindViewHolder(Presenter.ViewHolder viewHolder)
|
||||||
{
|
{
|
||||||
// no op
|
// no op
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,14 +5,12 @@ import android.app.Dialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
import android.support.v4.app.DialogFragment;
|
import android.support.v4.app.DialogFragment;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.squareup.picasso.Picasso;
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.DolphinApplication;
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
import org.dolphinemu.dolphinemu.model.GameFile;
|
import org.dolphinemu.dolphinemu.model.GameFile;
|
||||||
|
@ -22,63 +20,64 @@ import de.hdodenhof.circleimageview.CircleImageView;
|
||||||
|
|
||||||
public final class GameDetailsDialog extends DialogFragment
|
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)
|
public static GameDetailsDialog newInstance(String gamePath)
|
||||||
{
|
{
|
||||||
GameDetailsDialog fragment = new GameDetailsDialog();
|
GameDetailsDialog fragment = new GameDetailsDialog();
|
||||||
|
|
||||||
Bundle arguments = new Bundle();
|
Bundle arguments = new Bundle();
|
||||||
arguments.putString(ARG_GAME_PATH, gamePath);
|
arguments.putString(ARG_GAME_PATH, gamePath);
|
||||||
fragment.setArguments(arguments);
|
fragment.setArguments(arguments);
|
||||||
|
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState)
|
public Dialog onCreateDialog(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
GameFile gameFile = GameFileCacheService.addOrGet(getArguments().getString(ARG_GAME_PATH));
|
GameFile gameFile = GameFileCacheService.addOrGet(getArguments().getString(ARG_GAME_PATH));
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater().inflate(R.layout.dialog_game_details, null);
|
ViewGroup contents = (ViewGroup) getActivity().getLayoutInflater()
|
||||||
|
.inflate(R.layout.dialog_game_details, null);
|
||||||
|
|
||||||
final ImageView imageGameScreen = contents.findViewById(R.id.image_game_screen);
|
final ImageView imageGameScreen = contents.findViewById(R.id.image_game_screen);
|
||||||
CircleImageView circleBanner = contents.findViewById(R.id.circle_banner);
|
CircleImageView circleBanner = contents.findViewById(R.id.circle_banner);
|
||||||
|
|
||||||
TextView textTitle = contents.findViewById(R.id.text_game_title);
|
TextView textTitle = contents.findViewById(R.id.text_game_title);
|
||||||
TextView textDescription = contents.findViewById(R.id.text_description);
|
TextView textDescription = contents.findViewById(R.id.text_description);
|
||||||
|
|
||||||
TextView textCountry = contents.findViewById(R.id.text_country);
|
TextView textCountry = contents.findViewById(R.id.text_country);
|
||||||
TextView textCompany = contents.findViewById(R.id.text_company);
|
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());
|
textTitle.setText(gameFile.getTitle());
|
||||||
textDescription.setText(gameFile.getDescription());
|
textDescription.setText(gameFile.getDescription());
|
||||||
textCountry.setText(country);
|
textCountry.setText(country);
|
||||||
textCompany.setText(gameFile.getCompany());
|
textCompany.setText(gameFile.getCompany());
|
||||||
|
|
||||||
buttonLaunch.setOnClickListener(view ->
|
buttonLaunch.setOnClickListener(view ->
|
||||||
{
|
{
|
||||||
// Start the emulation activity and send the path of the clicked ROM to it.
|
// Start the emulation activity and send the path of the clicked ROM to it.
|
||||||
EmulationActivity.launch(getActivity(), gameFile, -1, imageGameScreen);
|
EmulationActivity.launch(getActivity(), gameFile, -1, imageGameScreen);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fill in the view contents.
|
// Fill in the view contents.
|
||||||
Picasso.with(imageGameScreen.getContext())
|
Picasso.with(imageGameScreen.getContext())
|
||||||
.load(getArguments().getString(gameFile.getScreenshotPath()))
|
.load(getArguments().getString(gameFile.getScreenshotPath()))
|
||||||
.fit()
|
.fit()
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.noFade()
|
.noFade()
|
||||||
.noPlaceholder()
|
.noPlaceholder()
|
||||||
.into(imageGameScreen);
|
.into(imageGameScreen);
|
||||||
|
|
||||||
circleBanner.setImageResource(R.drawable.no_banner);
|
circleBanner.setImageResource(R.drawable.no_banner);
|
||||||
|
|
||||||
builder.setView(contents);
|
builder.setView(contents);
|
||||||
return builder.create();
|
return builder.create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,205 +22,209 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public final class MotionAlertDialog extends AlertDialog
|
public final class MotionAlertDialog extends AlertDialog
|
||||||
{
|
{
|
||||||
// The selected input preference
|
// The selected input preference
|
||||||
private final InputBindingSetting setting;
|
private final InputBindingSetting setting;
|
||||||
private final ArrayList<Float> mPreviousValues = new ArrayList<>();
|
private final ArrayList<Float> mPreviousValues = new ArrayList<>();
|
||||||
private int mPrevDeviceId = 0;
|
private int mPrevDeviceId = 0;
|
||||||
private boolean mWaitingForEvent = true;
|
private boolean mWaitingForEvent = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param context The current {@link Context}.
|
* @param context The current {@link Context}.
|
||||||
* @param setting The Preference to show this dialog for.
|
* @param setting The Preference to show this dialog for.
|
||||||
*/
|
*/
|
||||||
public MotionAlertDialog(Context context, InputBindingSetting setting)
|
public MotionAlertDialog(Context context, InputBindingSetting setting)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
this.setting = setting;
|
this.setting = setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onKeyEvent(int keyCode, KeyEvent event)
|
public boolean onKeyEvent(int keyCode, KeyEvent event)
|
||||||
{
|
{
|
||||||
Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
|
Log.debug("[MotionAlertDialog] Received key event: " + event.getAction());
|
||||||
switch (event.getAction())
|
switch (event.getAction())
|
||||||
{
|
{
|
||||||
case KeyEvent.ACTION_UP:
|
case KeyEvent.ACTION_UP:
|
||||||
if (!ControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode))
|
if (!ControllerMappingHelper.shouldKeyBeIgnored(event.getDevice(), keyCode))
|
||||||
{
|
{
|
||||||
saveKeyInput(event);
|
saveKeyInput(event);
|
||||||
}
|
}
|
||||||
// Even if we ignore the key, we still consume it. Thus return true regardless.
|
// Even if we ignore the key, we still consume it. Thus return true regardless.
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyLongPress(int keyCode, KeyEvent event)
|
public boolean onKeyLongPress(int keyCode, KeyEvent event)
|
||||||
{
|
{
|
||||||
// Option to clear by long back is only needed on the TV interface
|
// Option to clear by long back is only needed on the TV interface
|
||||||
if (TvUtil.isLeanback(getContext()))
|
if (TvUtil.isLeanback(getContext()))
|
||||||
{
|
{
|
||||||
if (keyCode == KeyEvent.KEYCODE_BACK)
|
if (keyCode == KeyEvent.KEYCODE_BACK)
|
||||||
{
|
{
|
||||||
clearBinding();
|
clearBinding();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return super.onKeyLongPress(keyCode, event);
|
return super.onKeyLongPress(keyCode, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dispatchKeyEvent(KeyEvent event)
|
public boolean dispatchKeyEvent(KeyEvent event)
|
||||||
{
|
{
|
||||||
// Handle this key if we care about it, otherwise pass it down the framework
|
// Handle this key if we care about it, otherwise pass it down the framework
|
||||||
return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event);
|
return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dispatchGenericMotionEvent(MotionEvent event)
|
public boolean dispatchGenericMotionEvent(MotionEvent event)
|
||||||
{
|
{
|
||||||
// Handle this event if we care about it, otherwise pass it down the framework
|
// Handle this event if we care about it, otherwise pass it down the framework
|
||||||
return onMotionEvent(event) || super.dispatchGenericMotionEvent(event);
|
return onMotionEvent(event) || super.dispatchGenericMotionEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean onMotionEvent(MotionEvent event)
|
private boolean onMotionEvent(MotionEvent event)
|
||||||
{
|
{
|
||||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
|
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
|
||||||
return false;
|
return false;
|
||||||
if (event.getAction() != MotionEvent.ACTION_MOVE)
|
if (event.getAction() != MotionEvent.ACTION_MOVE)
|
||||||
return false;
|
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)
|
if (input.getId() != mPrevDeviceId)
|
||||||
{
|
{
|
||||||
mPreviousValues.clear();
|
mPreviousValues.clear();
|
||||||
}
|
}
|
||||||
mPrevDeviceId = input.getId();
|
mPrevDeviceId = input.getId();
|
||||||
boolean firstEvent = mPreviousValues.isEmpty();
|
boolean firstEvent = mPreviousValues.isEmpty();
|
||||||
|
|
||||||
int numMovedAxis = 0;
|
int numMovedAxis = 0;
|
||||||
float axisMoveValue = 0.0f;
|
float axisMoveValue = 0.0f;
|
||||||
InputDevice.MotionRange lastMovedRange = null;
|
InputDevice.MotionRange lastMovedRange = null;
|
||||||
char lastMovedDir = '?';
|
char lastMovedDir = '?';
|
||||||
if (mWaitingForEvent)
|
if (mWaitingForEvent)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < motionRanges.size(); i++)
|
for (int i = 0; i < motionRanges.size(); i++)
|
||||||
{
|
{
|
||||||
InputDevice.MotionRange range = motionRanges.get(i);
|
InputDevice.MotionRange range = motionRanges.get(i);
|
||||||
int axis = range.getAxis();
|
int axis = range.getAxis();
|
||||||
float origValue = event.getAxisValue(axis);
|
float origValue = event.getAxisValue(axis);
|
||||||
float value = ControllerMappingHelper.scaleAxis(input, axis, origValue);
|
float value = ControllerMappingHelper.scaleAxis(input, axis, origValue);
|
||||||
if (firstEvent)
|
if (firstEvent)
|
||||||
{
|
{
|
||||||
mPreviousValues.add(value);
|
mPreviousValues.add(value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float previousValue = mPreviousValues.get(i);
|
float previousValue = mPreviousValues.get(i);
|
||||||
|
|
||||||
// Only handle the axes that are not neutral (more than 0.5)
|
// 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)
|
// but ignore any axis that has a constant value (e.g. always 1)
|
||||||
if (Math.abs(value) > 0.5f && value != previousValue)
|
if (Math.abs(value) > 0.5f && value != previousValue)
|
||||||
{
|
{
|
||||||
// It is common to have multiple axes with the same physical input. For example,
|
// 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.
|
// 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
|
// 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
|
// we already saw. This way, we ignore axes with two names, but catch the case
|
||||||
// where a joystick is moved in two directions.
|
// where a joystick is moved in two directions.
|
||||||
// ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html
|
// ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html
|
||||||
if (value != axisMoveValue)
|
if (value != axisMoveValue)
|
||||||
{
|
{
|
||||||
axisMoveValue = value;
|
axisMoveValue = value;
|
||||||
numMovedAxis++;
|
numMovedAxis++;
|
||||||
lastMovedRange = range;
|
lastMovedRange = range;
|
||||||
lastMovedDir = value < 0.0f ? '-' : '+';
|
lastMovedDir = value < 0.0f ? '-' : '+';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Special case for d-pads (axis value jumps between 0 and 1 without any values
|
// 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
|
// 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.
|
// 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)
|
else if (Math.abs(value) < 0.25f && Math.abs(previousValue) > 0.75f)
|
||||||
{
|
{
|
||||||
numMovedAxis++;
|
numMovedAxis++;
|
||||||
lastMovedRange = range;
|
lastMovedRange = range;
|
||||||
lastMovedDir = previousValue < 0.0f ? '-' : '+';
|
lastMovedDir = previousValue < 0.0f ? '-' : '+';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mPreviousValues.set(i, value);
|
mPreviousValues.set(i, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If only one axis moved, that's the winner.
|
// If only one axis moved, that's the winner.
|
||||||
if (numMovedAxis == 1)
|
if (numMovedAxis == 1)
|
||||||
{
|
{
|
||||||
mWaitingForEvent = false;
|
mWaitingForEvent = false;
|
||||||
saveMotionInput(input, lastMovedRange, lastMovedDir);
|
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
|
* 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.)
|
* an Android preference (so it persists correctly and is human-readable.)
|
||||||
*
|
*
|
||||||
* @param keyEvent KeyEvent of this key press.
|
* @param keyEvent KeyEvent of this key press.
|
||||||
*/
|
*/
|
||||||
private void saveKeyInput(KeyEvent keyEvent)
|
private void saveKeyInput(KeyEvent keyEvent)
|
||||||
{
|
{
|
||||||
InputDevice device = keyEvent.getDevice();
|
InputDevice device = keyEvent.getDevice();
|
||||||
String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode();
|
String bindStr = "Device '" + device.getDescriptor() + "'-Button " + keyEvent.getKeyCode();
|
||||||
String uiString = device.getName() + ": 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
|
* 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.)
|
* an Android preference (so it persists correctly and is human-readable.)
|
||||||
*
|
*
|
||||||
* @param device InputDevice from which the input event originated.
|
* @param device InputDevice from which the input event originated.
|
||||||
* @param motionRange MotionRange of the movement
|
* @param motionRange MotionRange of the movement
|
||||||
* @param axisDir Either '-' or '+'
|
* @param axisDir Either '-' or '+'
|
||||||
*/
|
*/
|
||||||
private void saveMotionInput(InputDevice device, InputDevice.MotionRange motionRange, char axisDir)
|
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;
|
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)
|
* Save the input string to settings and SharedPreferences, then dismiss this Dialog.
|
||||||
{
|
*/
|
||||||
setting.setValue(bind);
|
private void saveInput(String bind, String ui)
|
||||||
|
{
|
||||||
|
setting.setValue(bind);
|
||||||
|
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
|
||||||
editor.putString(setting.getKey(), ui);
|
editor.putString(setting.getKey(), ui);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
|
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearBinding()
|
private void clearBinding()
|
||||||
{
|
{
|
||||||
setting.setValue("");
|
setting.setValue("");
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
editor.remove(setting.getKey());
|
editor.remove(setting.getKey());
|
||||||
editor.apply();
|
editor.apply();
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,27 @@ package org.dolphinemu.dolphinemu.features.settings.model;
|
||||||
|
|
||||||
public final class BooleanSetting extends Setting
|
public final class BooleanSetting extends Setting
|
||||||
{
|
{
|
||||||
private boolean mValue;
|
private boolean mValue;
|
||||||
|
|
||||||
public BooleanSetting(String key, String section, boolean value)
|
public BooleanSetting(String key, String section, boolean value)
|
||||||
{
|
{
|
||||||
super(key, section);
|
super(key, section);
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getValue()
|
public boolean getValue()
|
||||||
{
|
{
|
||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(boolean value)
|
public void setValue(boolean value)
|
||||||
{
|
{
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValueAsString()
|
public String getValueAsString()
|
||||||
{
|
{
|
||||||
return mValue ? "True" : "False";
|
return mValue ? "True" : "False";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,27 @@ package org.dolphinemu.dolphinemu.features.settings.model;
|
||||||
|
|
||||||
public final class FloatSetting extends Setting
|
public final class FloatSetting extends Setting
|
||||||
{
|
{
|
||||||
private float mValue;
|
private float mValue;
|
||||||
|
|
||||||
public FloatSetting(String key, String section, float value)
|
public FloatSetting(String key, String section, float value)
|
||||||
{
|
{
|
||||||
super(key, section);
|
super(key, section);
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getValue()
|
public float getValue()
|
||||||
{
|
{
|
||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(float value)
|
public void setValue(float value)
|
||||||
{
|
{
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValueAsString()
|
public String getValueAsString()
|
||||||
{
|
{
|
||||||
return Float.toString(mValue);
|
return Float.toString(mValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,41 +4,41 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
||||||
|
|
||||||
public final class IntSetting extends Setting
|
public final class IntSetting extends Setting
|
||||||
{
|
{
|
||||||
private int mValue;
|
private int mValue;
|
||||||
private MenuTag menuTag;
|
private MenuTag menuTag;
|
||||||
|
|
||||||
public IntSetting(String key, String section, int value)
|
public IntSetting(String key, String section, int value)
|
||||||
{
|
{
|
||||||
super(key, section);
|
super(key, section);
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IntSetting(String key, String section, int value, MenuTag menuTag)
|
public IntSetting(String key, String section, int value, MenuTag menuTag)
|
||||||
{
|
{
|
||||||
super(key, section);
|
super(key, section);
|
||||||
mValue = value;
|
mValue = value;
|
||||||
this.menuTag = menuTag;
|
this.menuTag = menuTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getValue()
|
public int getValue()
|
||||||
{
|
{
|
||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(int value)
|
public void setValue(int value)
|
||||||
{
|
{
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValueAsString()
|
public String getValueAsString()
|
||||||
{
|
{
|
||||||
return Integer.toString(mValue);
|
return Integer.toString(mValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MenuTag getMenuTag()
|
public MenuTag getMenuTag()
|
||||||
{
|
{
|
||||||
return menuTag;
|
return menuTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,42 +8,40 @@ package org.dolphinemu.dolphinemu.features.settings.model;
|
||||||
*/
|
*/
|
||||||
public abstract class Setting
|
public abstract class Setting
|
||||||
{
|
{
|
||||||
private String mKey;
|
private String mKey;
|
||||||
private String mSection;
|
private String mSection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base constructor.
|
* Base constructor.
|
||||||
*
|
*
|
||||||
* @param key Everything to the left of the = in a line from the ini file.
|
* @param key Everything to the left of the = in a line from the ini file.
|
||||||
* @param section The corresponding recent section header; e.g. [Core] or [Enhancements] without the brackets.
|
* @param section The corresponding recent section header; e.g. [Core] or [Enhancements] without the brackets.
|
||||||
*/
|
*/
|
||||||
public Setting(String key, String section)
|
public Setting(String key, String section)
|
||||||
{
|
{
|
||||||
mKey = key;
|
mKey = key;
|
||||||
mSection = section;
|
mSection = section;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return The identifier used to write this setting to the ini file.
|
||||||
* @return The identifier used to write this setting to the ini file.
|
*/
|
||||||
*/
|
public String getKey()
|
||||||
public String getKey()
|
{
|
||||||
{
|
return mKey;
|
||||||
return mKey;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return The name of the header under which this Setting should be written in the ini file.
|
||||||
* @return The name of the header under which this Setting should be written in the ini file.
|
*/
|
||||||
*/
|
public String getSection()
|
||||||
public String getSection()
|
{
|
||||||
{
|
return mSection;
|
||||||
return mSection;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A representation of this Setting's backing value converted to a String (e.g. for serialization).
|
* @return A representation of this Setting's backing value converted to a String (e.g. for serialization).
|
||||||
*/
|
*/
|
||||||
public abstract String getValueAsString();
|
public abstract String getValueAsString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,56 +8,56 @@ import java.util.HashMap;
|
||||||
*/
|
*/
|
||||||
public final class SettingSection
|
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.
|
* Create a new SettingSection with no Settings in it.
|
||||||
*
|
*
|
||||||
* @param name The header of this section; e.g. [Core] or [Enhancements] without the brackets.
|
* @param name The header of this section; e.g. [Core] or [Enhancements] without the brackets.
|
||||||
*/
|
*/
|
||||||
public SettingSection(String name)
|
public SettingSection(String name)
|
||||||
{
|
{
|
||||||
mName = name;
|
mName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return mName;
|
return mName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method; inserts a value directly into the backing HashMap.
|
* Convenience method; inserts a value directly into the backing HashMap.
|
||||||
*
|
*
|
||||||
* @param setting The Setting to be inserted.
|
* @param setting The Setting to be inserted.
|
||||||
*/
|
*/
|
||||||
public void putSetting(Setting setting)
|
public void putSetting(Setting setting)
|
||||||
{
|
{
|
||||||
mSettings.put(setting.getKey(), setting);
|
mSettings.put(setting.getKey(), setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method; gets a value directly from the backing HashMap.
|
* Convenience method; gets a value directly from the backing HashMap.
|
||||||
*
|
*
|
||||||
* @param key Used to retrieve the Setting.
|
* @param key Used to retrieve the Setting.
|
||||||
* @return A Setting object (you should probably cast this before using)
|
* @return A Setting object (you should probably cast this before using)
|
||||||
*/
|
*/
|
||||||
public Setting getSetting(String key)
|
public Setting getSetting(String key)
|
||||||
{
|
{
|
||||||
return mSettings.get(key);
|
return mSettings.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public HashMap<String, Setting> getSettings()
|
public HashMap<String, Setting> getSettings()
|
||||||
{
|
{
|
||||||
return mSettings;
|
return mSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void mergeSection(SettingSection settingSection)
|
public void mergeSection(SettingSection settingSection)
|
||||||
{
|
{
|
||||||
for (Setting setting : settingSection.mSettings.values())
|
for (Setting setting : settingSection.mSettings.values())
|
||||||
{
|
{
|
||||||
putSetting(setting);
|
putSetting(setting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,168 +14,174 @@ import java.util.TreeMap;
|
||||||
|
|
||||||
public class Settings
|
public class Settings
|
||||||
{
|
{
|
||||||
public static final String SECTION_INI_CORE = "Core";
|
public static final String SECTION_INI_CORE = "Core";
|
||||||
public static final String SECTION_INI_INTERFACE = "Interface";
|
public static final String SECTION_INI_INTERFACE = "Interface";
|
||||||
|
|
||||||
public static final String SECTION_GFX_SETTINGS = "Settings";
|
public static final String SECTION_GFX_SETTINGS = "Settings";
|
||||||
public static final String SECTION_GFX_ENHANCEMENTS = "Enhancements";
|
public static final String SECTION_GFX_ENHANCEMENTS = "Enhancements";
|
||||||
public static final String SECTION_GFX_HACKS = "Hacks";
|
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));
|
if (!(key instanceof String))
|
||||||
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));
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
loadDolphinSettings(view, filesToExclude);
|
||||||
* A HashMap<String, SettingSection> that constructs a new SettingSection instead of returning null
|
|
||||||
* when getting a key not already in the map
|
if (!TextUtils.isEmpty(gameId))
|
||||||
*/
|
|
||||||
public static final class SettingsSectionMap extends HashMap<String, SettingSection>
|
|
||||||
{
|
{
|
||||||
@Override
|
loadGenericGameSettings(gameId, view);
|
||||||
public SettingSection get(Object key)
|
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))
|
iniSections.put(section, sections.get(section));
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDolphinSettings(view, filesToExclude);
|
SettingsFile.saveFile(fileName, iniSections, view);
|
||||||
|
}
|
||||||
if (!TextUtils.isEmpty(gameId))
|
|
||||||
{
|
|
||||||
loadGenericGameSettings(gameId, view);
|
|
||||||
loadCustomGameSettings(gameId, view);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
private void loadDolphinSettings(SettingsActivityView view, HashSet<String> filesToExclude)
|
|
||||||
{
|
{
|
||||||
for (Map.Entry<String, List<String>> entry : configFileSectionsMap.entrySet())
|
// custom game settings
|
||||||
{
|
view.showToastMessage("Saved settings for " + gameId);
|
||||||
String fileName = entry.getKey();
|
SettingsFile.saveCustomGameSettings(gameId, sections);
|
||||||
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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,27 +2,27 @@ package org.dolphinemu.dolphinemu.features.settings.model;
|
||||||
|
|
||||||
public final class StringSetting extends Setting
|
public final class StringSetting extends Setting
|
||||||
{
|
{
|
||||||
private String mValue;
|
private String mValue;
|
||||||
|
|
||||||
public StringSetting(String key, String section, String value)
|
public StringSetting(String key, String section, String value)
|
||||||
{
|
{
|
||||||
super(key, section);
|
super(key, section);
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue()
|
public String getValue()
|
||||||
{
|
{
|
||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(String value)
|
public void setValue(String value)
|
||||||
{
|
{
|
||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getValueAsString()
|
public String getValueAsString()
|
||||||
{
|
{
|
||||||
return mValue;
|
return mValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,51 +5,52 @@ import org.dolphinemu.dolphinemu.features.settings.model.Setting;
|
||||||
|
|
||||||
public final class CheckBoxSetting extends SettingsItem
|
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)
|
public CheckBoxSetting(String key, String section, int titleId, int descriptionId,
|
||||||
{
|
boolean defaultValue, Setting setting)
|
||||||
super(key, section, setting, titleId, descriptionId);
|
{
|
||||||
mDefaultValue = defaultValue;
|
super(key, section, setting, titleId, descriptionId);
|
||||||
}
|
mDefaultValue = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isChecked()
|
public boolean isChecked()
|
||||||
{
|
{
|
||||||
if (getSetting() == null)
|
if (getSetting() == null)
|
||||||
{
|
{
|
||||||
return mDefaultValue;
|
return mDefaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BooleanSetting setting = (BooleanSetting) getSetting();
|
BooleanSetting setting = (BooleanSetting) getSetting();
|
||||||
return setting.getValue();
|
return setting.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a value to the backing boolean. If that boolean was previously 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.
|
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||||
*
|
*
|
||||||
* @param checked Pretty self explanatory.
|
* @param checked Pretty self explanatory.
|
||||||
* @return null if overwritten successfully; otherwise, a newly created BooleanSetting.
|
* @return null if overwritten successfully; otherwise, a newly created BooleanSetting.
|
||||||
*/
|
*/
|
||||||
public BooleanSetting setChecked(boolean checked)
|
public BooleanSetting setChecked(boolean checked)
|
||||||
{
|
{
|
||||||
if (getSetting() == null)
|
if (getSetting() == null)
|
||||||
{
|
{
|
||||||
BooleanSetting setting = new BooleanSetting(getKey(), getSection(), checked);
|
BooleanSetting setting = new BooleanSetting(getKey(), getSection(), checked);
|
||||||
setSetting(setting);
|
setSetting(setting);
|
||||||
return setting;
|
return setting;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
BooleanSetting setting = (BooleanSetting) getSetting();
|
BooleanSetting setting = (BooleanSetting) getSetting();
|
||||||
setting.setValue(checked);
|
setting.setValue(checked);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType()
|
public int getType()
|
||||||
{
|
{
|
||||||
return TYPE_CHECKBOX;
|
return TYPE_CHECKBOX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,14 @@ import org.dolphinemu.dolphinemu.features.settings.model.Setting;
|
||||||
|
|
||||||
public final class HeaderSetting extends SettingsItem
|
public final class HeaderSetting extends SettingsItem
|
||||||
{
|
{
|
||||||
public HeaderSetting(String key, Setting setting, int titleId, int descriptionId)
|
public HeaderSetting(String key, Setting setting, int titleId, int descriptionId)
|
||||||
{
|
{
|
||||||
super(key, null, setting, titleId, descriptionId);
|
super(key, null, setting, titleId, descriptionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType()
|
public int getType()
|
||||||
{
|
{
|
||||||
return SettingsItem.TYPE_HEADER;
|
return SettingsItem.TYPE_HEADER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,48 +5,48 @@ import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
|
||||||
|
|
||||||
public final class InputBindingSetting extends SettingsItem
|
public final class InputBindingSetting extends SettingsItem
|
||||||
{
|
{
|
||||||
public InputBindingSetting(String key, String section, int titleId, Setting setting)
|
public InputBindingSetting(String key, String section, int titleId, Setting setting)
|
||||||
{
|
{
|
||||||
super(key, section, setting, titleId, 0);
|
super(key, section, setting, titleId, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getValue()
|
public String getValue()
|
||||||
{
|
{
|
||||||
if (getSetting() == null)
|
if (getSetting() == null)
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSetting setting = (StringSetting) getSetting();
|
StringSetting setting = (StringSetting) getSetting();
|
||||||
return setting.getValue();
|
return setting.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a value to the backing string. If that string was previously 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.
|
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||||
*
|
*
|
||||||
* @param bind The input that will be bound
|
* @param bind The input that will be bound
|
||||||
* @return null if overwritten successfully; otherwise, a newly created StringSetting.
|
* @return null if overwritten successfully; otherwise, a newly created StringSetting.
|
||||||
*/
|
*/
|
||||||
public StringSetting setValue(String bind)
|
public StringSetting setValue(String bind)
|
||||||
{
|
{
|
||||||
if (getSetting() == null)
|
if (getSetting() == null)
|
||||||
{
|
{
|
||||||
StringSetting setting = new StringSetting(getKey(), getSection(), bind);
|
StringSetting setting = new StringSetting(getKey(), getSection(), bind);
|
||||||
setSetting(setting);
|
setSetting(setting);
|
||||||
return setting;
|
return setting;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
StringSetting setting = (StringSetting) getSetting();
|
StringSetting setting = (StringSetting) getSetting();
|
||||||
setting.setValue(bind);
|
setting.setValue(bind);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType()
|
public int getType()
|
||||||
{
|
{
|
||||||
return TYPE_INPUT_BINDING;
|
return TYPE_INPUT_BINDING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package org.dolphinemu.dolphinemu.features.settings.model.view;
|
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.model.Setting;
|
||||||
|
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ViewModel abstraction for an Item in the RecyclerView powering SettingsFragments.
|
* 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 abstract class SettingsItem
|
||||||
{
|
{
|
||||||
public static final int TYPE_HEADER = 0;
|
public static final int TYPE_HEADER = 0;
|
||||||
public static final int TYPE_CHECKBOX = 1;
|
public static final int TYPE_CHECKBOX = 1;
|
||||||
public static final int TYPE_SINGLE_CHOICE = 2;
|
public static final int TYPE_SINGLE_CHOICE = 2;
|
||||||
public static final int TYPE_SLIDER = 3;
|
public static final int TYPE_SLIDER = 3;
|
||||||
public static final int TYPE_SUBMENU = 4;
|
public static final int TYPE_SUBMENU = 4;
|
||||||
public static final int TYPE_INPUT_BINDING = 5;
|
public static final int TYPE_INPUT_BINDING = 5;
|
||||||
public static final int TYPE_STRING_SINGLE_CHOICE = 6;
|
public static final int TYPE_STRING_SINGLE_CHOICE = 6;
|
||||||
|
|
||||||
private String mKey;
|
private String mKey;
|
||||||
private String mSection;
|
private String mSection;
|
||||||
|
|
||||||
private Setting mSetting;
|
private Setting mSetting;
|
||||||
|
|
||||||
private int mNameId;
|
private int mNameId;
|
||||||
private int mDescriptionId;
|
private int mDescriptionId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base constructor. Takes a key / section name in case the third parameter, the Setting,
|
* 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.
|
* 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 key Identifier for the Setting represented by this Item.
|
||||||
* @param section Section to which the Setting belongs.
|
* @param section Section to which the Setting belongs.
|
||||||
* @param setting A possibly-null backing Setting, to be modified on UI events.
|
* @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 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.
|
* @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)
|
public SettingsItem(String key, String section, Setting setting, int nameId, int descriptionId)
|
||||||
{
|
{
|
||||||
mKey = key;
|
mKey = key;
|
||||||
mSection = section;
|
mSection = section;
|
||||||
mSetting = setting;
|
mSetting = setting;
|
||||||
mNameId = nameId;
|
mNameId = nameId;
|
||||||
mDescriptionId = descriptionId;
|
mDescriptionId = descriptionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return The identifier for the backing Setting.
|
||||||
* @return The identifier for the backing Setting.
|
*/
|
||||||
*/
|
public String getKey()
|
||||||
public String getKey()
|
{
|
||||||
{
|
return mKey;
|
||||||
return mKey;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return The header under which the backing Setting belongs.
|
||||||
* @return The header under which the backing Setting belongs.
|
*/
|
||||||
*/
|
public String getSection()
|
||||||
public String getSection()
|
{
|
||||||
{
|
return mSection;
|
||||||
return mSection;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return The backing Setting, possibly null.
|
||||||
* @return The backing Setting, possibly null.
|
*/
|
||||||
*/
|
public Setting getSetting()
|
||||||
public Setting getSetting()
|
{
|
||||||
{
|
return mSetting;
|
||||||
return mSetting;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace the backing setting with a new one. Generally used in cases where
|
* Replace the backing setting with a new one. Generally used in cases where
|
||||||
* the backing setting is null.
|
* the backing setting is null.
|
||||||
*
|
*
|
||||||
* @param setting A non-null Setting.
|
* @param setting A non-null Setting.
|
||||||
*/
|
*/
|
||||||
public void setSetting(Setting setting)
|
public void setSetting(Setting setting)
|
||||||
{
|
{
|
||||||
mSetting = setting;
|
mSetting = setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @return A resource ID for a text string representing this Setting's name.
|
||||||
* @return A resource ID for a text string representing this Setting's name.
|
*/
|
||||||
*/
|
public int getNameId()
|
||||||
public int getNameId()
|
{
|
||||||
{
|
return mNameId;
|
||||||
return mNameId;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int getDescriptionId()
|
public int getDescriptionId()
|
||||||
{
|
{
|
||||||
return mDescriptionId;
|
return mDescriptionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by {@link SettingsAdapter}'s onCreateViewHolder()
|
* Used by {@link SettingsAdapter}'s onCreateViewHolder()
|
||||||
* method to determine which type of ViewHolder should be created.
|
* method to determine which type of ViewHolder should be created.
|
||||||
*
|
*
|
||||||
* @return An integer (ideally, one of the constants defined in this file)
|
* @return An integer (ideally, one of the constants defined in this file)
|
||||||
*/
|
*/
|
||||||
public abstract int getType();
|
public abstract int getType();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,80 +6,82 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
||||||
|
|
||||||
public final class SingleChoiceSetting extends SettingsItem
|
public final class SingleChoiceSetting extends SettingsItem
|
||||||
{
|
{
|
||||||
private int mDefaultValue;
|
private int mDefaultValue;
|
||||||
|
|
||||||
private int mChoicesId;
|
private int mChoicesId;
|
||||||
private int mValuesId;
|
private int mValuesId;
|
||||||
private MenuTag menuTag;
|
private MenuTag menuTag;
|
||||||
|
|
||||||
public SingleChoiceSetting(String key, String section, int titleId, int descriptionId, int choicesId, int valuesId, int defaultValue, Setting setting, 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;
|
super(key, section, setting, titleId, descriptionId);
|
||||||
mChoicesId = choicesId;
|
mValuesId = valuesId;
|
||||||
mDefaultValue = defaultValue;
|
mChoicesId = choicesId;
|
||||||
this.menuTag = menuTag;
|
mDefaultValue = defaultValue;
|
||||||
}
|
this.menuTag = menuTag;
|
||||||
|
}
|
||||||
|
|
||||||
public SingleChoiceSetting(String key, String section, int titleId, int descriptionId, int choicesId, int valuesId, int defaultValue, Setting setting)
|
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);
|
{
|
||||||
}
|
this(key, section, titleId, descriptionId, choicesId, valuesId, defaultValue, setting, null);
|
||||||
|
}
|
||||||
|
|
||||||
public int getChoicesId()
|
public int getChoicesId()
|
||||||
{
|
{
|
||||||
return mChoicesId;
|
return mChoicesId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getValuesId()
|
public int getValuesId()
|
||||||
{
|
{
|
||||||
return mValuesId;
|
return mValuesId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSelectedValue()
|
public int getSelectedValue()
|
||||||
{
|
{
|
||||||
if (getSetting() != null)
|
if (getSetting() != null)
|
||||||
{
|
{
|
||||||
IntSetting setting = (IntSetting) getSetting();
|
IntSetting setting = (IntSetting) getSetting();
|
||||||
return setting.getValue();
|
return setting.getValue();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return mDefaultValue;
|
return mDefaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MenuTag getMenuTag()
|
public MenuTag getMenuTag()
|
||||||
{
|
{
|
||||||
return menuTag;
|
return menuTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a value to the backing int. If that int was previously 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.
|
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||||
*
|
*
|
||||||
* @param selection New value of the int.
|
* @param selection New value of the int.
|
||||||
* @return null if overwritten successfully otherwise; a newly created IntSetting.
|
* @return null if overwritten successfully otherwise; a newly created IntSetting.
|
||||||
*/
|
*/
|
||||||
public IntSetting setSelectedValue(int selection)
|
public IntSetting setSelectedValue(int selection)
|
||||||
{
|
{
|
||||||
if (getSetting() == null)
|
if (getSetting() == null)
|
||||||
{
|
{
|
||||||
IntSetting setting = new IntSetting(getKey(), getSection(), selection);
|
IntSetting setting = new IntSetting(getKey(), getSection(), selection);
|
||||||
setSetting(setting);
|
setSetting(setting);
|
||||||
return setting;
|
return setting;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IntSetting setting = (IntSetting) getSetting();
|
IntSetting setting = (IntSetting) getSetting();
|
||||||
setting.setValue(selection);
|
setting.setValue(selection);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType()
|
public int getType()
|
||||||
{
|
{
|
||||||
return TYPE_SINGLE_CHOICE;
|
return TYPE_SINGLE_CHOICE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.FloatSetting;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
|
import org.dolphinemu.dolphinemu.features.settings.model.IntSetting;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.model.Setting;
|
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.features.settings.utils.SettingsFile;
|
||||||
|
import org.dolphinemu.dolphinemu.utils.Log;
|
||||||
|
|
||||||
public final class SliderSetting extends SettingsItem
|
public final class SliderSetting extends SettingsItem
|
||||||
{
|
{
|
||||||
private int mMax;
|
private int mMax;
|
||||||
private int mDefaultValue;
|
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)
|
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;
|
super(key, section, setting, titleId, descriptionId);
|
||||||
mUnits = units;
|
mMax = max;
|
||||||
mDefaultValue = defaultValue;
|
mUnits = units;
|
||||||
}
|
mDefaultValue = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
public int getMax()
|
public int getMax()
|
||||||
{
|
{
|
||||||
return mMax;
|
return mMax;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSelectedValue()
|
public int getSelectedValue()
|
||||||
{
|
{
|
||||||
Setting setting = getSetting();
|
Setting setting = getSetting();
|
||||||
|
|
||||||
if (setting == null)
|
if (setting == null)
|
||||||
{
|
{
|
||||||
return mDefaultValue;
|
return mDefaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setting instanceof IntSetting)
|
if (setting instanceof IntSetting)
|
||||||
{
|
{
|
||||||
IntSetting intSetting = (IntSetting) setting;
|
IntSetting intSetting = (IntSetting) setting;
|
||||||
return intSetting.getValue();
|
return intSetting.getValue();
|
||||||
}
|
}
|
||||||
else if (setting instanceof FloatSetting)
|
else if (setting instanceof FloatSetting)
|
||||||
{
|
{
|
||||||
FloatSetting floatSetting = (FloatSetting) setting;
|
FloatSetting floatSetting = (FloatSetting) setting;
|
||||||
if (floatSetting.getKey().equals(SettingsFile.KEY_OVERCLOCK_PERCENT)
|
if (floatSetting.getKey().equals(SettingsFile.KEY_OVERCLOCK_PERCENT)
|
||||||
|| floatSetting.getKey().equals(SettingsFile.KEY_SPEED_LIMIT))
|
|| floatSetting.getKey().equals(SettingsFile.KEY_SPEED_LIMIT))
|
||||||
{
|
{
|
||||||
return Math.round(floatSetting.getValue() * 100);
|
return Math.round(floatSetting.getValue() * 100);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Math.round(floatSetting.getValue());
|
return Math.round(floatSetting.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.error("[SliderSetting] Error casting setting type.");
|
Log.error("[SliderSetting] Error casting setting type.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a value to the backing int. If that int was previously 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.
|
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||||
*
|
*
|
||||||
* @param selection New value of the int.
|
* @param selection New value of the int.
|
||||||
* @return null if overwritten successfully otherwise; a newly created IntSetting.
|
* @return null if overwritten successfully otherwise; a newly created IntSetting.
|
||||||
*/
|
*/
|
||||||
public IntSetting setSelectedValue(int selection)
|
public IntSetting setSelectedValue(int selection)
|
||||||
{
|
{
|
||||||
if (getSetting() == null)
|
if (getSetting() == null)
|
||||||
{
|
{
|
||||||
IntSetting setting = new IntSetting(getKey(), getSection(), selection);
|
IntSetting setting = new IntSetting(getKey(), getSection(), selection);
|
||||||
setSetting(setting);
|
setSetting(setting);
|
||||||
return setting;
|
return setting;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IntSetting setting = (IntSetting) getSetting();
|
IntSetting setting = (IntSetting) getSetting();
|
||||||
setting.setValue(selection);
|
setting.setValue(selection);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a value to the backing float. If that float was previously 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.
|
* initializes a new one and returns it, so it can be added to the Hashmap.
|
||||||
*
|
*
|
||||||
* @param selection New value of the float.
|
* @param selection New value of the float.
|
||||||
* @return null if overwritten successfully otherwise; a newly created FloatSetting.
|
* @return null if overwritten successfully otherwise; a newly created FloatSetting.
|
||||||
*/
|
*/
|
||||||
public FloatSetting setSelectedValue(float selection)
|
public FloatSetting setSelectedValue(float selection)
|
||||||
{
|
{
|
||||||
if (getSetting() == null)
|
if (getSetting() == null)
|
||||||
{
|
{
|
||||||
FloatSetting setting = new FloatSetting(getKey(), getSection(), selection);
|
FloatSetting setting = new FloatSetting(getKey(), getSection(), selection);
|
||||||
setSetting(setting);
|
setSetting(setting);
|
||||||
return setting;
|
return setting;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FloatSetting setting = (FloatSetting) getSetting();
|
FloatSetting setting = (FloatSetting) getSetting();
|
||||||
setting.setValue(selection);
|
setting.setValue(selection);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUnits()
|
public String getUnits()
|
||||||
{
|
{
|
||||||
return mUnits;
|
return mUnits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType()
|
public int getType()
|
||||||
{
|
{
|
||||||
return TYPE_SLIDER;
|
return TYPE_SLIDER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,93 +5,98 @@ import org.dolphinemu.dolphinemu.features.settings.model.StringSetting;
|
||||||
|
|
||||||
public class StringSingleChoiceSetting extends SettingsItem
|
public class StringSingleChoiceSetting extends SettingsItem
|
||||||
{
|
{
|
||||||
private String mDefaultValue;
|
private String mDefaultValue;
|
||||||
|
|
||||||
private String[] mChoicesId;
|
private String[] mChoicesId;
|
||||||
private String[] mValuesId;
|
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);
|
return mValuesId[index];
|
||||||
mValuesId = valuesId;
|
|
||||||
mChoicesId = choicesId;
|
|
||||||
mDefaultValue = defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getChoicesId()
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSelectedValue()
|
||||||
|
{
|
||||||
|
if (getSetting() != null)
|
||||||
{
|
{
|
||||||
return mChoicesId;
|
StringSetting setting = (StringSetting) getSetting();
|
||||||
|
return setting.getValue();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public String[] getValuesId()
|
|
||||||
{
|
{
|
||||||
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)
|
if (mValuesId[i].equals(selectedValue))
|
||||||
return null;
|
{
|
||||||
|
return i;
|
||||||
if (index >= 0 && index < mValuesId.length)
|
}
|
||||||
{
|
|
||||||
return mValuesId[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = new StringSetting(getKey(), getSection(), selection);
|
||||||
{
|
setSetting(setting);
|
||||||
StringSetting setting = (StringSetting) getSetting();
|
return setting;
|
||||||
return setting.getValue();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return mDefaultValue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (getSetting() == null)
|
StringSetting setting = (StringSetting) getSetting();
|
||||||
{
|
setting.setValue(selection);
|
||||||
StringSetting setting = new StringSetting(getKey(), getSection(), selection);
|
return null;
|
||||||
setSetting(setting);
|
|
||||||
return setting;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
StringSetting setting = (StringSetting) getSetting();
|
|
||||||
setting.setValue(selection);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType()
|
public int getType()
|
||||||
{
|
{
|
||||||
return TYPE_STRING_SINGLE_CHOICE;
|
return TYPE_STRING_SINGLE_CHOICE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,22 +5,23 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
||||||
|
|
||||||
public final class SubmenuSetting extends SettingsItem
|
public final class SubmenuSetting extends SettingsItem
|
||||||
{
|
{
|
||||||
private MenuTag mMenuKey;
|
private MenuTag mMenuKey;
|
||||||
|
|
||||||
public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, MenuTag menuKey)
|
public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId,
|
||||||
{
|
MenuTag menuKey)
|
||||||
super(key, null, setting, titleId, descriptionId);
|
{
|
||||||
mMenuKey = menuKey;
|
super(key, null, setting, titleId, descriptionId);
|
||||||
}
|
mMenuKey = menuKey;
|
||||||
|
}
|
||||||
|
|
||||||
public MenuTag getMenuKey()
|
public MenuTag getMenuKey()
|
||||||
{
|
{
|
||||||
return mMenuKey;
|
return mMenuKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getType()
|
public int getType()
|
||||||
{
|
{
|
||||||
return TYPE_SUBMENU;
|
return TYPE_SUBMENU;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,105 +2,105 @@ package org.dolphinemu.dolphinemu.features.settings.ui;
|
||||||
|
|
||||||
public enum MenuTag
|
public enum MenuTag
|
||||||
{
|
{
|
||||||
CONFIG("config"),
|
CONFIG("config"),
|
||||||
CONFIG_GENERAL("config_general"),
|
CONFIG_GENERAL("config_general"),
|
||||||
CONFIG_INTERFACE("config_interface"),
|
CONFIG_INTERFACE("config_interface"),
|
||||||
CONFIG_GAME_CUBE("config_gamecube"),
|
CONFIG_GAME_CUBE("config_gamecube"),
|
||||||
CONFIG_WII("config_wii"),
|
CONFIG_WII("config_wii"),
|
||||||
WIIMOTE("wiimote"),
|
WIIMOTE("wiimote"),
|
||||||
WIIMOTE_EXTENSION("wiimote_extension"),
|
WIIMOTE_EXTENSION("wiimote_extension"),
|
||||||
GCPAD_TYPE("gc_pad_type"),
|
GCPAD_TYPE("gc_pad_type"),
|
||||||
GRAPHICS("graphics"),
|
GRAPHICS("graphics"),
|
||||||
HACKS("hacks"),
|
HACKS("hacks"),
|
||||||
ENHANCEMENTS("enhancements"),
|
ENHANCEMENTS("enhancements"),
|
||||||
STEREOSCOPY("stereoscopy"),
|
STEREOSCOPY("stereoscopy"),
|
||||||
GCPAD_1("gcpad", 0),
|
GCPAD_1("gcpad", 0),
|
||||||
GCPAD_2("gcpad", 1),
|
GCPAD_2("gcpad", 1),
|
||||||
GCPAD_3("gcpad", 2),
|
GCPAD_3("gcpad", 2),
|
||||||
GCPAD_4("gcpad", 3),
|
GCPAD_4("gcpad", 3),
|
||||||
WIIMOTE_1("wiimote", 4),
|
WIIMOTE_1("wiimote", 4),
|
||||||
WIIMOTE_2("wiimote", 5),
|
WIIMOTE_2("wiimote", 5),
|
||||||
WIIMOTE_3("wiimote", 6),
|
WIIMOTE_3("wiimote", 6),
|
||||||
WIIMOTE_4("wiimote", 7),
|
WIIMOTE_4("wiimote", 7),
|
||||||
WIIMOTE_EXTENSION_1("wiimote_extension", 4),
|
WIIMOTE_EXTENSION_1("wiimote_extension", 4),
|
||||||
WIIMOTE_EXTENSION_2("wiimote_extension", 5),
|
WIIMOTE_EXTENSION_2("wiimote_extension", 5),
|
||||||
WIIMOTE_EXTENSION_3("wiimote_extension", 6),
|
WIIMOTE_EXTENSION_3("wiimote_extension", 6),
|
||||||
WIIMOTE_EXTENSION_4("wiimote_extension", 7);
|
WIIMOTE_EXTENSION_4("wiimote_extension", 7);
|
||||||
|
|
||||||
private String tag;
|
private String tag;
|
||||||
private int subType = -1;
|
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;
|
if (menuTag.tag.equals(tag) && menuTag.subType == subtype) return menuTag;
|
||||||
this.subType = subtype;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
throw new IllegalArgumentException("You are asking for a menu that is not available or " +
|
||||||
public String toString()
|
"passing a wrong subtype");
|
||||||
{
|
}
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,247 +15,248 @@ import android.view.MenuItem;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.model.SettingSection;
|
|
||||||
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
||||||
import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
|
import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView
|
public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView
|
||||||
{
|
{
|
||||||
private static final String ARG_MENU_TAG = "menu_tag";
|
private static final String ARG_MENU_TAG = "menu_tag";
|
||||||
private static final String ARG_GAME_ID = "game_id";
|
private static final String ARG_GAME_ID = "game_id";
|
||||||
private static final String FRAGMENT_TAG = "settings";
|
private static final String FRAGMENT_TAG = "settings";
|
||||||
private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this);
|
private SettingsActivityPresenter mPresenter = new SettingsActivityPresenter(this);
|
||||||
|
|
||||||
private ProgressDialog dialog;
|
private ProgressDialog dialog;
|
||||||
|
|
||||||
public static void launch(Context context, MenuTag menuTag, String gameId)
|
public static void launch(Context context, MenuTag menuTag, String gameId)
|
||||||
{
|
{
|
||||||
Intent settings = new Intent(context, SettingsActivity.class);
|
Intent settings = new Intent(context, SettingsActivity.class);
|
||||||
settings.putExtra(ARG_MENU_TAG, menuTag);
|
settings.putExtra(ARG_MENU_TAG, menuTag);
|
||||||
settings.putExtra(ARG_GAME_ID, gameId);
|
settings.putExtra(ARG_GAME_ID, gameId);
|
||||||
context.startActivity(settings);
|
context.startActivity(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
setContentView(R.layout.activity_settings);
|
setContentView(R.layout.activity_settings);
|
||||||
|
|
||||||
Intent launcher = getIntent();
|
Intent launcher = getIntent();
|
||||||
String gameID = launcher.getStringExtra(ARG_GAME_ID);
|
String gameID = launcher.getStringExtra(ARG_GAME_ID);
|
||||||
MenuTag menuTag = (MenuTag) launcher.getSerializableExtra(ARG_MENU_TAG);
|
MenuTag menuTag = (MenuTag) launcher.getSerializableExtra(ARG_MENU_TAG);
|
||||||
mPresenter.onCreate(savedInstanceState, menuTag, gameID);
|
mPresenter.onCreate(savedInstanceState, menuTag, gameID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu)
|
public boolean onCreateOptionsMenu(Menu menu)
|
||||||
{
|
{
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.menu_settings, menu);
|
inflater.inflate(R.menu.menu_settings, menu);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item)
|
public boolean onOptionsItemSelected(MenuItem item)
|
||||||
{
|
{
|
||||||
return mPresenter.handleOptionsItem(item.getItemId());
|
return mPresenter.handleOptionsItem(item.getItemId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle outState)
|
protected void onSaveInstanceState(Bundle outState)
|
||||||
{
|
{
|
||||||
// Critical: If super method is not called, rotations will be busted.
|
// Critical: If super method is not called, rotations will be busted.
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
mPresenter.saveState(outState);
|
mPresenter.saveState(outState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart()
|
protected void onStart()
|
||||||
{
|
{
|
||||||
super.onStart();
|
super.onStart();
|
||||||
mPresenter.onStart();
|
mPresenter.onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this is called, the user has left the settings screen (potentially through the
|
* If this is called, the user has left the settings screen (potentially through the
|
||||||
* home button) and will expect their changes to be persisted. So we kick off an
|
* home button) and will expect their changes to be persisted. So we kick off an
|
||||||
* IntentService which will do so on a background thread.
|
* IntentService which will do so on a background thread.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void onStop()
|
protected void onStop()
|
||||||
{
|
{
|
||||||
super.onStop();
|
super.onStop();
|
||||||
|
|
||||||
mPresenter.onStop(isFinishing());
|
mPresenter.onStop(isFinishing());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed()
|
public void onBackPressed()
|
||||||
{
|
{
|
||||||
mPresenter.onBackPressed();
|
mPresenter.onBackPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack, String gameID)
|
public void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack,
|
||||||
{
|
String gameID)
|
||||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
{
|
||||||
|
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
|
||||||
|
|
||||||
if (addToStack)
|
if (addToStack)
|
||||||
{
|
{
|
||||||
if (areSystemAnimationsEnabled())
|
if (areSystemAnimationsEnabled())
|
||||||
{
|
{
|
||||||
transaction.setCustomAnimations(
|
transaction.setCustomAnimations(
|
||||||
R.animator.settings_enter,
|
R.animator.settings_enter,
|
||||||
R.animator.settings_exit,
|
R.animator.settings_exit,
|
||||||
R.animator.settings_pop_enter,
|
R.animator.settings_pop_enter,
|
||||||
R.animator.setttings_pop_exit);
|
R.animator.setttings_pop_exit);
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.addToBackStack(null);
|
transaction.addToBackStack(null);
|
||||||
mPresenter.addToStack();
|
mPresenter.addToStack();
|
||||||
}
|
}
|
||||||
transaction.replace(R.id.frame_content, SettingsFragment.newInstance(menuTag, gameID, extras), FRAGMENT_TAG);
|
transaction.replace(R.id.frame_content, SettingsFragment.newInstance(menuTag, gameID, extras),
|
||||||
|
FRAGMENT_TAG);
|
||||||
|
|
||||||
transaction.commit();
|
transaction.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean areSystemAnimationsEnabled()
|
private boolean areSystemAnimationsEnabled()
|
||||||
{
|
{
|
||||||
float duration = Settings.Global.getFloat(
|
float duration = Settings.Global.getFloat(
|
||||||
getContentResolver(),
|
getContentResolver(),
|
||||||
Settings.Global.ANIMATOR_DURATION_SCALE, 1);
|
Settings.Global.ANIMATOR_DURATION_SCALE, 1);
|
||||||
float transition = Settings.Global.getFloat(
|
float transition = Settings.Global.getFloat(
|
||||||
getContentResolver(),
|
getContentResolver(),
|
||||||
Settings.Global.TRANSITION_ANIMATION_SCALE, 1);
|
Settings.Global.TRANSITION_ANIMATION_SCALE, 1);
|
||||||
return duration != 0 && transition != 0;
|
return duration != 0 && transition != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter)
|
public void startDirectoryInitializationService(DirectoryStateReceiver receiver,
|
||||||
{
|
IntentFilter filter)
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(
|
{
|
||||||
receiver,
|
LocalBroadcastManager.getInstance(this).registerReceiver(
|
||||||
filter);
|
receiver,
|
||||||
DirectoryInitializationService.startService(this);
|
filter);
|
||||||
}
|
DirectoryInitializationService.startService(this);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver)
|
public void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver)
|
||||||
{
|
{
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showLoading()
|
public void showLoading()
|
||||||
{
|
{
|
||||||
if (dialog == null)
|
if (dialog == null)
|
||||||
{
|
{
|
||||||
dialog = new ProgressDialog(this);
|
dialog = new ProgressDialog(this);
|
||||||
dialog.setMessage(getString(R.string.load_settings));
|
dialog.setMessage(getString(R.string.load_settings));
|
||||||
dialog.setIndeterminate(true);
|
dialog.setIndeterminate(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hideLoading()
|
public void hideLoading()
|
||||||
{
|
{
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showPermissionNeededHint()
|
public void showPermissionNeededHint()
|
||||||
{
|
{
|
||||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showExternalStorageNotMountedHint()
|
public void showExternalStorageNotMountedHint()
|
||||||
{
|
{
|
||||||
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
|
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public org.dolphinemu.dolphinemu.features.settings.model.Settings getSettings()
|
public org.dolphinemu.dolphinemu.features.settings.model.Settings getSettings()
|
||||||
{
|
{
|
||||||
return mPresenter.getSettings();
|
return mPresenter.getSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSettings(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
|
public void setSettings(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
|
||||||
{
|
{
|
||||||
mPresenter.setSettings(settings);
|
mPresenter.setSettings(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSettingsFileLoaded(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
|
public void onSettingsFileLoaded(
|
||||||
{
|
org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
|
||||||
SettingsFragmentView fragment = getFragment();
|
{
|
||||||
|
SettingsFragmentView fragment = getFragment();
|
||||||
|
|
||||||
if (fragment != null)
|
if (fragment != null)
|
||||||
{
|
{
|
||||||
fragment.onSettingsFileLoaded(settings);
|
fragment.onSettingsFileLoaded(settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSettingsFileNotFound()
|
public void onSettingsFileNotFound()
|
||||||
{
|
{
|
||||||
SettingsFragmentView fragment = getFragment();
|
SettingsFragmentView fragment = getFragment();
|
||||||
|
|
||||||
if (fragment != null)
|
if (fragment != null)
|
||||||
{
|
{
|
||||||
fragment.loadDefaultSettings();
|
fragment.loadDefaultSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showToastMessage(String message)
|
public void showToastMessage(String message)
|
||||||
{
|
{
|
||||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void popBackStack()
|
public void popBackStack()
|
||||||
{
|
{
|
||||||
getSupportFragmentManager().popBackStackImmediate();
|
getSupportFragmentManager().popBackStackImmediate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSettingChanged()
|
public void onSettingChanged()
|
||||||
{
|
{
|
||||||
mPresenter.onSettingChanged();
|
mPresenter.onSettingChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGcPadSettingChanged(MenuTag key, int value)
|
public void onGcPadSettingChanged(MenuTag key, int value)
|
||||||
{
|
{
|
||||||
mPresenter.onGcPadSettingChanged(key, value);
|
mPresenter.onGcPadSettingChanged(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWiimoteSettingChanged(MenuTag section, int value)
|
public void onWiimoteSettingChanged(MenuTag section, int value)
|
||||||
{
|
{
|
||||||
mPresenter.onWiimoteSettingChanged(section, value);
|
mPresenter.onWiimoteSettingChanged(section, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExtensionSettingChanged(MenuTag menuTag, int value)
|
public void onExtensionSettingChanged(MenuTag menuTag, int value)
|
||||||
{
|
{
|
||||||
mPresenter.onExtensionSettingChanged(menuTag, value);
|
mPresenter.onExtensionSettingChanged(menuTag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SettingsFragment getFragment()
|
private SettingsFragment getFragment()
|
||||||
{
|
{
|
||||||
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,194 +13,197 @@ import org.dolphinemu.dolphinemu.utils.Log;
|
||||||
|
|
||||||
public final class SettingsActivityPresenter
|
public final class SettingsActivityPresenter
|
||||||
{
|
{
|
||||||
private static final String KEY_SHOULD_SAVE = "should_save";
|
private static final String KEY_SHOULD_SAVE = "should_save";
|
||||||
|
|
||||||
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 MenuTag menuTag;
|
||||||
private String gameId;
|
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)
|
loadSettingsUI();
|
||||||
{
|
}
|
||||||
this.menuTag = menuTag;
|
else
|
||||||
this.gameId = gameId;
|
{
|
||||||
}
|
mView.showLoading();
|
||||||
else
|
IntentFilter statusIntentFilter = new IntentFilter(
|
||||||
{
|
DirectoryInitializationService.BROADCAST_ACTION);
|
||||||
mShouldSave = savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
|
|
||||||
}
|
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())
|
Bundle bundle = new Bundle();
|
||||||
{
|
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value / 6);
|
||||||
if (!TextUtils.isEmpty(gameId))
|
mView.showSettingsFragment(key, bundle, true, gameId);
|
||||||
{
|
|
||||||
mSettings.loadSettings(gameId, mView);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mSettings.loadSettings(mView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mView.showSettingsFragment(menuTag, null, false, gameId);
|
|
||||||
mView.onSettingsFileLoaded(mSettings);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void prepareDolphinDirectoriesIfNeeded()
|
public void onWiimoteSettingChanged(MenuTag menuTag, int value)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
{
|
{
|
||||||
if (DirectoryInitializationService.areDolphinDirectoriesReady())
|
case 1:
|
||||||
{
|
mView.showSettingsFragment(menuTag, null, true, gameId);
|
||||||
loadSettingsUI();
|
break;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mView.showLoading();
|
|
||||||
IntentFilter statusIntentFilter = new IntentFilter(
|
|
||||||
DirectoryInitializationService.BROADCAST_ACTION);
|
|
||||||
|
|
||||||
directoryStateReceiver =
|
case 2:
|
||||||
new DirectoryStateReceiver(directoryInitializationState ->
|
mView.showToastMessage("Please make sure Continuous Scanning is enabled in Core Settings.");
|
||||||
{
|
break;
|
||||||
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)
|
public void onExtensionSettingChanged(MenuTag menuTag, int value)
|
||||||
|
{
|
||||||
|
if (value != 0) // None
|
||||||
{
|
{
|
||||||
mSettings = settings;
|
Bundle bundle = new Bundle();
|
||||||
}
|
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value);
|
||||||
|
mView.showSettingsFragment(menuTag, bundle, true, gameId);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,126 +11,126 @@ import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
|
||||||
*/
|
*/
|
||||||
public interface SettingsActivityView
|
public interface SettingsActivityView
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Show a new SettingsFragment.
|
* Show a new SettingsFragment.
|
||||||
*
|
*
|
||||||
* @param menuTag Identifier for the settings group that should be displayed.
|
* @param menuTag Identifier for the settings group that should be displayed.
|
||||||
* @param addToStack Whether or not this fragment should replace a previous one.
|
* @param addToStack Whether or not this fragment should replace a previous one.
|
||||||
*/
|
*/
|
||||||
void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack, String gameId);
|
void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack, String gameId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by a contained Fragment to get access to the Setting HashMap
|
* 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
|
* loaded from disk, so that each Fragment doesn't need to perform its own
|
||||||
* read operation.
|
* read operation.
|
||||||
*
|
*
|
||||||
* @return A possibly null HashMap of Settings.
|
* @return A possibly null HashMap of Settings.
|
||||||
*/
|
*/
|
||||||
Settings getSettings();
|
Settings getSettings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to provide the Activity with Settings HashMaps if a Fragment already
|
* 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,
|
* 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.
|
* but the Activity will, so the Activity needs to have its HashMaps resupplied.
|
||||||
*
|
*
|
||||||
* @param settings The ArrayList of all the Settings HashMaps.
|
* @param settings The ArrayList of all the Settings HashMaps.
|
||||||
*/
|
*/
|
||||||
void setSettings(Settings settings);
|
void setSettings(Settings settings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when an asynchronous load operation completes.
|
* Called when an asynchronous load operation completes.
|
||||||
*
|
*
|
||||||
* @param settings The (possibly null) result of the ini load operation.
|
* @param settings The (possibly null) result of the ini load operation.
|
||||||
*/
|
*/
|
||||||
void onSettingsFileLoaded(Settings settings);
|
void onSettingsFileLoaded(Settings settings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when an asynchronous load operation fails.
|
* Called when an asynchronous load operation fails.
|
||||||
*/
|
*/
|
||||||
void onSettingsFileNotFound();
|
void onSettingsFileNotFound();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a popup text message on screen.
|
* Display a popup text message on screen.
|
||||||
*
|
*
|
||||||
* @param message The contents of the onscreen message.
|
* @param message The contents of the onscreen message.
|
||||||
*/
|
*/
|
||||||
void showToastMessage(String message);
|
void showToastMessage(String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the previous fragment.
|
* Show the previous fragment.
|
||||||
*/
|
*/
|
||||||
void popBackStack();
|
void popBackStack();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* End the activity.
|
* End the activity.
|
||||||
*/
|
*/
|
||||||
void finish();
|
void finish();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by a containing Fragment to tell the Activity that a setting was changed;
|
* 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.
|
* unless this has been called, the Activity will not save to disk.
|
||||||
*/
|
*/
|
||||||
void onSettingChanged();
|
void onSettingChanged();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by a containing Fragment to tell the containing Activity that a GCPad's setting
|
* Called by a containing Fragment to tell the containing Activity that a GCPad's setting
|
||||||
* was modified.
|
* was modified.
|
||||||
*
|
*
|
||||||
* @param menuTag Identifier for the GCPad that was modified.
|
* @param menuTag Identifier for the GCPad that was modified.
|
||||||
* @param value New setting for the GCPad.
|
* @param value New setting for the GCPad.
|
||||||
*/
|
*/
|
||||||
void onGcPadSettingChanged(MenuTag menuTag, int value);
|
void onGcPadSettingChanged(MenuTag menuTag, int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by a containing Fragment to tell the containing Activity that a Wiimote's setting
|
* Called by a containing Fragment to tell the containing Activity that a Wiimote's setting
|
||||||
* was modified.
|
* was modified.
|
||||||
*
|
*
|
||||||
* @param menuTag Identifier for Wiimote that was modified.
|
* @param menuTag Identifier for Wiimote that was modified.
|
||||||
* @param value New setting for the Wiimote.
|
* @param value New setting for the Wiimote.
|
||||||
*/
|
*/
|
||||||
void onWiimoteSettingChanged(MenuTag menuTag, int value);
|
void onWiimoteSettingChanged(MenuTag menuTag, int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by a containing Fragment to tell the containing Activity that an extension setting
|
* Called by a containing Fragment to tell the containing Activity that an extension setting
|
||||||
* was modified.
|
* was modified.
|
||||||
*
|
*
|
||||||
* @param menuTag Identifier for the extension that was modified.
|
* @param menuTag Identifier for the extension that was modified.
|
||||||
* @param value New setting for the extension.
|
* @param value New setting for the extension.
|
||||||
*/
|
*/
|
||||||
void onExtensionSettingChanged(MenuTag menuTag, int value);
|
void onExtensionSettingChanged(MenuTag menuTag, int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show loading dialog while loading the settings
|
* Show loading dialog while loading the settings
|
||||||
*/
|
*/
|
||||||
void showLoading();
|
void showLoading();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide the loading the dialog
|
* Hide the loading the dialog
|
||||||
*/
|
*/
|
||||||
void hideLoading();
|
void hideLoading();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a hint to the user that the app needs write to external storage access
|
* Show a hint to the user that the app needs write to external storage access
|
||||||
*/
|
*/
|
||||||
void showPermissionNeededHint();
|
void showPermissionNeededHint();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a hint to the user that the app needs the external storage to be mounted
|
* Show a hint to the user that the app needs the external storage to be mounted
|
||||||
*/
|
*/
|
||||||
void showExternalStorageNotMountedHint();
|
void showExternalStorageNotMountedHint();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the DirectoryInitializationService and listen for the result.
|
* Start the DirectoryInitializationService and listen for the result.
|
||||||
*
|
*
|
||||||
* @param receiver the broadcast receiver for the DirectoryInitializationService
|
* @param receiver the broadcast receiver for the DirectoryInitializationService
|
||||||
* @param filter the Intent broadcasts to be received.
|
* @param filter the Intent broadcasts to be received.
|
||||||
*/
|
*/
|
||||||
void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter);
|
void startDirectoryInitializationService(DirectoryStateReceiver receiver, IntentFilter filter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop listening to the DirectoryInitializationService.
|
* Stop listening to the DirectoryInitializationService.
|
||||||
*
|
*
|
||||||
* @param receiver The broadcast receiver to unregister.
|
* @param receiver The broadcast receiver to unregister.
|
||||||
*/
|
*/
|
||||||
void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver);
|
void stopListeningToDirectoryInitializationService(DirectoryStateReceiver receiver);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.SingleChoiceViewHolder;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SliderViewHolder;
|
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SliderViewHolder;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SubmenuViewHolder;
|
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.features.settings.utils.SettingsFile;
|
||||||
|
import org.dolphinemu.dolphinemu.utils.Log;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
|
public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
|
||||||
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener
|
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener
|
||||||
{
|
{
|
||||||
private SettingsFragmentView mView;
|
private SettingsFragmentView mView;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private ArrayList<SettingsItem> mSettings;
|
private ArrayList<SettingsItem> mSettings;
|
||||||
|
|
||||||
private SettingsItem mClickedItem;
|
private SettingsItem mClickedItem;
|
||||||
private int mSeekbarProgress;
|
private int mSeekbarProgress;
|
||||||
|
|
||||||
private AlertDialog mDialog;
|
private AlertDialog mDialog;
|
||||||
private TextView mTextSliderValue;
|
private TextView mTextSliderValue;
|
||||||
|
|
||||||
public SettingsAdapter(SettingsFragmentView view, Context context)
|
public SettingsAdapter(SettingsFragmentView view, Context context)
|
||||||
{
|
{
|
||||||
mView = view;
|
mView = view;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
|
public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
|
||||||
{
|
{
|
||||||
View view;
|
View view;
|
||||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||||
|
|
||||||
switch (viewType)
|
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)
|
|
||||||
{
|
{
|
||||||
StringSetting gfxBackend = null;
|
case SettingsItem.TYPE_HEADER:
|
||||||
switch (which)
|
view = inflater.inflate(R.layout.list_item_settings_header, parent, false);
|
||||||
{
|
return new HeaderViewHolder(view, this);
|
||||||
case 0:
|
|
||||||
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "OGL");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
case SettingsItem.TYPE_CHECKBOX:
|
||||||
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "Vulkan");
|
view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false);
|
||||||
break;
|
return new CheckBoxSettingViewHolder(view, this);
|
||||||
|
|
||||||
case 2:
|
case SettingsItem.TYPE_STRING_SINGLE_CHOICE:
|
||||||
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "Software Renderer");
|
case SettingsItem.TYPE_SINGLE_CHOICE:
|
||||||
break;
|
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||||
|
return new SingleChoiceViewHolder(view, this);
|
||||||
|
|
||||||
case 3:
|
case SettingsItem.TYPE_SLIDER:
|
||||||
gfxBackend = new StringSetting(SettingsFile.KEY_VIDEO_BACKEND, Settings.SECTION_INI_CORE, "Null");
|
view = inflater.inflate(R.layout.list_item_setting, parent, false);
|
||||||
break;
|
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)
|
if (item.getKey().equals(SettingsFile.KEY_SKIP_EFB) ||
|
||||||
{
|
item.getKey().equals(SettingsFile.KEY_IGNORE_FORMAT))
|
||||||
StringSetting extension = new StringSetting(SettingsFile.KEY_WIIMOTE_EXTENSION, Settings.SECTION_WIIMOTE + wiimoteNumber, mContext.getResources().getStringArray(R.array.wiimoteExtensionsEntries)[which]);
|
{
|
||||||
mView.putSetting(extension);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,170 +20,173 @@ import java.util.ArrayList;
|
||||||
|
|
||||||
public final class SettingsFragment extends Fragment implements SettingsFragmentView
|
public final class SettingsFragment extends Fragment implements SettingsFragmentView
|
||||||
{
|
{
|
||||||
private static final String ARGUMENT_MENU_TAG = "menu_tag";
|
private static final String ARGUMENT_MENU_TAG = "menu_tag";
|
||||||
private static final String ARGUMENT_GAME_ID = "game_id";
|
private static final String ARGUMENT_GAME_ID = "game_id";
|
||||||
|
|
||||||
private SettingsFragmentPresenter mPresenter = new SettingsFragmentPresenter(this);
|
private SettingsFragmentPresenter mPresenter = new SettingsFragmentPresenter(this);
|
||||||
private SettingsActivityView mActivity;
|
private SettingsActivityView mActivity;
|
||||||
|
|
||||||
private SettingsAdapter mAdapter;
|
private SettingsAdapter mAdapter;
|
||||||
|
|
||||||
public static Fragment newInstance(MenuTag menuTag, String gameId, Bundle extras)
|
public static Fragment newInstance(MenuTag menuTag, String gameId, Bundle extras)
|
||||||
{
|
{
|
||||||
SettingsFragment fragment = new SettingsFragment();
|
SettingsFragment fragment = new SettingsFragment();
|
||||||
|
|
||||||
Bundle arguments = new Bundle();
|
Bundle arguments = new Bundle();
|
||||||
if(extras != null)
|
if (extras != null)
|
||||||
{
|
{
|
||||||
arguments.putAll(extras);
|
arguments.putAll(extras);
|
||||||
}
|
}
|
||||||
|
|
||||||
arguments.putSerializable(ARGUMENT_MENU_TAG, menuTag);
|
arguments.putSerializable(ARGUMENT_MENU_TAG, menuTag);
|
||||||
arguments.putString(ARGUMENT_GAME_ID, gameId);
|
arguments.putString(ARGUMENT_GAME_ID, gameId);
|
||||||
|
|
||||||
fragment.setArguments(arguments);
|
fragment.setArguments(arguments);
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context)
|
public void onAttach(Context context)
|
||||||
{
|
{
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
|
||||||
mActivity = (SettingsActivityView) context;
|
mActivity = (SettingsActivityView) context;
|
||||||
mPresenter.onAttach();
|
mPresenter.onAttach();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This version of onAttach is needed for versions below Marshmallow.
|
* This version of onAttach is needed for versions below Marshmallow.
|
||||||
*
|
*
|
||||||
* @param activity
|
* @param activity
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Activity activity)
|
public void onAttach(Activity activity)
|
||||||
{
|
{
|
||||||
super.onAttach(activity);
|
super.onAttach(activity);
|
||||||
|
|
||||||
mActivity = (SettingsActivityView) activity;
|
mActivity = (SettingsActivityView) activity;
|
||||||
mPresenter.onAttach();
|
mPresenter.onAttach();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
setRetainInstance(true);
|
setRetainInstance(true);
|
||||||
Bundle args = getArguments();
|
Bundle args = getArguments();
|
||||||
MenuTag menuTag = (MenuTag) args.getSerializable(ARGUMENT_MENU_TAG);
|
MenuTag menuTag = (MenuTag) args.getSerializable(ARGUMENT_MENU_TAG);
|
||||||
String gameId = getArguments().getString(ARGUMENT_GAME_ID);
|
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
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
||||||
{
|
@Nullable Bundle savedInstanceState)
|
||||||
return inflater.inflate(R.layout.fragment_settings, container, false);
|
{
|
||||||
}
|
return inflater.inflate(R.layout.fragment_settings, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
|
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.setAdapter(mAdapter);
|
||||||
recyclerView.setLayoutManager(manager);
|
recyclerView.setLayoutManager(manager);
|
||||||
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
|
recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
|
||||||
|
|
||||||
SettingsActivityView activity = (SettingsActivityView) getActivity();
|
SettingsActivityView activity = (SettingsActivityView) getActivity();
|
||||||
mPresenter.onViewCreated(activity.getSettings());
|
mPresenter.onViewCreated(activity.getSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDetach()
|
public void onDetach()
|
||||||
{
|
{
|
||||||
super.onDetach();
|
super.onDetach();
|
||||||
mActivity = null;
|
mActivity = null;
|
||||||
|
|
||||||
if (mAdapter != null)
|
if (mAdapter != null)
|
||||||
{
|
{
|
||||||
mAdapter.closeDialog();
|
mAdapter.closeDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSettingsFileLoaded(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
|
public void onSettingsFileLoaded(
|
||||||
{
|
org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
|
||||||
mPresenter.setSettings(settings);
|
{
|
||||||
}
|
mPresenter.setSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void passSettingsToActivity(org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
|
public void passSettingsToActivity(
|
||||||
{
|
org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
|
||||||
if (mActivity != null)
|
{
|
||||||
{
|
if (mActivity != null)
|
||||||
mActivity.setSettings(settings);
|
{
|
||||||
}
|
mActivity.setSettings(settings);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showSettingsList(ArrayList<SettingsItem> settingsList)
|
public void showSettingsList(ArrayList<SettingsItem> settingsList)
|
||||||
{
|
{
|
||||||
mAdapter.setSettings(settingsList);
|
mAdapter.setSettings(settingsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadDefaultSettings()
|
public void loadDefaultSettings()
|
||||||
{
|
{
|
||||||
mPresenter.loadDefaultSettings();
|
mPresenter.loadDefaultSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadSubMenu(MenuTag menuKey)
|
public void loadSubMenu(MenuTag menuKey)
|
||||||
{
|
{
|
||||||
mActivity.showSettingsFragment(menuKey, null, true, getArguments().getString(ARGUMENT_GAME_ID));
|
mActivity.showSettingsFragment(menuKey, null, true, getArguments().getString(ARGUMENT_GAME_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showToastMessage(String message)
|
public void showToastMessage(String message)
|
||||||
{
|
{
|
||||||
mActivity.showToastMessage(message);
|
mActivity.showToastMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void putSetting(Setting setting)
|
public void putSetting(Setting setting)
|
||||||
{
|
{
|
||||||
mPresenter.putSetting(setting);
|
mPresenter.putSetting(setting);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSettingChanged()
|
public void onSettingChanged()
|
||||||
{
|
{
|
||||||
mActivity.onSettingChanged();
|
mActivity.onSettingChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGcPadSettingChanged(MenuTag menuTag, int value)
|
public void onGcPadSettingChanged(MenuTag menuTag, int value)
|
||||||
{
|
{
|
||||||
mActivity.onGcPadSettingChanged(menuTag, value);
|
mActivity.onGcPadSettingChanged(menuTag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWiimoteSettingChanged(MenuTag menuTag, int value)
|
public void onWiimoteSettingChanged(MenuTag menuTag, int value)
|
||||||
{
|
{
|
||||||
mActivity.onWiimoteSettingChanged(menuTag, value);
|
mActivity.onWiimoteSettingChanged(menuTag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExtensionSettingChanged(MenuTag menuTag, int value)
|
public void onExtensionSettingChanged(MenuTag menuTag, int value)
|
||||||
{
|
{
|
||||||
mActivity.onExtensionSettingChanged(menuTag, value);
|
mActivity.onExtensionSettingChanged(menuTag, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,89 +14,89 @@ import java.util.ArrayList;
|
||||||
*/
|
*/
|
||||||
public interface SettingsFragmentView
|
public interface SettingsFragmentView
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Called by the containing Activity to notify the Fragment that an
|
* Called by the containing Activity to notify the Fragment that an
|
||||||
* asynchronous load operation completed.
|
* asynchronous load operation completed.
|
||||||
*
|
*
|
||||||
* @param settings The (possibly null) result of the ini load operation.
|
* @param settings The (possibly null) result of the ini load operation.
|
||||||
*/
|
*/
|
||||||
void onSettingsFileLoaded(Settings settings);
|
void onSettingsFileLoaded(Settings settings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass a settings HashMap to the containing activity, so that it can
|
* Pass a settings HashMap to the containing activity, so that it can
|
||||||
* share the HashMap with other SettingsFragments; useful so that rotations
|
* share the HashMap with other SettingsFragments; useful so that rotations
|
||||||
* do not require an additional load operation.
|
* do not require an additional load operation.
|
||||||
*
|
*
|
||||||
* @param settings An ArrayList containing all the settings HashMaps.
|
* @param settings An ArrayList containing all the settings HashMaps.
|
||||||
*/
|
*/
|
||||||
void passSettingsToActivity(Settings settings);
|
void passSettingsToActivity(Settings settings);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass an ArrayList to the View so that it can be displayed on screen.
|
* 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
|
* @param settingsList The result of converting the HashMap to an ArrayList
|
||||||
*/
|
*/
|
||||||
void showSettingsList(ArrayList<SettingsItem> settingsList);
|
void showSettingsList(ArrayList<SettingsItem> settingsList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the containing Activity when an asynchronous load operation fails.
|
* Called by the containing Activity when an asynchronous load operation fails.
|
||||||
* Instructs the Fragment to load the settings screen with defaults selected.
|
* Instructs the Fragment to load the settings screen with defaults selected.
|
||||||
*/
|
*/
|
||||||
void loadDefaultSettings();
|
void loadDefaultSettings();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The Fragment's containing activity.
|
* @return The Fragment's containing activity.
|
||||||
*/
|
*/
|
||||||
FragmentActivity getActivity();
|
FragmentActivity getActivity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the Fragment to tell the containing Activity to show a new
|
* Tell the Fragment to tell the containing Activity to show a new
|
||||||
* Fragment containing a submenu of settings.
|
* Fragment containing a submenu of settings.
|
||||||
*
|
*
|
||||||
* @param menuKey Identifier for the settings group that should be shown.
|
* @param menuKey Identifier for the settings group that should be shown.
|
||||||
*/
|
*/
|
||||||
void loadSubMenu(MenuTag menuKey);
|
void loadSubMenu(MenuTag menuKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the Fragment to tell the containing activity to display a toast message.
|
* Tell the Fragment to tell the containing activity to display a toast message.
|
||||||
*
|
*
|
||||||
* @param message Text to be shown in the Toast
|
* @param message Text to be shown in the Toast
|
||||||
*/
|
*/
|
||||||
void showToastMessage(String message);
|
void showToastMessage(String message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Have the fragment add a setting to the HashMap.
|
* Have the fragment add a setting to the HashMap.
|
||||||
*
|
*
|
||||||
* @param setting The (possibly previously missing) new setting.
|
* @param setting The (possibly previously missing) new setting.
|
||||||
*/
|
*/
|
||||||
void putSetting(Setting setting);
|
void putSetting(Setting setting);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Have the fragment tell the containing Activity that a setting was modified.
|
* Have the fragment tell the containing Activity that a setting was modified.
|
||||||
*/
|
*/
|
||||||
void onSettingChanged();
|
void onSettingChanged();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Have the fragment tell the containing Activity that a GCPad's setting was modified.
|
* Have the fragment tell the containing Activity that a GCPad's setting was modified.
|
||||||
*
|
*
|
||||||
* @param menuTag Identifier for the GCPad that was modified.
|
* @param menuTag Identifier for the GCPad that was modified.
|
||||||
* @param value New setting for the GCPad.
|
* @param value New setting for the GCPad.
|
||||||
*/
|
*/
|
||||||
void onGcPadSettingChanged(MenuTag menuTag, int value);
|
void onGcPadSettingChanged(MenuTag menuTag, int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Have the fragment tell the containing Activity that a Wiimote's setting was modified.
|
* Have the fragment tell the containing Activity that a Wiimote's setting was modified.
|
||||||
*
|
*
|
||||||
* @param menuTag Identifier for Wiimote that was modified.
|
* @param menuTag Identifier for Wiimote that was modified.
|
||||||
* @param value New setting for the Wiimote.
|
* @param value New setting for the Wiimote.
|
||||||
*/
|
*/
|
||||||
void onWiimoteSettingChanged(MenuTag menuTag, int value);
|
void onWiimoteSettingChanged(MenuTag menuTag, int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Have the fragment tell the containing Activity that an extension setting was modified.
|
* Have the fragment tell the containing Activity that an extension setting was modified.
|
||||||
*
|
*
|
||||||
* @param menuTag Identifier for the extension that was modified.
|
* @param menuTag Identifier for the extension that was modified.
|
||||||
* @param value New setting for the extension.
|
* @param value New setting for the extension.
|
||||||
*/
|
*/
|
||||||
void onExtensionSettingChanged(MenuTag menuTag, int value);
|
void onExtensionSettingChanged(MenuTag menuTag, int value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,48 +9,48 @@ import android.widget.FrameLayout;
|
||||||
*/
|
*/
|
||||||
public final class SettingsFrameLayout extends FrameLayout
|
public final class SettingsFrameLayout extends FrameLayout
|
||||||
{
|
{
|
||||||
private float mVisibleness = 1.0f;
|
private float mVisibleness = 1.0f;
|
||||||
|
|
||||||
public SettingsFrameLayout(Context context)
|
public SettingsFrameLayout(Context context)
|
||||||
{
|
{
|
||||||
super(context);
|
super(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SettingsFrameLayout(Context context, AttributeSet attrs)
|
public SettingsFrameLayout(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr)
|
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr)
|
||||||
{
|
{
|
||||||
super(context, attrs, defStyleAttr);
|
super(context, attrs, defStyleAttr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
|
public SettingsFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
|
||||||
{
|
{
|
||||||
super(context, attrs, defStyleAttr, defStyleRes);
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getYFraction()
|
public float getYFraction()
|
||||||
{
|
{
|
||||||
return getY() / getHeight();
|
return getY() / getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setYFraction(float yFraction)
|
public void setYFraction(float yFraction)
|
||||||
{
|
{
|
||||||
final int height = getHeight();
|
final int height = getHeight();
|
||||||
setY((height > 0) ? (yFraction * height) : -9999);
|
setY((height > 0) ? (yFraction * height) : -9999);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getVisibleness()
|
public float getVisibleness()
|
||||||
{
|
{
|
||||||
return mVisibleness;
|
return mVisibleness;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVisibleness(float visibleness)
|
public void setVisibleness(float visibleness)
|
||||||
{
|
{
|
||||||
setScaleX(visibleness);
|
setScaleX(visibleness);
|
||||||
setScaleY(visibleness);
|
setScaleY(visibleness);
|
||||||
setAlpha(visibleness);
|
setAlpha(visibleness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,46 +11,46 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||||
|
|
||||||
public final class CheckBoxSettingViewHolder extends SettingViewHolder
|
public final class CheckBoxSettingViewHolder extends SettingViewHolder
|
||||||
{
|
{
|
||||||
private CheckBoxSetting mItem;
|
private CheckBoxSetting mItem;
|
||||||
|
|
||||||
private TextView mTextSettingName;
|
private TextView mTextSettingName;
|
||||||
private TextView mTextSettingDescription;
|
private TextView mTextSettingDescription;
|
||||||
|
|
||||||
private CheckBox mCheckbox;
|
private CheckBox mCheckbox;
|
||||||
|
|
||||||
public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter)
|
public CheckBoxSettingViewHolder(View itemView, SettingsAdapter adapter)
|
||||||
{
|
{
|
||||||
super(itemView, adapter);
|
super(itemView, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void findViews(View root)
|
protected void findViews(View root)
|
||||||
{
|
{
|
||||||
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
||||||
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
||||||
mCheckbox = (CheckBox) root.findViewById(R.id.checkbox);
|
mCheckbox = (CheckBox) root.findViewById(R.id.checkbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(SettingsItem item)
|
public void bind(SettingsItem item)
|
||||||
{
|
{
|
||||||
mItem = (CheckBoxSetting) item;
|
mItem = (CheckBoxSetting) item;
|
||||||
|
|
||||||
mTextSettingName.setText(item.getNameId());
|
mTextSettingName.setText(item.getNameId());
|
||||||
|
|
||||||
if (item.getDescriptionId() > 0)
|
if (item.getDescriptionId() > 0)
|
||||||
{
|
{
|
||||||
mTextSettingDescription.setText(item.getDescriptionId());
|
mTextSettingDescription.setText(item.getDescriptionId());
|
||||||
}
|
}
|
||||||
|
|
||||||
mCheckbox.setChecked(mItem.isChecked());
|
mCheckbox.setChecked(mItem.isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View clicked)
|
public void onClick(View clicked)
|
||||||
{
|
{
|
||||||
mCheckbox.toggle();
|
mCheckbox.toggle();
|
||||||
|
|
||||||
getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked());
|
getAdapter().onBooleanClick(mItem, getAdapterPosition(), mCheckbox.isChecked());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,29 +9,29 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||||
|
|
||||||
public final class HeaderViewHolder extends SettingViewHolder
|
public final class HeaderViewHolder extends SettingViewHolder
|
||||||
{
|
{
|
||||||
private TextView mHeaderName;
|
private TextView mHeaderName;
|
||||||
|
|
||||||
public HeaderViewHolder(View itemView, SettingsAdapter adapter)
|
public HeaderViewHolder(View itemView, SettingsAdapter adapter)
|
||||||
{
|
{
|
||||||
super(itemView, adapter);
|
super(itemView, adapter);
|
||||||
itemView.setOnClickListener(null);
|
itemView.setOnClickListener(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void findViews(View root)
|
protected void findViews(View root)
|
||||||
{
|
{
|
||||||
mHeaderName = (TextView) root.findViewById(R.id.text_header_name);
|
mHeaderName = (TextView) root.findViewById(R.id.text_header_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(SettingsItem item)
|
public void bind(SettingsItem item)
|
||||||
{
|
{
|
||||||
mHeaderName.setText(item.getNameId());
|
mHeaderName.setText(item.getNameId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View clicked)
|
public void onClick(View clicked)
|
||||||
{
|
{
|
||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,41 +13,41 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||||
|
|
||||||
public final class InputBindingSettingViewHolder extends SettingViewHolder
|
public final class InputBindingSettingViewHolder extends SettingViewHolder
|
||||||
{
|
{
|
||||||
private InputBindingSetting mItem;
|
private InputBindingSetting mItem;
|
||||||
|
|
||||||
private TextView mTextSettingName;
|
private TextView mTextSettingName;
|
||||||
private TextView mTextSettingDescription;
|
private TextView mTextSettingDescription;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
public InputBindingSettingViewHolder(View itemView, SettingsAdapter adapter, Context context)
|
public InputBindingSettingViewHolder(View itemView, SettingsAdapter adapter, Context context)
|
||||||
{
|
{
|
||||||
super(itemView, adapter);
|
super(itemView, adapter);
|
||||||
|
|
||||||
mContext = context;
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void findViews(View root)
|
protected void findViews(View root)
|
||||||
{
|
{
|
||||||
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
||||||
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(SettingsItem item)
|
public void bind(SettingsItem item)
|
||||||
{
|
{
|
||||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||||
|
|
||||||
mItem = (InputBindingSetting) item;
|
mItem = (InputBindingSetting) item;
|
||||||
|
|
||||||
mTextSettingName.setText(item.getNameId());
|
mTextSettingName.setText(item.getNameId());
|
||||||
mTextSettingDescription.setText(sharedPreferences.getString(mItem.getKey(), ""));
|
mTextSettingDescription.setText(sharedPreferences.getString(mItem.getKey(), ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View clicked)
|
public void onClick(View clicked)
|
||||||
{
|
{
|
||||||
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
|
getAdapter().onInputBindingClick(mItem, getAdapterPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,46 +6,47 @@ import android.view.View;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
|
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
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)
|
public SettingViewHolder(View itemView, SettingsAdapter adapter)
|
||||||
{
|
{
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
mAdapter = adapter;
|
mAdapter = adapter;
|
||||||
|
|
||||||
itemView.setOnClickListener(this);
|
itemView.setOnClickListener(this);
|
||||||
|
|
||||||
findViews(itemView);
|
findViews(itemView);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SettingsAdapter getAdapter()
|
protected SettingsAdapter getAdapter()
|
||||||
{
|
{
|
||||||
return mAdapter;
|
return mAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets handles to all this ViewHolder's child views using their XML-defined identifiers.
|
* Gets handles to all this ViewHolder's child views using their XML-defined identifiers.
|
||||||
*
|
*
|
||||||
* @param root The newly inflated top-level view.
|
* @param root The newly inflated top-level view.
|
||||||
*/
|
*/
|
||||||
protected abstract void findViews(View root);
|
protected abstract void findViews(View root);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the adapter to set this ViewHolder's child views to display the list item
|
* Called by the adapter to set this ViewHolder's child views to display the list item
|
||||||
* it must now represent.
|
* it must now represent.
|
||||||
*
|
*
|
||||||
* @param item The list item that should be represented by this ViewHolder.
|
* @param item The list item that should be represented by this ViewHolder.
|
||||||
*/
|
*/
|
||||||
public abstract void bind(SettingsItem item);
|
public abstract void bind(SettingsItem item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when this ViewHolder's view is clicked on. Implementations should usually pass
|
* Called when this ViewHolder's view is clicked on. Implementations should usually pass
|
||||||
* this event up to the adapter.
|
* this event up to the adapter.
|
||||||
*
|
*
|
||||||
* @param clicked The view that was clicked on.
|
* @param clicked The view that was clicked on.
|
||||||
*/
|
*/
|
||||||
public abstract void onClick(View clicked);
|
public abstract void onClick(View clicked);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,46 +11,46 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||||
|
|
||||||
public final class SingleChoiceViewHolder extends SettingViewHolder
|
public final class SingleChoiceViewHolder extends SettingViewHolder
|
||||||
{
|
{
|
||||||
private SettingsItem mItem;
|
private SettingsItem mItem;
|
||||||
|
|
||||||
private TextView mTextSettingName;
|
private TextView mTextSettingName;
|
||||||
private TextView mTextSettingDescription;
|
private TextView mTextSettingDescription;
|
||||||
|
|
||||||
public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter)
|
public SingleChoiceViewHolder(View itemView, SettingsAdapter adapter)
|
||||||
{
|
{
|
||||||
super(itemView, adapter);
|
super(itemView, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void findViews(View root)
|
protected void findViews(View root)
|
||||||
{
|
{
|
||||||
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
||||||
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(SettingsItem item)
|
public void bind(SettingsItem item)
|
||||||
{
|
{
|
||||||
mItem = item;
|
mItem = item;
|
||||||
|
|
||||||
mTextSettingName.setText(item.getNameId());
|
mTextSettingName.setText(item.getNameId());
|
||||||
|
|
||||||
if (item.getDescriptionId() > 0)
|
if (item.getDescriptionId() > 0)
|
||||||
{
|
{
|
||||||
mTextSettingDescription.setText(item.getDescriptionId());
|
mTextSettingDescription.setText(item.getDescriptionId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View clicked)
|
public void onClick(View clicked)
|
||||||
{
|
{
|
||||||
if (mItem instanceof SingleChoiceSetting)
|
if (mItem instanceof SingleChoiceSetting)
|
||||||
{
|
{
|
||||||
getAdapter().onSingleChoiceClick((SingleChoiceSetting) mItem);
|
getAdapter().onSingleChoiceClick((SingleChoiceSetting) mItem);
|
||||||
}
|
}
|
||||||
else if (mItem instanceof StringSingleChoiceSetting)
|
else if (mItem instanceof StringSingleChoiceSetting)
|
||||||
{
|
{
|
||||||
getAdapter().onStringSingleChoiceClick((StringSingleChoiceSetting) mItem);
|
getAdapter().onStringSingleChoiceClick((StringSingleChoiceSetting) mItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,40 +10,40 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||||
|
|
||||||
public final class SliderViewHolder extends SettingViewHolder
|
public final class SliderViewHolder extends SettingViewHolder
|
||||||
{
|
{
|
||||||
private SliderSetting mItem;
|
private SliderSetting mItem;
|
||||||
|
|
||||||
private TextView mTextSettingName;
|
private TextView mTextSettingName;
|
||||||
private TextView mTextSettingDescription;
|
private TextView mTextSettingDescription;
|
||||||
|
|
||||||
public SliderViewHolder(View itemView, SettingsAdapter adapter)
|
public SliderViewHolder(View itemView, SettingsAdapter adapter)
|
||||||
{
|
{
|
||||||
super(itemView, adapter);
|
super(itemView, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void findViews(View root)
|
protected void findViews(View root)
|
||||||
{
|
{
|
||||||
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
||||||
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(SettingsItem item)
|
public void bind(SettingsItem item)
|
||||||
{
|
{
|
||||||
mItem = (SliderSetting) item;
|
mItem = (SliderSetting) item;
|
||||||
|
|
||||||
mTextSettingName.setText(item.getNameId());
|
mTextSettingName.setText(item.getNameId());
|
||||||
|
|
||||||
if (item.getDescriptionId() > 0)
|
if (item.getDescriptionId() > 0)
|
||||||
{
|
{
|
||||||
mTextSettingDescription.setText(item.getDescriptionId());
|
mTextSettingDescription.setText(item.getDescriptionId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View clicked)
|
public void onClick(View clicked)
|
||||||
{
|
{
|
||||||
getAdapter().onSliderClick(mItem);
|
getAdapter().onSliderClick(mItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,39 +10,39 @@ import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
|
||||||
|
|
||||||
public final class SubmenuViewHolder extends SettingViewHolder
|
public final class SubmenuViewHolder extends SettingViewHolder
|
||||||
{
|
{
|
||||||
private SubmenuSetting mItem;
|
private SubmenuSetting mItem;
|
||||||
|
|
||||||
private TextView mTextSettingName;
|
private TextView mTextSettingName;
|
||||||
private TextView mTextSettingDescription;
|
private TextView mTextSettingDescription;
|
||||||
|
|
||||||
public SubmenuViewHolder(View itemView, SettingsAdapter adapter)
|
public SubmenuViewHolder(View itemView, SettingsAdapter adapter)
|
||||||
{
|
{
|
||||||
super(itemView, adapter);
|
super(itemView, adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void findViews(View root)
|
protected void findViews(View root)
|
||||||
{
|
{
|
||||||
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name);
|
||||||
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bind(SettingsItem item)
|
public void bind(SettingsItem item)
|
||||||
{
|
{
|
||||||
mItem = (SubmenuSetting) item;
|
mItem = (SubmenuSetting) item;
|
||||||
|
|
||||||
mTextSettingName.setText(item.getNameId());
|
mTextSettingName.setText(item.getNameId());
|
||||||
|
|
||||||
if (item.getDescriptionId() > 0)
|
if (item.getDescriptionId() > 0)
|
||||||
{
|
{
|
||||||
mTextSettingDescription.setText(item.getDescriptionId());
|
mTextSettingDescription.setText(item.getDescriptionId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View clicked)
|
public void onClick(View clicked)
|
||||||
{
|
{
|
||||||
getAdapter().onSubmenuClick(mItem);
|
getAdapter().onSubmenuClick(mItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -10,13 +10,13 @@ import java.io.File;
|
||||||
|
|
||||||
public class CustomFilePickerFragment extends FilePickerFragment
|
public class CustomFilePickerFragment extends FilePickerFragment
|
||||||
{
|
{
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Uri toUri(@NonNull final File file)
|
public Uri toUri(@NonNull final File file)
|
||||||
{
|
{
|
||||||
return FileProvider
|
return FileProvider
|
||||||
.getUriForFile(getContext(),
|
.getUriForFile(getContext(),
|
||||||
getContext().getApplicationContext().getPackageName() + ".filesprovider",
|
getContext().getApplicationContext().getPackageName() + ".filesprovider",
|
||||||
file);
|
file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,433 +30,438 @@ import java.io.File;
|
||||||
|
|
||||||
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
||||||
{
|
{
|
||||||
private static final String KEY_GAMEPATH = "gamepath";
|
private static final String KEY_GAMEPATH = "gamepath";
|
||||||
|
|
||||||
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();
|
Bundle args = new Bundle();
|
||||||
args.putString(KEY_GAMEPATH, gamePath);
|
args.putString(KEY_GAMEPATH, gamePath);
|
||||||
|
|
||||||
EmulationFragment fragment = new EmulationFragment();
|
EmulationFragment fragment = new EmulationFragment();
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context)
|
public void onAttach(Context context)
|
||||||
{
|
{
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
|
||||||
if (context instanceof EmulationActivity)
|
if (context instanceof EmulationActivity)
|
||||||
{
|
{
|
||||||
activity = (EmulationActivity)context;
|
activity = (EmulationActivity) context;
|
||||||
NativeLibrary.setEmulationActivity((EmulationActivity) context);
|
NativeLibrary.setEmulationActivity((EmulationActivity) context);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("EmulationFragment must have EmulationActivity parent");
|
throw new IllegalStateException("EmulationFragment must have EmulationActivity parent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize anything that doesn't depend on the layout / views in here.
|
* Initialize anything that doesn't depend on the layout / views in here.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
// So this fragment doesn't restart on configuration changes; i.e. rotation.
|
||||||
setRetainInstance(true);
|
setRetainInstance(true);
|
||||||
|
|
||||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||||
|
|
||||||
String gamePath = getArguments().getString(KEY_GAMEPATH);
|
String gamePath = getArguments().getString(KEY_GAMEPATH);
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||||
boolean firstOpen = preferences.getBoolean(StartupHandler.NEW_SESSION, true);
|
boolean firstOpen = preferences.getBoolean(StartupHandler.NEW_SESSION, true);
|
||||||
SharedPreferences.Editor sPrefsEditor = preferences.edit();
|
SharedPreferences.Editor sPrefsEditor = preferences.edit();
|
||||||
sPrefsEditor.putBoolean(StartupHandler.NEW_SESSION, false);
|
sPrefsEditor.putBoolean(StartupHandler.NEW_SESSION, false);
|
||||||
sPrefsEditor.apply();
|
sPrefsEditor.apply();
|
||||||
mEmulationState = new EmulationState(gamePath, getTemporaryStateFilePath(), firstOpen);
|
mEmulationState = new EmulationState(gamePath, getTemporaryStateFilePath(), firstOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the UI and start emulation in here.
|
* Initialize the UI and start emulation in here.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
|
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
|
||||||
|
|
||||||
SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation);
|
SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation);
|
||||||
surfaceView.getHolder().addCallback(this);
|
surfaceView.getHolder().addCallback(this);
|
||||||
|
|
||||||
mInputOverlay = contents.findViewById(R.id.surface_input_overlay);
|
mInputOverlay = contents.findViewById(R.id.surface_input_overlay);
|
||||||
if (mInputOverlay != null)
|
if (mInputOverlay != null)
|
||||||
{
|
{
|
||||||
// If the input overlay was previously disabled, then don't show it.
|
// If the input overlay was previously disabled, then don't show it.
|
||||||
if (!mPreferences.getBoolean("showInputOverlay", true))
|
if (!mPreferences.getBoolean("showInputOverlay", true))
|
||||||
{
|
{
|
||||||
mInputOverlay.setVisibility(View.GONE);
|
mInputOverlay.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button doneButton = contents.findViewById(R.id.done_control_config);
|
Button doneButton = contents.findViewById(R.id.done_control_config);
|
||||||
if (doneButton != null)
|
if (doneButton != null)
|
||||||
{
|
{
|
||||||
doneButton.setOnClickListener(v -> stopConfiguringControls());
|
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
|
@Override
|
||||||
public void onResume()
|
public void onResume()
|
||||||
{
|
{
|
||||||
super.onResume();
|
super.onResume();
|
||||||
if (DirectoryInitializationService.areDolphinDirectoriesReady())
|
if (DirectoryInitializationService.areDolphinDirectoriesReady())
|
||||||
{
|
{
|
||||||
mEmulationState.run(activity.isActivityRecreated());
|
mEmulationState.run(activity.isActivityRecreated());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setupDolphinDirectoriesThenStartEmulation();
|
setupDolphinDirectoriesThenStartEmulation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause()
|
public void onPause()
|
||||||
{
|
{
|
||||||
if (directoryStateReceiver != null)
|
if (directoryStateReceiver != null)
|
||||||
{
|
{
|
||||||
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
|
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
|
||||||
directoryStateReceiver = null;
|
directoryStateReceiver = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
mEmulationState.pause();
|
mEmulationState.pause();
|
||||||
super.onPause();
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDetach()
|
public void onDetach()
|
||||||
{
|
{
|
||||||
NativeLibrary.clearEmulationActivity();
|
NativeLibrary.clearEmulationActivity();
|
||||||
super.onDetach();
|
super.onDetach();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupDolphinDirectoriesThenStartEmulation() {
|
private void setupDolphinDirectoriesThenStartEmulation()
|
||||||
IntentFilter statusIntentFilter = new IntentFilter(
|
{
|
||||||
DirectoryInitializationService.BROADCAST_ACTION);
|
IntentFilter statusIntentFilter = new IntentFilter(
|
||||||
|
DirectoryInitializationService.BROADCAST_ACTION);
|
||||||
|
|
||||||
directoryStateReceiver =
|
directoryStateReceiver =
|
||||||
new DirectoryStateReceiver(directoryInitializationState ->
|
new DirectoryStateReceiver(directoryInitializationState ->
|
||||||
{
|
{
|
||||||
if (directoryInitializationState == DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
if (directoryInitializationState ==
|
||||||
{
|
DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
||||||
mEmulationState.run(activity.isActivityRecreated());
|
{
|
||||||
}
|
mEmulationState.run(activity.isActivityRecreated());
|
||||||
else if (directoryInitializationState == DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
}
|
||||||
{
|
else if (directoryInitializationState ==
|
||||||
Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
||||||
.show();
|
{
|
||||||
}
|
Toast.makeText(getContext(), R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||||
else if (directoryInitializationState == DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
|
.show();
|
||||||
{
|
}
|
||||||
Toast.makeText(getContext(), R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
|
else if (directoryInitializationState ==
|
||||||
.show();
|
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
|
// Registers the DirectoryStateReceiver and its intent filters
|
||||||
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
|
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
|
||||||
directoryStateReceiver,
|
directoryStateReceiver,
|
||||||
statusIntentFilter);
|
statusIntentFilter);
|
||||||
DirectoryInitializationService.startService(getActivity());
|
DirectoryInitializationService.startService(getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleInputOverlayVisibility()
|
public void toggleInputOverlayVisibility()
|
||||||
{
|
{
|
||||||
SharedPreferences.Editor editor = mPreferences.edit();
|
SharedPreferences.Editor editor = mPreferences.edit();
|
||||||
|
|
||||||
// If the overlay is currently set to INVISIBLE
|
// If the overlay is currently set to INVISIBLE
|
||||||
if (!mPreferences.getBoolean("showInputOverlay", false))
|
if (!mPreferences.getBoolean("showInputOverlay", false))
|
||||||
{
|
{
|
||||||
// Set it to VISIBLE
|
// Set it to VISIBLE
|
||||||
mInputOverlay.setVisibility(View.VISIBLE);
|
mInputOverlay.setVisibility(View.VISIBLE);
|
||||||
editor.putBoolean("showInputOverlay", true);
|
editor.putBoolean("showInputOverlay", true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set it to INVISIBLE
|
// Set it to INVISIBLE
|
||||||
mInputOverlay.setVisibility(View.GONE);
|
mInputOverlay.setVisibility(View.GONE);
|
||||||
editor.putBoolean("showInputOverlay", false);
|
editor.putBoolean("showInputOverlay", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshInputOverlay()
|
public void refreshInputOverlay()
|
||||||
{
|
{
|
||||||
mInputOverlay.refreshControls();
|
mInputOverlay.refreshControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder holder)
|
public void surfaceCreated(SurfaceHolder holder)
|
||||||
{
|
{
|
||||||
// We purposely don't do anything here.
|
// We purposely don't do anything here.
|
||||||
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
|
// All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
|
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
|
||||||
mEmulationState.newSurface(holder.getSurface());
|
mEmulationState.newSurface(holder.getSurface());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceDestroyed(SurfaceHolder holder)
|
public void surfaceDestroyed(SurfaceHolder holder)
|
||||||
{
|
{
|
||||||
mEmulationState.clearSurface();
|
mEmulationState.clearSurface();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopEmulation()
|
public void stopEmulation()
|
||||||
{
|
{
|
||||||
mEmulationState.stop();
|
mEmulationState.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startConfiguringControls()
|
public void startConfiguringControls()
|
||||||
{
|
{
|
||||||
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
|
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
|
||||||
mInputOverlay.setIsInEditMode(true);
|
mInputOverlay.setIsInEditMode(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stopConfiguringControls()
|
public void stopConfiguringControls()
|
||||||
{
|
{
|
||||||
getView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
|
getView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
|
||||||
mInputOverlay.setIsInEditMode(false);
|
mInputOverlay.setIsInEditMode(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConfiguringControls()
|
public boolean isConfiguringControls()
|
||||||
{
|
{
|
||||||
return mInputOverlay.isInEditMode();
|
return mInputOverlay.isInEditMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class EmulationState
|
private static class EmulationState
|
||||||
{
|
{
|
||||||
private enum State
|
private enum State
|
||||||
{
|
{
|
||||||
STOPPED, RUNNING, PAUSED
|
STOPPED, RUNNING, PAUSED
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String mGamePath;
|
private final String mGamePath;
|
||||||
private Thread mEmulationThread;
|
private Thread mEmulationThread;
|
||||||
private State state;
|
private State state;
|
||||||
private Surface mSurface;
|
private Surface mSurface;
|
||||||
private boolean mRunWhenSurfaceIsValid;
|
private boolean mRunWhenSurfaceIsValid;
|
||||||
private boolean loadPreviousTemporaryState;
|
private boolean loadPreviousTemporaryState;
|
||||||
private boolean firstOpen;
|
private boolean firstOpen;
|
||||||
private final String temporaryStatePath;
|
private final String temporaryStatePath;
|
||||||
|
|
||||||
EmulationState(String gamePath, String temporaryStatePath, boolean firstOpen)
|
EmulationState(String gamePath, String temporaryStatePath, boolean firstOpen)
|
||||||
{
|
{
|
||||||
this.firstOpen = firstOpen;
|
this.firstOpen = firstOpen;
|
||||||
mGamePath = gamePath;
|
mGamePath = gamePath;
|
||||||
this.temporaryStatePath = temporaryStatePath;
|
this.temporaryStatePath = temporaryStatePath;
|
||||||
// Starting state is stopped.
|
// Starting state is stopped.
|
||||||
state = State.STOPPED;
|
state = State.STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters for the current state
|
// Getters for the current state
|
||||||
|
|
||||||
public synchronized boolean isStopped()
|
public synchronized boolean isStopped()
|
||||||
{
|
{
|
||||||
return state == State.STOPPED;
|
return state == State.STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean isPaused()
|
public synchronized boolean isPaused()
|
||||||
{
|
{
|
||||||
return state == State.PAUSED;
|
return state == State.PAUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean isRunning()
|
public synchronized boolean isRunning()
|
||||||
{
|
{
|
||||||
return state == State.RUNNING;
|
return state == State.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
// State changing methods
|
// State changing methods
|
||||||
|
|
||||||
public synchronized void stop()
|
public synchronized void stop()
|
||||||
{
|
{
|
||||||
if (state != State.STOPPED)
|
if (state != State.STOPPED)
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] Stopping emulation.");
|
Log.debug("[EmulationFragment] Stopping emulation.");
|
||||||
state = State.STOPPED;
|
state = State.STOPPED;
|
||||||
NativeLibrary.StopEmulation();
|
NativeLibrary.StopEmulation();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.warning("[EmulationFragment] Stop called while already stopped.");
|
Log.warning("[EmulationFragment] Stop called while already stopped.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void pause()
|
public synchronized void pause()
|
||||||
{
|
{
|
||||||
if (state != State.PAUSED)
|
if (state != State.PAUSED)
|
||||||
{
|
{
|
||||||
state = State.PAUSED;
|
state = State.PAUSED;
|
||||||
Log.debug("[EmulationFragment] Pausing emulation.");
|
Log.debug("[EmulationFragment] Pausing emulation.");
|
||||||
|
|
||||||
// Release the surface before pausing, since emulation has to be running for that.
|
// Release the surface before pausing, since emulation has to be running for that.
|
||||||
NativeLibrary.SurfaceDestroyed();
|
NativeLibrary.SurfaceDestroyed();
|
||||||
NativeLibrary.PauseEmulation();
|
NativeLibrary.PauseEmulation();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.warning("[EmulationFragment] Pause called while already paused.");
|
Log.warning("[EmulationFragment] Pause called while already paused.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void run(boolean isActivityRecreated)
|
public synchronized void run(boolean isActivityRecreated)
|
||||||
{
|
{
|
||||||
if (isActivityRecreated)
|
if (isActivityRecreated)
|
||||||
{
|
{
|
||||||
if (NativeLibrary.IsRunning())
|
if (NativeLibrary.IsRunning())
|
||||||
{
|
{
|
||||||
loadPreviousTemporaryState = false;
|
loadPreviousTemporaryState = false;
|
||||||
state = State.PAUSED;
|
state = State.PAUSED;
|
||||||
deleteFile(temporaryStatePath);
|
deleteFile(temporaryStatePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loadPreviousTemporaryState = true;
|
loadPreviousTemporaryState = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] activity resumed or fresh start");
|
Log.debug("[EmulationFragment] activity resumed or fresh start");
|
||||||
loadPreviousTemporaryState = false;
|
loadPreviousTemporaryState = false;
|
||||||
// activity resumed without being killed or this is the first run
|
// activity resumed without being killed or this is the first run
|
||||||
deleteFile(temporaryStatePath);
|
deleteFile(temporaryStatePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the surface is set, run now. Otherwise, wait for it to get set.
|
// If the surface is set, run now. Otherwise, wait for it to get set.
|
||||||
if (mSurface != null)
|
if (mSurface != null)
|
||||||
{
|
{
|
||||||
runWithValidSurface();
|
runWithValidSurface();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mRunWhenSurfaceIsValid = true;
|
mRunWhenSurfaceIsValid = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Surface callbacks
|
// Surface callbacks
|
||||||
public synchronized void newSurface(Surface surface)
|
public synchronized void newSurface(Surface surface)
|
||||||
{
|
{
|
||||||
mSurface = surface;
|
mSurface = surface;
|
||||||
if (mRunWhenSurfaceIsValid)
|
if (mRunWhenSurfaceIsValid)
|
||||||
{
|
{
|
||||||
runWithValidSurface();
|
runWithValidSurface();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void clearSurface()
|
public synchronized void clearSurface()
|
||||||
{
|
{
|
||||||
if (mSurface == null)
|
if (mSurface == null)
|
||||||
{
|
{
|
||||||
Log.warning("[EmulationFragment] clearSurface called, but surface already null.");
|
Log.warning("[EmulationFragment] clearSurface called, but surface already null.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mSurface = null;
|
mSurface = null;
|
||||||
Log.debug("[EmulationFragment] Surface destroyed.");
|
Log.debug("[EmulationFragment] Surface destroyed.");
|
||||||
|
|
||||||
if (state == State.RUNNING)
|
if (state == State.RUNNING)
|
||||||
{
|
{
|
||||||
NativeLibrary.SurfaceDestroyed();
|
NativeLibrary.SurfaceDestroyed();
|
||||||
state = State.PAUSED;
|
state = State.PAUSED;
|
||||||
}
|
}
|
||||||
else if (state == State.PAUSED)
|
else if (state == State.PAUSED)
|
||||||
{
|
{
|
||||||
Log.warning("[EmulationFragment] Surface cleared while emulation paused.");
|
Log.warning("[EmulationFragment] Surface cleared while emulation paused.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.warning("[EmulationFragment] Surface cleared while emulation stopped.");
|
Log.warning("[EmulationFragment] Surface cleared while emulation stopped.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runWithValidSurface()
|
private void runWithValidSurface()
|
||||||
{
|
{
|
||||||
mRunWhenSurfaceIsValid = false;
|
mRunWhenSurfaceIsValid = false;
|
||||||
if (state == State.STOPPED)
|
if (state == State.STOPPED)
|
||||||
{
|
{
|
||||||
mEmulationThread = new Thread(() ->
|
mEmulationThread = new Thread(() ->
|
||||||
{
|
{
|
||||||
NativeLibrary.SurfaceChanged(mSurface);
|
NativeLibrary.SurfaceChanged(mSurface);
|
||||||
if (loadPreviousTemporaryState)
|
if (loadPreviousTemporaryState)
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] Starting emulation thread from previous state.");
|
Log.debug("[EmulationFragment] Starting emulation thread from previous state.");
|
||||||
NativeLibrary.Run(mGamePath, temporaryStatePath, true);
|
NativeLibrary.Run(mGamePath, temporaryStatePath, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] Starting emulation thread.");
|
Log.debug("[EmulationFragment] Starting emulation thread.");
|
||||||
NativeLibrary.Run(mGamePath, firstOpen);
|
NativeLibrary.Run(mGamePath, firstOpen);
|
||||||
}
|
}
|
||||||
}, "NativeEmulation");
|
}, "NativeEmulation");
|
||||||
mEmulationThread.start();
|
mEmulationThread.start();
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (state == State.PAUSED)
|
else if (state == State.PAUSED)
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] Resuming emulation.");
|
Log.debug("[EmulationFragment] Resuming emulation.");
|
||||||
NativeLibrary.SurfaceChanged(mSurface);
|
NativeLibrary.SurfaceChanged(mSurface);
|
||||||
NativeLibrary.UnPauseEmulation();
|
NativeLibrary.UnPauseEmulation();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] Bug, run called while already running.");
|
Log.debug("[EmulationFragment] Bug, run called while already running.");
|
||||||
}
|
}
|
||||||
state = State.RUNNING;
|
state = State.RUNNING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveTemporaryState()
|
public void saveTemporaryState()
|
||||||
{
|
{
|
||||||
NativeLibrary.SaveStateAs(getTemporaryStateFilePath(), true);
|
NativeLibrary.SaveStateAs(getTemporaryStateFilePath(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTemporaryStateFilePath()
|
private String getTemporaryStateFilePath()
|
||||||
{
|
{
|
||||||
return getContext().getFilesDir() + File.separator + "temp.sav";
|
return getContext().getFilesDir() + File.separator + "temp.sav";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void deleteFile(String path)
|
private static void deleteFile(String path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File file = new File(path);
|
File file = new File(path);
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// fail safely
|
// fail safely
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,62 +16,68 @@ import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
|
|
||||||
public final class MenuFragment extends Fragment implements View.OnClickListener
|
public final class MenuFragment extends Fragment implements View.OnClickListener
|
||||||
{
|
{
|
||||||
private static final String KEY_TITLE = "title";
|
private static final String KEY_TITLE = "title";
|
||||||
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MenuFragment newInstance(String title)
|
static
|
||||||
{
|
{
|
||||||
MenuFragment fragment = new MenuFragment();
|
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();
|
public static MenuFragment newInstance(String title)
|
||||||
arguments.putSerializable(KEY_TITLE, title);
|
{
|
||||||
fragment.setArguments(arguments);
|
MenuFragment fragment = new MenuFragment();
|
||||||
|
|
||||||
return fragment;
|
Bundle arguments = new Bundle();
|
||||||
}
|
arguments.putSerializable(KEY_TITLE, title);
|
||||||
|
fragment.setArguments(arguments);
|
||||||
|
|
||||||
@Nullable
|
return fragment;
|
||||||
@Override
|
}
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
View rootView = inflater.inflate(R.layout.fragment_ingame_menu, container, false);
|
|
||||||
|
|
||||||
LinearLayout options = (LinearLayout) rootView.findViewById(R.id.layout_options);
|
@Nullable
|
||||||
for (int childIndex = 0; childIndex < options.getChildCount(); childIndex++)
|
@Override
|
||||||
{
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||||
Button button = (Button) options.getChildAt(childIndex);
|
{
|
||||||
|
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);
|
button.setOnClickListener(this);
|
||||||
String title = getArguments().getString(KEY_TITLE);
|
}
|
||||||
if (title != null)
|
|
||||||
{
|
|
||||||
titleText.setText(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
return rootView;
|
||||||
@Override
|
}
|
||||||
public void onClick(View button)
|
|
||||||
{
|
@SuppressWarnings("WrongConstant")
|
||||||
int action = buttonsActionsMap.get(button.getId());
|
@Override
|
||||||
if (action >= 0)
|
public void onClick(View button)
|
||||||
{
|
{
|
||||||
((EmulationActivity) getActivity()).handleMenuAction(action);
|
int action = buttonsActionsMap.get(button.getId());
|
||||||
}
|
if (action >= 0)
|
||||||
}
|
{
|
||||||
|
((EmulationActivity) getActivity()).handleMenuAction(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,86 +15,104 @@ import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
|
|
||||||
public final class SaveLoadStateFragment extends Fragment implements View.OnClickListener
|
public final class SaveLoadStateFragment extends Fragment implements View.OnClickListener
|
||||||
{
|
{
|
||||||
public enum SaveOrLoad
|
public enum SaveOrLoad
|
||||||
{
|
{
|
||||||
SAVE, LOAD
|
SAVE, LOAD
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String KEY_SAVEORLOAD = "saveorload";
|
private static final String KEY_SAVEORLOAD = "saveorload";
|
||||||
private static SparseIntArray saveButtonsActionsMap = new SparseIntArray();
|
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;
|
|
||||||
|
|
||||||
public static SaveLoadStateFragment newInstance(SaveOrLoad saveOrLoad)
|
static
|
||||||
{
|
{
|
||||||
SaveLoadStateFragment fragment = new SaveLoadStateFragment();
|
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();
|
private static SparseIntArray loadButtonsActionsMap = new SparseIntArray();
|
||||||
arguments.putSerializable(KEY_SAVEORLOAD, saveOrLoad);
|
|
||||||
fragment.setArguments(arguments);
|
|
||||||
|
|
||||||
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
|
private SaveOrLoad mSaveOrLoad;
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState)
|
|
||||||
{
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
mSaveOrLoad = (SaveOrLoad) getArguments().getSerializable(KEY_SAVEORLOAD);
|
public static SaveLoadStateFragment newInstance(SaveOrLoad saveOrLoad)
|
||||||
}
|
{
|
||||||
|
SaveLoadStateFragment fragment = new SaveLoadStateFragment();
|
||||||
|
|
||||||
@Nullable
|
Bundle arguments = new Bundle();
|
||||||
@Override
|
arguments.putSerializable(KEY_SAVEORLOAD, saveOrLoad);
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
fragment.setArguments(arguments);
|
||||||
{
|
|
||||||
View rootView = inflater.inflate(R.layout.fragment_saveload_state, container, false);
|
|
||||||
|
|
||||||
GridLayout grid = (GridLayout) rootView.findViewById(R.id.grid_state_slots);
|
return fragment;
|
||||||
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.
|
@Override
|
||||||
grid.requestFocus();
|
public void onCreate(@Nullable Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
return rootView;
|
mSaveOrLoad = (SaveOrLoad) getArguments().getSerializable(KEY_SAVEORLOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("WrongConstant")
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View button)
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
int action = 0;
|
View rootView = inflater.inflate(R.layout.fragment_saveload_state, container, false);
|
||||||
switch(mSaveOrLoad)
|
|
||||||
{
|
GridLayout grid = (GridLayout) rootView.findViewById(R.id.grid_state_slots);
|
||||||
case SAVE:
|
for (int childIndex = 0; childIndex < grid.getChildCount(); childIndex++)
|
||||||
action = saveButtonsActionsMap.get(button.getId(), -1);
|
{
|
||||||
break;
|
Button button = (Button) grid.getChildAt(childIndex);
|
||||||
case LOAD:
|
button.setOnClickListener(this);
|
||||||
action = loadButtonsActionsMap.get(button.getId(), -1);
|
}
|
||||||
}
|
|
||||||
if (action >= 0)
|
// So that item clicked to start this Fragment is no longer the focused item.
|
||||||
{
|
grid.requestFocus();
|
||||||
((EmulationActivity) getActivity()).handleMenuAction(action);
|
|
||||||
}
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,50 +1,56 @@
|
||||||
package org.dolphinemu.dolphinemu.model;
|
package org.dolphinemu.dolphinemu.model;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.utils.CoverHelper;
|
|
||||||
|
|
||||||
public class GameFile
|
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)
|
private GameFile(long pointer)
|
||||||
{
|
{
|
||||||
mPointer = pointer;
|
mPointer = pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public native void finalize();
|
public native void finalize();
|
||||||
|
|
||||||
public native int getPlatform();
|
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 String getCoverPath()
|
public native String getTitle();
|
||||||
{
|
|
||||||
return Environment.getExternalStorageDirectory().getPath() +
|
|
||||||
"/dolphin-emu/Cache/GameCovers/" + getGameId() + ".png";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCustomCoverPath()
|
public native String getDescription();
|
||||||
{
|
|
||||||
return getPath().substring(0, getPath().lastIndexOf(".")) + ".cover.png";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getScreenshotPath()
|
public native String getCompany();
|
||||||
{
|
|
||||||
String gameId = getGameId();
|
public native int getCountry();
|
||||||
return "file://" + Environment.getExternalStorageDirectory().getPath() +
|
|
||||||
"/dolphin-emu/ScreenShots/" + gameId + "/" + gameId + "-1.png";
|
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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,80 +10,86 @@ import java.util.Set;
|
||||||
|
|
||||||
public class GameFileCache
|
public class GameFileCache
|
||||||
{
|
{
|
||||||
private static final String GAME_FOLDER_PATHS_PREFERENCE = "gameFolderPaths";
|
private static final String GAME_FOLDER_PATHS_PREFERENCE = "gameFolderPaths";
|
||||||
private static final Set<String> EMPTY_SET = new HashSet<>();
|
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)
|
public GameFileCache(String path)
|
||||||
{
|
{
|
||||||
mPointer = newGameFileCache(path);
|
mPointer = newGameFileCache(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native long newGameFileCache(String path);
|
private static native long newGameFileCache(String path);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public native void finalize();
|
public native void finalize();
|
||||||
|
|
||||||
public static void addGameFolder(String path, Context context)
|
public static void addGameFolder(String path, Context context)
|
||||||
{
|
{
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
Set<String> folderPaths = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
|
Set<String> folderPaths = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
|
||||||
Set<String> newFolderPaths = new HashSet<>(folderPaths);
|
Set<String> newFolderPaths = new HashSet<>(folderPaths);
|
||||||
newFolderPaths.add(path);
|
newFolderPaths.add(path);
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
editor.putStringSet(GAME_FOLDER_PATHS_PREFERENCE, newFolderPaths);
|
editor.putStringSet(GAME_FOLDER_PATHS_PREFERENCE, newFolderPaths);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeNonExistentGameFolders(Context context)
|
private void removeNonExistentGameFolders(Context context)
|
||||||
{
|
{
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
Set<String> folderPaths = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
|
Set<String> folderPaths = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
|
||||||
Set<String> newFolderPaths = new HashSet<>();
|
Set<String> newFolderPaths = new HashSet<>();
|
||||||
for (String folderPath : folderPaths)
|
for (String folderPath : folderPaths)
|
||||||
{
|
{
|
||||||
File folder = new File(folderPath);
|
File folder = new File(folderPath);
|
||||||
if (folder.exists())
|
if (folder.exists())
|
||||||
{
|
{
|
||||||
newFolderPaths.add(folderPath);
|
newFolderPaths.add(folderPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folderPaths.size() != newFolderPaths.size())
|
if (folderPaths.size() != newFolderPaths.size())
|
||||||
{
|
{
|
||||||
// One or more folders are being deleted
|
// One or more folders are being deleted
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
editor.putStringSet(GAME_FOLDER_PATHS_PREFERENCE, newFolderPaths);
|
editor.putStringSet(GAME_FOLDER_PATHS_PREFERENCE, newFolderPaths);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans through the file system and updates the cache to match.
|
* Scans through the file system and updates the cache to match.
|
||||||
* @return true if the cache was modified
|
*
|
||||||
*/
|
* @return true if the cache was modified
|
||||||
public boolean scanLibrary(Context context)
|
*/
|
||||||
{
|
public boolean scanLibrary(Context context)
|
||||||
removeNonExistentGameFolders(context);
|
{
|
||||||
|
removeNonExistentGameFolders(context);
|
||||||
|
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
Set<String> folderPathsSet = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
|
Set<String> folderPathsSet = preferences.getStringSet(GAME_FOLDER_PATHS_PREFERENCE, EMPTY_SET);
|
||||||
String[] folderPaths = folderPathsSet.toArray(new String[folderPathsSet.size()]);
|
String[] folderPaths = folderPathsSet.toArray(new String[folderPathsSet.size()]);
|
||||||
|
|
||||||
boolean cacheChanged = update(folderPaths);
|
boolean cacheChanged = update(folderPaths);
|
||||||
cacheChanged |= updateAdditionalMetadata();
|
cacheChanged |= updateAdditionalMetadata();
|
||||||
if (cacheChanged)
|
if (cacheChanged)
|
||||||
{
|
{
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
return cacheChanged;
|
return cacheChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public native GameFile[] getAllGames();
|
public native GameFile[] getAllGames();
|
||||||
public native GameFile addOrGet(String gamePath);
|
|
||||||
private native boolean update(String[] folderPaths);
|
public native GameFile addOrGet(String gamePath);
|
||||||
private native boolean updateAdditionalMetadata();
|
|
||||||
public native boolean load();
|
private native boolean update(String[] folderPaths);
|
||||||
private native boolean save();
|
|
||||||
|
private native boolean updateAdditionalMetadata();
|
||||||
|
|
||||||
|
public native boolean load();
|
||||||
|
|
||||||
|
private native boolean save();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,59 +6,59 @@ package org.dolphinemu.dolphinemu.model;
|
||||||
public class HomeScreenChannel
|
public class HomeScreenChannel
|
||||||
{
|
{
|
||||||
|
|
||||||
private long channelId;
|
private long channelId;
|
||||||
private String name;
|
private String name;
|
||||||
private String description;
|
private String description;
|
||||||
private String appLinkIntentUri;
|
private String appLinkIntentUri;
|
||||||
|
|
||||||
public HomeScreenChannel()
|
public HomeScreenChannel()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public HomeScreenChannel(String name, String description, String appLinkIntentUri)
|
public HomeScreenChannel(String name, String description, String appLinkIntentUri)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.appLinkIntentUri = appLinkIntentUri;
|
this.appLinkIntentUri = appLinkIntentUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getChannelId()
|
public long getChannelId()
|
||||||
{
|
{
|
||||||
return channelId;
|
return channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setChannelId(long channelId)
|
public void setChannelId(long channelId)
|
||||||
{
|
{
|
||||||
this.channelId = channelId;
|
this.channelId = channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name)
|
public void setName(String name)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription()
|
public String getDescription()
|
||||||
{
|
{
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDescription(String description)
|
public void setDescription(String description)
|
||||||
{
|
{
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAppLinkIntentUri()
|
public String getAppLinkIntentUri()
|
||||||
{
|
{
|
||||||
return appLinkIntentUri;
|
return appLinkIntentUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAppLinkIntentUri(String appLinkIntentUri)
|
public void setAppLinkIntentUri(String appLinkIntentUri)
|
||||||
{
|
{
|
||||||
this.appLinkIntentUri = appLinkIntentUri;
|
this.appLinkIntentUri = appLinkIntentUri;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,29 +2,29 @@ package org.dolphinemu.dolphinemu.model;
|
||||||
|
|
||||||
public final class TvSettingsItem
|
public final class TvSettingsItem
|
||||||
{
|
{
|
||||||
private final int mItemId;
|
private final int mItemId;
|
||||||
private final int mIconId;
|
private final int mIconId;
|
||||||
private final int mLabelId;
|
private final int mLabelId;
|
||||||
|
|
||||||
public TvSettingsItem(int itemId, int iconId, int labelId)
|
public TvSettingsItem(int itemId, int iconId, int labelId)
|
||||||
{
|
{
|
||||||
mItemId = itemId;
|
mItemId = itemId;
|
||||||
mIconId = iconId;
|
mIconId = iconId;
|
||||||
mLabelId = labelId;
|
mLabelId = labelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getItemId()
|
public int getItemId()
|
||||||
{
|
{
|
||||||
return mItemId;
|
return mItemId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIconId()
|
public int getIconId()
|
||||||
{
|
{
|
||||||
return mIconId;
|
return mIconId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLabelId()
|
public int getLabelId()
|
||||||
{
|
{
|
||||||
return mLabelId;
|
return mLabelId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,117 +19,119 @@ import android.view.MotionEvent;
|
||||||
*/
|
*/
|
||||||
public final class InputOverlayDrawableButton
|
public final class InputOverlayDrawableButton
|
||||||
{
|
{
|
||||||
// The ID identifying what type of button this Drawable represents.
|
// The ID identifying what type of button this Drawable represents.
|
||||||
private int mButtonType;
|
private int mButtonType;
|
||||||
private int mTrackId;
|
private int mTrackId;
|
||||||
private int mPreviousTouchX, mPreviousTouchY;
|
private int mPreviousTouchX, mPreviousTouchY;
|
||||||
private int mControlPositionX, mControlPositionY;
|
private int mControlPositionX, mControlPositionY;
|
||||||
private int mWidth;
|
private int mWidth;
|
||||||
private int mHeight;
|
private int mHeight;
|
||||||
private BitmapDrawable mDefaultStateBitmap;
|
private BitmapDrawable mDefaultStateBitmap;
|
||||||
private BitmapDrawable mPressedStateBitmap;
|
private BitmapDrawable mPressedStateBitmap;
|
||||||
private boolean mPressedState = false;
|
private boolean mPressedState = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param res {@link Resources} instance.
|
* @param res {@link Resources} instance.
|
||||||
* @param defaultStateBitmap {@link Bitmap} to use with the default state Drawable.
|
* @param defaultStateBitmap {@link Bitmap} to use with the default state Drawable.
|
||||||
* @param pressedStateBitmap {@link Bitmap} to use with the pressed state Drawable.
|
* @param pressedStateBitmap {@link Bitmap} to use with the pressed state Drawable.
|
||||||
* @param buttonType Identifier for this type of button.
|
* @param buttonType Identifier for this type of button.
|
||||||
*/
|
*/
|
||||||
public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap, Bitmap pressedStateBitmap, int buttonType)
|
public InputOverlayDrawableButton(Resources res, Bitmap defaultStateBitmap,
|
||||||
{
|
Bitmap pressedStateBitmap, int buttonType)
|
||||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
{
|
||||||
mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap);
|
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||||
mButtonType = buttonType;
|
mPressedStateBitmap = new BitmapDrawable(res, pressedStateBitmap);
|
||||||
|
mButtonType = buttonType;
|
||||||
|
|
||||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets this InputOverlayDrawableButton's button ID.
|
* Gets this InputOverlayDrawableButton's button ID.
|
||||||
*
|
*
|
||||||
* @return this InputOverlayDrawableButton's button ID.
|
* @return this InputOverlayDrawableButton's button ID.
|
||||||
*/
|
*/
|
||||||
public int getId()
|
public int getId()
|
||||||
{
|
{
|
||||||
return mButtonType;
|
return mButtonType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTrackId(int trackId)
|
public void setTrackId(int trackId)
|
||||||
{
|
{
|
||||||
mTrackId = trackId;
|
mTrackId = trackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTrackId()
|
public int getTrackId()
|
||||||
{
|
{
|
||||||
return mTrackId;
|
return mTrackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onConfigureTouch(MotionEvent event)
|
public boolean onConfigureTouch(MotionEvent event)
|
||||||
{
|
{
|
||||||
int pointerIndex = event.getActionIndex();
|
int pointerIndex = event.getActionIndex();
|
||||||
int fingerPositionX = (int)event.getX(pointerIndex);
|
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||||
int fingerPositionY = (int)event.getY(pointerIndex);
|
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||||
switch (event.getAction())
|
switch (event.getAction())
|
||||||
{
|
{
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
mPreviousTouchX = fingerPositionX;
|
mPreviousTouchX = fingerPositionX;
|
||||||
mPreviousTouchY = fingerPositionY;
|
mPreviousTouchY = fingerPositionY;
|
||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_MOVE:
|
case MotionEvent.ACTION_MOVE:
|
||||||
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
||||||
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
||||||
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX, getHeight() + mControlPositionY);
|
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX,
|
||||||
mPreviousTouchX = fingerPositionX;
|
getHeight() + mControlPositionY);
|
||||||
mPreviousTouchY = fingerPositionY;
|
mPreviousTouchX = fingerPositionX;
|
||||||
break;
|
mPreviousTouchY = fingerPositionY;
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(int x, int y)
|
public void setPosition(int x, int y)
|
||||||
{
|
{
|
||||||
mControlPositionX = x;
|
mControlPositionX = x;
|
||||||
mControlPositionY = y;
|
mControlPositionY = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Canvas canvas)
|
public void draw(Canvas canvas)
|
||||||
{
|
{
|
||||||
getCurrentStateBitmapDrawable().draw(canvas);
|
getCurrentStateBitmapDrawable().draw(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitmapDrawable getCurrentStateBitmapDrawable()
|
private BitmapDrawable getCurrentStateBitmapDrawable()
|
||||||
{
|
{
|
||||||
return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap;
|
return mPressedState ? mPressedStateBitmap : mDefaultStateBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBounds(int left, int top, int right, int bottom)
|
public void setBounds(int left, int top, int right, int bottom)
|
||||||
{
|
{
|
||||||
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
||||||
mPressedStateBitmap.setBounds(left, top, right, bottom);
|
mPressedStateBitmap.setBounds(left, top, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect getBounds()
|
public Rect getBounds()
|
||||||
{
|
{
|
||||||
return mDefaultStateBitmap.getBounds();
|
return mDefaultStateBitmap.getBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWidth()
|
public int getWidth()
|
||||||
{
|
{
|
||||||
return mWidth;
|
return mWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHeight()
|
public int getHeight()
|
||||||
{
|
{
|
||||||
return mHeight;
|
return mHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPressedState(boolean isPressed)
|
public void setPressedState(boolean isPressed)
|
||||||
{
|
{
|
||||||
mPressedState = isPressed;
|
mPressedState = isPressed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,183 +19,188 @@ import android.view.MotionEvent;
|
||||||
*/
|
*/
|
||||||
public final class InputOverlayDrawableDpad
|
public final class InputOverlayDrawableDpad
|
||||||
{
|
{
|
||||||
// The ID identifying what type of button this Drawable represents.
|
// The ID identifying what type of button this Drawable represents.
|
||||||
private int[] mButtonType = new int[4];
|
private int[] mButtonType = new int[4];
|
||||||
private int mTrackId;
|
private int mTrackId;
|
||||||
private int mPreviousTouchX, mPreviousTouchY;
|
private int mPreviousTouchX, mPreviousTouchY;
|
||||||
private int mControlPositionX, mControlPositionY;
|
private int mControlPositionX, mControlPositionY;
|
||||||
private int mWidth;
|
private int mWidth;
|
||||||
private int mHeight;
|
private int mHeight;
|
||||||
private BitmapDrawable mDefaultStateBitmap;
|
private BitmapDrawable mDefaultStateBitmap;
|
||||||
private BitmapDrawable mPressedOneDirectionStateBitmap;
|
private BitmapDrawable mPressedOneDirectionStateBitmap;
|
||||||
private BitmapDrawable mPressedTwoDirectionsStateBitmap;
|
private BitmapDrawable mPressedTwoDirectionsStateBitmap;
|
||||||
private int mPressState = STATE_DEFAULT;
|
private int mPressState = STATE_DEFAULT;
|
||||||
|
|
||||||
public static final int STATE_DEFAULT = 0;
|
public static final int STATE_DEFAULT = 0;
|
||||||
public static final int STATE_PRESSED_UP = 1;
|
public static final int STATE_PRESSED_UP = 1;
|
||||||
public static final int STATE_PRESSED_DOWN = 2;
|
public static final int STATE_PRESSED_DOWN = 2;
|
||||||
public static final int STATE_PRESSED_LEFT = 3;
|
public static final int STATE_PRESSED_LEFT = 3;
|
||||||
public static final int STATE_PRESSED_RIGHT = 4;
|
public static final int STATE_PRESSED_RIGHT = 4;
|
||||||
public static final int STATE_PRESSED_UP_LEFT = 5;
|
public static final int STATE_PRESSED_UP_LEFT = 5;
|
||||||
public static final int STATE_PRESSED_UP_RIGHT = 6;
|
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_LEFT = 7;
|
||||||
public static final int STATE_PRESSED_DOWN_RIGHT = 8;
|
public static final int STATE_PRESSED_DOWN_RIGHT = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param res {@link Resources} instance.
|
* @param res {@link Resources} instance.
|
||||||
* @param defaultStateBitmap {@link Bitmap} of the default state.
|
* @param defaultStateBitmap {@link Bitmap} of the default state.
|
||||||
* @param pressedOneDirectionStateBitmap {@link Bitmap} of the pressed state in one direction.
|
* @param pressedOneDirectionStateBitmap {@link Bitmap} of the pressed state in one direction.
|
||||||
* @param pressedTwoDirectionsStateBitmap {@link Bitmap} of the pressed state in two direction.
|
* @param pressedTwoDirectionsStateBitmap {@link Bitmap} of the pressed state in two direction.
|
||||||
* @param buttonUp Identifier for the up button.
|
* @param buttonUp Identifier for the up button.
|
||||||
* @param buttonDown Identifier for the down button.
|
* @param buttonDown Identifier for the down button.
|
||||||
* @param buttonLeft Identifier for the left button.
|
* @param buttonLeft Identifier for the left button.
|
||||||
* @param buttonRight Identifier for the right button.
|
* @param buttonRight Identifier for the right button.
|
||||||
*/
|
*/
|
||||||
public InputOverlayDrawableDpad(Resources res,
|
public InputOverlayDrawableDpad(Resources res,
|
||||||
Bitmap defaultStateBitmap,
|
Bitmap defaultStateBitmap,
|
||||||
Bitmap pressedOneDirectionStateBitmap,
|
Bitmap pressedOneDirectionStateBitmap,
|
||||||
Bitmap pressedTwoDirectionsStateBitmap,
|
Bitmap pressedTwoDirectionsStateBitmap,
|
||||||
int buttonUp, int buttonDown,
|
int buttonUp, int buttonDown,
|
||||||
int buttonLeft, int buttonRight)
|
int buttonLeft, int buttonRight)
|
||||||
{
|
{
|
||||||
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
mDefaultStateBitmap = new BitmapDrawable(res, defaultStateBitmap);
|
||||||
mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap);
|
mPressedOneDirectionStateBitmap = new BitmapDrawable(res, pressedOneDirectionStateBitmap);
|
||||||
mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap);
|
mPressedTwoDirectionsStateBitmap = new BitmapDrawable(res, pressedTwoDirectionsStateBitmap);
|
||||||
|
|
||||||
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
mWidth = mDefaultStateBitmap.getIntrinsicWidth();
|
||||||
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
mHeight = mDefaultStateBitmap.getIntrinsicHeight();
|
||||||
|
|
||||||
mButtonType[0] = buttonUp;
|
mButtonType[0] = buttonUp;
|
||||||
mButtonType[1] = buttonDown;
|
mButtonType[1] = buttonDown;
|
||||||
mButtonType[2] = buttonLeft;
|
mButtonType[2] = buttonLeft;
|
||||||
mButtonType[3] = buttonRight;
|
mButtonType[3] = buttonRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Canvas canvas)
|
public void draw(Canvas canvas)
|
||||||
{
|
{
|
||||||
int px = mControlPositionX + (getWidth()/2);
|
int px = mControlPositionX + (getWidth() / 2);
|
||||||
int py = mControlPositionY + (getHeight()/2);
|
int py = mControlPositionY + (getHeight() / 2);
|
||||||
switch (mPressState) {
|
switch (mPressState)
|
||||||
case STATE_DEFAULT:
|
{
|
||||||
mDefaultStateBitmap.draw(canvas);
|
case STATE_DEFAULT:
|
||||||
break;
|
mDefaultStateBitmap.draw(canvas);
|
||||||
case STATE_PRESSED_UP:
|
break;
|
||||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
case STATE_PRESSED_UP:
|
||||||
break;
|
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||||
case STATE_PRESSED_RIGHT:
|
break;
|
||||||
canvas.save();
|
case STATE_PRESSED_RIGHT:
|
||||||
canvas.rotate(90, px, py);
|
canvas.save();
|
||||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
canvas.rotate(90, px, py);
|
||||||
canvas.restore();
|
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||||
break;
|
canvas.restore();
|
||||||
case STATE_PRESSED_DOWN:
|
break;
|
||||||
canvas.save();
|
case STATE_PRESSED_DOWN:
|
||||||
canvas.rotate(180, px, py);
|
canvas.save();
|
||||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
canvas.rotate(180, px, py);
|
||||||
canvas.restore();
|
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||||
break;
|
canvas.restore();
|
||||||
case STATE_PRESSED_LEFT:
|
break;
|
||||||
canvas.save();
|
case STATE_PRESSED_LEFT:
|
||||||
canvas.rotate(270, px, py);
|
canvas.save();
|
||||||
mPressedOneDirectionStateBitmap.draw(canvas);
|
canvas.rotate(270, px, py);
|
||||||
canvas.restore();
|
mPressedOneDirectionStateBitmap.draw(canvas);
|
||||||
break;
|
canvas.restore();
|
||||||
case STATE_PRESSED_UP_LEFT:
|
break;
|
||||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
case STATE_PRESSED_UP_LEFT:
|
||||||
break;
|
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||||
case STATE_PRESSED_UP_RIGHT:
|
break;
|
||||||
canvas.save();
|
case STATE_PRESSED_UP_RIGHT:
|
||||||
canvas.rotate(90, px, py);
|
canvas.save();
|
||||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
canvas.rotate(90, px, py);
|
||||||
canvas.restore();
|
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||||
break;
|
canvas.restore();
|
||||||
case STATE_PRESSED_DOWN_RIGHT:
|
break;
|
||||||
canvas.save();
|
case STATE_PRESSED_DOWN_RIGHT:
|
||||||
canvas.rotate(180, px, py);
|
canvas.save();
|
||||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
canvas.rotate(180, px, py);
|
||||||
canvas.restore();
|
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||||
break;
|
canvas.restore();
|
||||||
case STATE_PRESSED_DOWN_LEFT:
|
break;
|
||||||
canvas.save();
|
case STATE_PRESSED_DOWN_LEFT:
|
||||||
canvas.rotate(270, px, py);
|
canvas.save();
|
||||||
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
canvas.rotate(270, px, py);
|
||||||
canvas.restore();
|
mPressedTwoDirectionsStateBitmap.draw(canvas);
|
||||||
break;
|
canvas.restore();
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets one of the InputOverlayDrawableDpad's button IDs.
|
* Gets one of the InputOverlayDrawableDpad's button IDs.
|
||||||
*
|
*
|
||||||
* @return the requested InputOverlayDrawableDpad's button ID.
|
* @return the requested InputOverlayDrawableDpad's button ID.
|
||||||
*/
|
*/
|
||||||
public int getId(int direction)
|
public int getId(int direction)
|
||||||
{
|
{
|
||||||
return mButtonType[direction];
|
return mButtonType[direction];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTrackId(int trackId)
|
public void setTrackId(int trackId)
|
||||||
{
|
{
|
||||||
mTrackId = trackId;
|
mTrackId = trackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTrackId()
|
public int getTrackId()
|
||||||
{
|
{
|
||||||
return mTrackId;
|
return mTrackId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onConfigureTouch(MotionEvent event)
|
public boolean onConfigureTouch(MotionEvent event)
|
||||||
{
|
{
|
||||||
int pointerIndex = event.getActionIndex();
|
int pointerIndex = event.getActionIndex();
|
||||||
int fingerPositionX = (int)event.getX(pointerIndex);
|
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||||
int fingerPositionY = (int)event.getY(pointerIndex);
|
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||||
switch (event.getAction())
|
switch (event.getAction())
|
||||||
{
|
{
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
mPreviousTouchX = fingerPositionX;
|
mPreviousTouchX = fingerPositionX;
|
||||||
mPreviousTouchY = fingerPositionY;
|
mPreviousTouchY = fingerPositionY;
|
||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_MOVE:
|
case MotionEvent.ACTION_MOVE:
|
||||||
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
mControlPositionX += fingerPositionX - mPreviousTouchX;
|
||||||
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
mControlPositionY += fingerPositionY - mPreviousTouchY;
|
||||||
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX, getHeight() + mControlPositionY);
|
setBounds(mControlPositionX, mControlPositionY, getWidth() + mControlPositionX,
|
||||||
mPreviousTouchX = fingerPositionX;
|
getHeight() + mControlPositionY);
|
||||||
mPreviousTouchY = fingerPositionY;
|
mPreviousTouchX = fingerPositionX;
|
||||||
break;
|
mPreviousTouchY = fingerPositionY;
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(int x, int y)
|
public void setPosition(int x, int y)
|
||||||
{
|
{
|
||||||
mControlPositionX = x;
|
mControlPositionX = x;
|
||||||
mControlPositionY = y;
|
mControlPositionY = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBounds(int left, int top, int right, int bottom)
|
public void setBounds(int left, int top, int right, int bottom)
|
||||||
{
|
{
|
||||||
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
mDefaultStateBitmap.setBounds(left, top, right, bottom);
|
||||||
mPressedOneDirectionStateBitmap.setBounds(left, top, right, bottom);
|
mPressedOneDirectionStateBitmap.setBounds(left, top, right, bottom);
|
||||||
mPressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom);
|
mPressedTwoDirectionsStateBitmap.setBounds(left, top, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect getBounds()
|
public Rect getBounds()
|
||||||
{
|
{
|
||||||
return mDefaultStateBitmap.getBounds();
|
return mDefaultStateBitmap.getBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWidth() {
|
public int getWidth()
|
||||||
return mWidth;
|
{
|
||||||
}
|
return mWidth;
|
||||||
|
}
|
||||||
|
|
||||||
public int getHeight() {
|
public int getHeight()
|
||||||
return mHeight;
|
{
|
||||||
}
|
return mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
public void setState(int pressState) {
|
public void setState(int pressState)
|
||||||
mPressState = pressState;
|
{
|
||||||
}
|
mPressState = pressState;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
package org.dolphinemu.dolphinemu.overlay;
|
package org.dolphinemu.dolphinemu.overlay;
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
@ -21,246 +20,258 @@ import android.view.MotionEvent;
|
||||||
*/
|
*/
|
||||||
public final class InputOverlayDrawableJoystick
|
public final class InputOverlayDrawableJoystick
|
||||||
{
|
{
|
||||||
private SharedPreferences mPreferences;
|
private SharedPreferences mPreferences;
|
||||||
|
|
||||||
private final int[] axisIDs = {0, 0, 0, 0};
|
private final int[] axisIDs = {0, 0, 0, 0};
|
||||||
private final float[] axises = {0f, 0f};
|
private final float[] axises = {0f, 0f};
|
||||||
private int trackId = -1;
|
private int trackId = -1;
|
||||||
private int mJoystickType;
|
private int mJoystickType;
|
||||||
private int mControlPositionX, mControlPositionY;
|
private int mControlPositionX, mControlPositionY;
|
||||||
private int mPreviousTouchX, mPreviousTouchY;
|
private int mPreviousTouchX, mPreviousTouchY;
|
||||||
private int mWidth;
|
private int mWidth;
|
||||||
private int mHeight;
|
private int mHeight;
|
||||||
private Rect mVirtBounds;
|
private Rect mVirtBounds;
|
||||||
private Rect mOrigBounds;
|
private Rect mOrigBounds;
|
||||||
private BitmapDrawable mOuterBitmap;
|
private BitmapDrawable mOuterBitmap;
|
||||||
private BitmapDrawable mDefaultStateInnerBitmap;
|
private BitmapDrawable mDefaultStateInnerBitmap;
|
||||||
private BitmapDrawable mPressedStateInnerBitmap;
|
private BitmapDrawable mPressedStateInnerBitmap;
|
||||||
private BitmapDrawable mBoundsBoxBitmap;
|
private BitmapDrawable mBoundsBoxBitmap;
|
||||||
private boolean mPressedState = false;
|
private boolean mPressedState = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param res {@link Resources} instance.
|
* @param res {@link Resources} instance.
|
||||||
* @param bitmapOuter {@link Bitmap} which represents the outer non-movable part of the joystick.
|
* @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 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 bitmapInnerPressed {@link Bitmap} which represents the pressed inner movable part of the joystick.
|
||||||
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
* @param rectOuter {@link Rect} which represents the outer joystick bounds.
|
||||||
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
* @param rectInner {@link Rect} which represents the inner joystick bounds.
|
||||||
* @param joystick Identifier for which joystick this is.
|
* @param joystick Identifier for which joystick this is.
|
||||||
*/
|
*/
|
||||||
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter,
|
public InputOverlayDrawableJoystick(Resources res, Bitmap bitmapOuter,
|
||||||
Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed,
|
Bitmap bitmapInnerDefault, Bitmap bitmapInnerPressed,
|
||||||
Rect rectOuter, Rect rectInner, int joystick, SharedPreferences prefsHandle)
|
Rect rectOuter, Rect rectInner, int joystick, SharedPreferences prefsHandle)
|
||||||
{
|
{
|
||||||
axisIDs[0] = joystick + 1;
|
axisIDs[0] = joystick + 1;
|
||||||
axisIDs[1] = joystick + 2;
|
axisIDs[1] = joystick + 2;
|
||||||
axisIDs[2] = joystick + 3;
|
axisIDs[2] = joystick + 3;
|
||||||
axisIDs[3] = joystick + 4;
|
axisIDs[3] = joystick + 4;
|
||||||
mJoystickType = joystick;
|
mJoystickType = joystick;
|
||||||
|
|
||||||
mPreferences = prefsHandle;
|
mPreferences = prefsHandle;
|
||||||
mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
|
mOuterBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||||
mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
|
mDefaultStateInnerBitmap = new BitmapDrawable(res, bitmapInnerDefault);
|
||||||
mPressedStateInnerBitmap = new BitmapDrawable(res, bitmapInnerPressed);
|
mPressedStateInnerBitmap = new BitmapDrawable(res, bitmapInnerPressed);
|
||||||
mBoundsBoxBitmap = new BitmapDrawable(res, bitmapOuter);
|
mBoundsBoxBitmap = new BitmapDrawable(res, bitmapOuter);
|
||||||
mWidth = bitmapOuter.getWidth();
|
mWidth = bitmapOuter.getWidth();
|
||||||
mHeight = bitmapOuter.getHeight();
|
mHeight = bitmapOuter.getHeight();
|
||||||
|
|
||||||
setBounds(rectOuter);
|
setBounds(rectOuter);
|
||||||
mDefaultStateInnerBitmap.setBounds(rectInner);
|
mDefaultStateInnerBitmap.setBounds(rectInner);
|
||||||
mPressedStateInnerBitmap.setBounds(rectInner);
|
mPressedStateInnerBitmap.setBounds(rectInner);
|
||||||
mVirtBounds = getBounds();
|
mVirtBounds = getBounds();
|
||||||
mOrigBounds = mOuterBitmap.copyBounds();
|
mOrigBounds = mOuterBitmap.copyBounds();
|
||||||
mBoundsBoxBitmap.setAlpha(0);
|
mBoundsBoxBitmap.setAlpha(0);
|
||||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
||||||
SetInnerBounds();
|
SetInnerBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets this InputOverlayDrawableJoystick's button ID.
|
* Gets this InputOverlayDrawableJoystick's button ID.
|
||||||
*
|
*
|
||||||
* @return this InputOverlayDrawableJoystick's button ID.
|
* @return this InputOverlayDrawableJoystick's button ID.
|
||||||
*/
|
*/
|
||||||
public int getId()
|
public int getId()
|
||||||
{
|
{
|
||||||
return mJoystickType;
|
return mJoystickType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Canvas canvas)
|
public void draw(Canvas canvas)
|
||||||
{
|
{
|
||||||
mOuterBitmap.draw(canvas);
|
mOuterBitmap.draw(canvas);
|
||||||
getCurrentStateBitmapDrawable().draw(canvas);
|
getCurrentStateBitmapDrawable().draw(canvas);
|
||||||
mBoundsBoxBitmap.draw(canvas);
|
mBoundsBoxBitmap.draw(canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TrackEvent(MotionEvent event)
|
public void TrackEvent(MotionEvent event)
|
||||||
{
|
{
|
||||||
boolean reCenter = mPreferences.getBoolean("joystickRelCenter", true);
|
boolean reCenter = mPreferences.getBoolean("joystickRelCenter", true);
|
||||||
int pointerIndex = event.getActionIndex();
|
int pointerIndex = event.getActionIndex();
|
||||||
|
|
||||||
switch(event.getAction() & MotionEvent.ACTION_MASK)
|
switch (event.getAction() & MotionEvent.ACTION_MASK)
|
||||||
{
|
{
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
case MotionEvent.ACTION_POINTER_DOWN:
|
case MotionEvent.ACTION_POINTER_DOWN:
|
||||||
if (getBounds().contains((int)event.getX(pointerIndex), (int)event.getY(pointerIndex)))
|
if (getBounds().contains((int) event.getX(pointerIndex), (int) event.getY(pointerIndex)))
|
||||||
{
|
{
|
||||||
mPressedState = true;
|
mPressedState = true;
|
||||||
mOuterBitmap.setAlpha(0);
|
mOuterBitmap.setAlpha(0);
|
||||||
mBoundsBoxBitmap.setAlpha(255);
|
mBoundsBoxBitmap.setAlpha(255);
|
||||||
if (reCenter)
|
if (reCenter)
|
||||||
{
|
{
|
||||||
getVirtBounds().offset((int)event.getX(pointerIndex) - getVirtBounds().centerX(), (int)event.getY(pointerIndex) - getVirtBounds().centerY());
|
getVirtBounds().offset((int) event.getX(pointerIndex) - getVirtBounds().centerX(),
|
||||||
}
|
(int) event.getY(pointerIndex) - getVirtBounds().centerY());
|
||||||
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
}
|
||||||
trackId = event.getPointerId(pointerIndex);
|
mBoundsBoxBitmap.setBounds(getVirtBounds());
|
||||||
}
|
trackId = event.getPointerId(pointerIndex);
|
||||||
break;
|
}
|
||||||
case MotionEvent.ACTION_UP:
|
break;
|
||||||
case MotionEvent.ACTION_POINTER_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
if (trackId == event.getPointerId(pointerIndex))
|
case MotionEvent.ACTION_POINTER_UP:
|
||||||
{
|
if (trackId == event.getPointerId(pointerIndex))
|
||||||
mPressedState = false;
|
{
|
||||||
axises[0] = axises[1] = 0.0f;
|
mPressedState = false;
|
||||||
mOuterBitmap.setAlpha(255);
|
axises[0] = axises[1] = 0.0f;
|
||||||
mBoundsBoxBitmap.setAlpha(0);
|
mOuterBitmap.setAlpha(255);
|
||||||
setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right, mOrigBounds.bottom));
|
mBoundsBoxBitmap.setAlpha(0);
|
||||||
setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right, mOrigBounds.bottom));
|
setVirtBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||||
SetInnerBounds();
|
mOrigBounds.bottom));
|
||||||
trackId = -1;
|
setBounds(new Rect(mOrigBounds.left, mOrigBounds.top, mOrigBounds.right,
|
||||||
}
|
mOrigBounds.bottom));
|
||||||
break;
|
SetInnerBounds();
|
||||||
}
|
trackId = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (trackId == -1)
|
if (trackId == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < event.getPointerCount(); i++)
|
for (int i = 0; i < event.getPointerCount(); i++)
|
||||||
{
|
{
|
||||||
if (trackId == event.getPointerId(i))
|
if (trackId == event.getPointerId(i))
|
||||||
{
|
{
|
||||||
float touchX = event.getX(i);
|
float touchX = event.getX(i);
|
||||||
float touchY = event.getY(i);
|
float touchY = event.getY(i);
|
||||||
float maxY = getVirtBounds().bottom;
|
float maxY = getVirtBounds().bottom;
|
||||||
float maxX = getVirtBounds().right;
|
float maxX = getVirtBounds().right;
|
||||||
touchX -= getVirtBounds().centerX();
|
touchX -= getVirtBounds().centerX();
|
||||||
maxX -= getVirtBounds().centerX();
|
maxX -= getVirtBounds().centerX();
|
||||||
touchY -= getVirtBounds().centerY();
|
touchY -= getVirtBounds().centerY();
|
||||||
maxY -= getVirtBounds().centerY();
|
maxY -= getVirtBounds().centerY();
|
||||||
final float AxisX = touchX / maxX;
|
final float AxisX = touchX / maxX;
|
||||||
final float AxisY = touchY / maxY;
|
final float AxisY = touchY / maxY;
|
||||||
axises[0] = AxisY;
|
axises[0] = AxisY;
|
||||||
axises[1] = AxisX;
|
axises[1] = AxisX;
|
||||||
|
|
||||||
SetInnerBounds();
|
SetInnerBounds();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onConfigureTouch(MotionEvent event)
|
public boolean onConfigureTouch(MotionEvent event)
|
||||||
{
|
{
|
||||||
int pointerIndex = event.getActionIndex();
|
int pointerIndex = event.getActionIndex();
|
||||||
int fingerPositionX = (int)event.getX(pointerIndex);
|
int fingerPositionX = (int) event.getX(pointerIndex);
|
||||||
int fingerPositionY = (int)event.getY(pointerIndex);
|
int fingerPositionY = (int) event.getY(pointerIndex);
|
||||||
switch (event.getAction())
|
switch (event.getAction())
|
||||||
{
|
{
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
mPreviousTouchX = fingerPositionX;
|
mPreviousTouchX = fingerPositionX;
|
||||||
mPreviousTouchY = fingerPositionY;
|
mPreviousTouchY = fingerPositionY;
|
||||||
break;
|
break;
|
||||||
case MotionEvent.ACTION_MOVE:
|
case MotionEvent.ACTION_MOVE:
|
||||||
int deltaX = fingerPositionX - mPreviousTouchX;
|
int deltaX = fingerPositionX - mPreviousTouchX;
|
||||||
int deltaY = fingerPositionY - mPreviousTouchY;
|
int deltaY = fingerPositionY - mPreviousTouchY;
|
||||||
mControlPositionX += deltaX;
|
mControlPositionX += deltaX;
|
||||||
mControlPositionY += deltaY;
|
mControlPositionY += deltaY;
|
||||||
setBounds(new Rect(mControlPositionX, mControlPositionY,
|
setBounds(new Rect(mControlPositionX, mControlPositionY,
|
||||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
||||||
setVirtBounds(new Rect(mControlPositionX, mControlPositionY,
|
setVirtBounds(new Rect(mControlPositionX, mControlPositionY,
|
||||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
mOuterBitmap.getIntrinsicHeight() + mControlPositionY));
|
||||||
SetInnerBounds();
|
SetInnerBounds();
|
||||||
setOrigBounds(new Rect(new Rect(mControlPositionX, mControlPositionY,
|
setOrigBounds(new Rect(new Rect(mControlPositionX, mControlPositionY,
|
||||||
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
mOuterBitmap.getIntrinsicWidth() + mControlPositionX,
|
||||||
mOuterBitmap.getIntrinsicHeight() + mControlPositionY)));
|
mOuterBitmap.getIntrinsicHeight() + mControlPositionY)));
|
||||||
mPreviousTouchX = fingerPositionX;
|
mPreviousTouchX = fingerPositionX;
|
||||||
mPreviousTouchY = fingerPositionY;
|
mPreviousTouchY = fingerPositionY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public float[] getAxisValues()
|
public float[] getAxisValues()
|
||||||
{
|
{
|
||||||
float[] joyaxises = {0f, 0f, 0f, 0f};
|
float[] joyaxises = {0f, 0f, 0f, 0f};
|
||||||
joyaxises[1] = Math.min(axises[0], 1.0f);
|
joyaxises[1] = Math.min(axises[0], 1.0f);
|
||||||
joyaxises[0] = Math.min(axises[0], 0.0f);
|
joyaxises[0] = Math.min(axises[0], 0.0f);
|
||||||
joyaxises[3] = Math.min(axises[1], 1.0f);
|
joyaxises[3] = Math.min(axises[1], 1.0f);
|
||||||
joyaxises[2] = Math.min(axises[1], 0.0f);
|
joyaxises[2] = Math.min(axises[1], 0.0f);
|
||||||
return joyaxises;
|
return joyaxises;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] getAxisIDs()
|
public int[] getAxisIDs()
|
||||||
{
|
{
|
||||||
return axisIDs;
|
return axisIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetInnerBounds()
|
private void SetInnerBounds()
|
||||||
{
|
{
|
||||||
int X = getVirtBounds().centerX() + (int)((axises[1]) * (getVirtBounds().width() / 2));
|
int X = getVirtBounds().centerX() + (int) ((axises[1]) * (getVirtBounds().width() / 2));
|
||||||
int Y = getVirtBounds().centerY() + (int)((axises[0]) * (getVirtBounds().height() / 2));
|
int Y = getVirtBounds().centerY() + (int) ((axises[0]) * (getVirtBounds().height() / 2));
|
||||||
|
|
||||||
if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2))
|
if (X > getVirtBounds().centerX() + (getVirtBounds().width() / 2))
|
||||||
X = getVirtBounds().centerX() + (getVirtBounds().width() / 2);
|
X = getVirtBounds().centerX() + (getVirtBounds().width() / 2);
|
||||||
if (X < getVirtBounds().centerX() - (getVirtBounds().width() / 2))
|
if (X < getVirtBounds().centerX() - (getVirtBounds().width() / 2))
|
||||||
X = getVirtBounds().centerX() - (getVirtBounds().width() / 2);
|
X = getVirtBounds().centerX() - (getVirtBounds().width() / 2);
|
||||||
if (Y > getVirtBounds().centerY() + (getVirtBounds().height() / 2))
|
if (Y > getVirtBounds().centerY() + (getVirtBounds().height() / 2))
|
||||||
Y = getVirtBounds().centerY() + (getVirtBounds().height() / 2);
|
Y = getVirtBounds().centerY() + (getVirtBounds().height() / 2);
|
||||||
if (Y < getVirtBounds().centerY() - (getVirtBounds().height() / 2))
|
if (Y < getVirtBounds().centerY() - (getVirtBounds().height() / 2))
|
||||||
Y = getVirtBounds().centerY() - (getVirtBounds().height() / 2);
|
Y = getVirtBounds().centerY() - (getVirtBounds().height() / 2);
|
||||||
|
|
||||||
int width = mPressedStateInnerBitmap.getBounds().width() / 2;
|
int width = mPressedStateInnerBitmap.getBounds().width() / 2;
|
||||||
int height = mPressedStateInnerBitmap.getBounds().height() / 2;
|
int height = mPressedStateInnerBitmap.getBounds().height() / 2;
|
||||||
mDefaultStateInnerBitmap.setBounds(X - width, Y - height, X + width, Y + height);
|
mDefaultStateInnerBitmap.setBounds(X - width, Y - height, X + width, Y + height);
|
||||||
mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds());
|
mPressedStateInnerBitmap.setBounds(mDefaultStateInnerBitmap.getBounds());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(int x, int y)
|
public void setPosition(int x, int y)
|
||||||
{
|
{
|
||||||
mControlPositionX = x;
|
mControlPositionX = x;
|
||||||
mControlPositionY = y;
|
mControlPositionY = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitmapDrawable getCurrentStateBitmapDrawable()
|
private BitmapDrawable getCurrentStateBitmapDrawable()
|
||||||
{
|
{
|
||||||
return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap;
|
return mPressedState ? mPressedStateInnerBitmap : mDefaultStateInnerBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBounds(Rect bounds)
|
public void setBounds(Rect bounds)
|
||||||
{
|
{
|
||||||
mOuterBitmap.setBounds(bounds);
|
mOuterBitmap.setBounds(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect getBounds()
|
public Rect getBounds()
|
||||||
{
|
{
|
||||||
return mOuterBitmap.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()
|
public int getWidth()
|
||||||
{
|
{
|
||||||
return mWidth;
|
return mWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHeight()
|
public int getHeight()
|
||||||
{
|
{
|
||||||
return mHeight;
|
return mHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,231 +32,239 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
*/
|
*/
|
||||||
public final class DirectoryInitializationService extends IntentService
|
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";
|
public static final String EXTRA_STATE = "directoryState";
|
||||||
private static volatile DirectoryInitializationState directoryState = null;
|
private static volatile DirectoryInitializationState directoryState = null;
|
||||||
private static String userPath;
|
private static String userPath;
|
||||||
private static String internalPath;
|
private static String internalPath;
|
||||||
private static AtomicBoolean isDolphinDirectoryInitializationRunning = new AtomicBoolean(false);
|
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,
|
if (PermissionsHandler.hasWriteAccess(this))
|
||||||
EXTERNAL_STORAGE_PERMISSION_NEEDED,
|
{
|
||||||
CANT_FIND_EXTERNAL_STORAGE
|
if (setDolphinUserDirectory())
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
initializeInternalStorage();
|
||||||
{
|
initializeExternalStorage();
|
||||||
if (setDolphinUserDirectory())
|
|
||||||
{
|
|
||||||
initializeInternalStorage();
|
|
||||||
initializeExternalStorage();
|
|
||||||
|
|
||||||
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
|
directoryState = DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
directoryState = DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
directoryState = DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
isDolphinDirectoryInitializationRunning.set(false);
|
{
|
||||||
sendBroadcastState(directoryState);
|
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)
|
||||||
File externalPath = Environment.getExternalStorageDirectory();
|
{
|
||||||
if (externalPath != null)
|
userPath = externalPath.getAbsolutePath() + "/dolphin-emu";
|
||||||
{
|
Log.debug("[DirectoryInitializationService] User Dir: " + userPath);
|
||||||
userPath = externalPath.getAbsolutePath() + "/dolphin-emu";
|
NativeLibrary.SetUserDirectory(userPath);
|
||||||
Log.debug("[DirectoryInitializationService] User Dir: " + userPath);
|
return true;
|
||||||
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");
|
// There is no extracted Sys directory, or there is a Sys directory from another
|
||||||
internalPath = sysDirectory.getAbsolutePath();
|
// version of Dolphin that might contain outdated files. Let's (re-)extract Sys.
|
||||||
|
deleteDirectoryRecursively(sysDirectory);
|
||||||
|
copyAssetFolder("Sys", sysDirectory, true);
|
||||||
|
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
String revision = NativeLibrary.GetGitRevision();
|
editor.putString("sysDirectoryVersion", revision);
|
||||||
if (!preferences.getString("sysDirectoryVersion", "").equals(revision))
|
editor.apply();
|
||||||
{
|
|
||||||
// There is no extracted Sys directory, or there is a Sys directory from another
|
|
||||||
// version of Dolphin that might contain outdated files. Let's (re-)extract Sys.
|
|
||||||
deleteDirectoryRecursively(sysDirectory);
|
|
||||||
copyAssetFolder("Sys", sysDirectory, true);
|
|
||||||
|
|
||||||
SharedPreferences.Editor editor = preferences.edit();
|
|
||||||
editor.putString("sysDirectoryVersion", revision);
|
|
||||||
editor.apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let the native code know where the Sys directory is.
|
|
||||||
SetSysDirectory(sysDirectory.getPath());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private 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.
|
for (File child : file.listFiles())
|
||||||
CreateUserDirectories();
|
deleteDirectoryRecursively(child);
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
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())
|
throw new IllegalStateException("DirectoryInitializationService has to run at least once!");
|
||||||
{
|
|
||||||
for (File child : file.listFiles())
|
|
||||||
deleteDirectoryRecursively(child);
|
|
||||||
}
|
|
||||||
file.delete();
|
|
||||||
}
|
}
|
||||||
|
else if (isDolphinDirectoryInitializationRunning.get())
|
||||||
public static boolean areDolphinDirectoriesReady()
|
|
||||||
{
|
{
|
||||||
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!");
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (isDolphinDirectoryInitializationRunning.get())
|
||||||
public static String getDolphinInternalDirectory()
|
|
||||||
{
|
{
|
||||||
if (directoryState == null)
|
throw new IllegalStateException(
|
||||||
{
|
"DirectoryInitializationService has to finish running first!");
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
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 =
|
if (!output.exists() || overwrite)
|
||||||
new Intent(BROADCAST_ACTION)
|
{
|
||||||
.putExtra(EXTRA_STATE, state);
|
InputStream in = getAssets().open(asset);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
|
OutputStream out = new FileOutputStream(output);
|
||||||
|
copyFile(in, out);
|
||||||
|
in.close();
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (IOException e)
|
||||||
private void copyAsset(String asset, File output, Boolean overwrite)
|
|
||||||
{
|
{
|
||||||
Log.verbose("[DirectoryInitializationService] Copying File " + asset + " to " + output);
|
Log.error("[DirectoryInitializationService] Failed to copy asset file: " + asset +
|
||||||
|
e.getMessage());
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!output.exists() || overwrite)
|
|
||||||
{
|
|
||||||
InputStream in = getAssets().open(asset);
|
|
||||||
OutputStream out = new FileOutputStream(output);
|
|
||||||
copyFile(in, out);
|
|
||||||
in.close();
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
Log.error("[DirectoryInitializationService] Failed to copy asset file: " + asset + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void copyAssetFolder(String assetFolder, File outputFolder, Boolean overwrite)
|
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);
|
boolean createdFolder = false;
|
||||||
|
for (String file : getAssets().list(assetFolder))
|
||||||
try
|
{
|
||||||
|
if (!createdFolder)
|
||||||
{
|
{
|
||||||
boolean createdFolder = false;
|
outputFolder.mkdir();
|
||||||
for (String file : getAssets().list(assetFolder))
|
createdFolder = true;
|
||||||
{
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
copyAssetFolder(assetFolder + File.separator + file, new File(outputFolder, file),
|
||||||
|
overwrite);
|
||||||
|
copyAsset(assetFolder + File.separator + file, new File(outputFolder, file), overwrite);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch (IOException e)
|
||||||
private void copyFile(InputStream in, OutputStream out) throws IOException
|
|
||||||
{
|
{
|
||||||
byte[] buffer = new byte[1024];
|
Log.error("[DirectoryInitializationService] Failed to copy asset folder: " + assetFolder +
|
||||||
int read;
|
e.getMessage());
|
||||||
|
|
||||||
while ((read = in.read(buffer)) != -1)
|
|
||||||
{
|
|
||||||
out.write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static native void CreateUserDirectories();
|
private void copyFile(InputStream in, OutputStream out) throws IOException
|
||||||
private static native void SetSysDirectory(String path);
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,117 +20,117 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||||
*/
|
*/
|
||||||
public final class GameFileCacheService extends IntentService
|
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_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_RESCAN = "org.dolphinemu.dolphinemu.RESCAN_GAME_FILE_CACHE";
|
||||||
|
|
||||||
private static GameFileCache gameFileCache = null;
|
private static GameFileCache gameFileCache = null;
|
||||||
private static AtomicReference<GameFile[]> gameFiles = new AtomicReference<>(new GameFile[]{});
|
private static AtomicReference<GameFile[]> gameFiles = new AtomicReference<>(new GameFile[]{});
|
||||||
|
|
||||||
public GameFileCacheService()
|
public GameFileCacheService()
|
||||||
{
|
{
|
||||||
// Superclass constructor is called to name the thread on which this service executes.
|
// Superclass constructor is called to name the thread on which this service executes.
|
||||||
super("GameFileCacheService");
|
super("GameFileCacheService");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<GameFile> getGameFilesForPlatform(Platform platform)
|
public static List<GameFile> getGameFilesForPlatform(Platform platform)
|
||||||
{
|
{
|
||||||
GameFile[] allGames = gameFiles.get();
|
GameFile[] allGames = gameFiles.get();
|
||||||
ArrayList<GameFile> platformGames = new ArrayList<>();
|
ArrayList<GameFile> platformGames = new ArrayList<>();
|
||||||
for (GameFile game : allGames)
|
for (GameFile game : allGames)
|
||||||
{
|
{
|
||||||
if (Platform.fromNativeInt(game.getPlatform()) == platform)
|
if (Platform.fromNativeInt(game.getPlatform()) == platform)
|
||||||
{
|
{
|
||||||
platformGames.add(game);
|
platformGames.add(game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return platformGames;
|
return platformGames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameFile getGameFileByGameId(String gameId)
|
public static GameFile getGameFileByGameId(String gameId)
|
||||||
{
|
{
|
||||||
GameFile[] allGames = gameFiles.get();
|
GameFile[] allGames = gameFiles.get();
|
||||||
for (GameFile game : allGames)
|
for (GameFile game : allGames)
|
||||||
{
|
{
|
||||||
if (game.getGameId().equals(gameId))
|
if (game.getGameId().equals(gameId))
|
||||||
{
|
{
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startService(Context context, String action)
|
private static void startService(Context context, String action)
|
||||||
{
|
{
|
||||||
Intent intent = new Intent(context, GameFileCacheService.class);
|
Intent intent = new Intent(context, GameFileCacheService.class);
|
||||||
intent.setAction(action);
|
intent.setAction(action);
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously loads the game file cache from disk without checking
|
* Asynchronously loads the game file cache from disk without checking
|
||||||
* which games are present on the file system.
|
* which games are present on the file system.
|
||||||
*/
|
*/
|
||||||
public static void startLoad(Context context)
|
public static void startLoad(Context context)
|
||||||
{
|
{
|
||||||
startService(context, ACTION_LOAD);
|
startService(context, ACTION_LOAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronously scans for games in the user's configured folders,
|
* Asynchronously scans for games in the user's configured folders,
|
||||||
* updating the game file cache with the results.
|
* updating the game file cache with the results.
|
||||||
* If startLoad hasn't been called before this, this has no effect.
|
* If startLoad hasn't been called before this, this has no effect.
|
||||||
*/
|
*/
|
||||||
public static void startRescan(Context context)
|
public static void startRescan(Context context)
|
||||||
{
|
{
|
||||||
startService(context, ACTION_RESCAN);
|
startService(context, ACTION_RESCAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GameFile addOrGet(String gamePath)
|
public static GameFile addOrGet(String gamePath)
|
||||||
{
|
{
|
||||||
// The existence of this one function, which is called from one
|
// The existence of this one function, which is called from one
|
||||||
// single place, forces us to use synchronization in onHandleIntent...
|
// single place, forces us to use synchronization in onHandleIntent...
|
||||||
// A bit annoying, but should be good enough for now
|
// A bit annoying, but should be good enough for now
|
||||||
synchronized (gameFileCache)
|
synchronized (gameFileCache)
|
||||||
{
|
{
|
||||||
return gameFileCache.addOrGet(gamePath);
|
return gameFileCache.addOrGet(gamePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onHandleIntent(Intent intent)
|
protected void onHandleIntent(Intent intent)
|
||||||
{
|
{
|
||||||
// Load the game list cache if it isn't already loaded, otherwise do nothing
|
// Load the game list cache if it isn't already loaded, otherwise do nothing
|
||||||
if (ACTION_LOAD.equals(intent.getAction()) && gameFileCache == null)
|
if (ACTION_LOAD.equals(intent.getAction()) && gameFileCache == null)
|
||||||
{
|
{
|
||||||
GameFileCache temp = new GameFileCache(getCacheDir() + File.separator + "gamelist.cache");
|
GameFileCache temp = new GameFileCache(getCacheDir() + File.separator + "gamelist.cache");
|
||||||
synchronized (temp)
|
synchronized (temp)
|
||||||
{
|
{
|
||||||
gameFileCache = temp;
|
gameFileCache = temp;
|
||||||
gameFileCache.load();
|
gameFileCache.load();
|
||||||
updateGameFileArray();
|
updateGameFileArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rescan the file system and update the game list cache with the results
|
// Rescan the file system and update the game list cache with the results
|
||||||
if (ACTION_RESCAN.equals(intent.getAction()) && gameFileCache != null)
|
if (ACTION_RESCAN.equals(intent.getAction()) && gameFileCache != null)
|
||||||
{
|
{
|
||||||
synchronized (gameFileCache)
|
synchronized (gameFileCache)
|
||||||
{
|
{
|
||||||
if (gameFileCache.scanLibrary(this))
|
if (gameFileCache.scanLibrary(this))
|
||||||
{
|
{
|
||||||
updateGameFileArray();
|
updateGameFileArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateGameFileArray()
|
private void updateGameFileArray()
|
||||||
{
|
{
|
||||||
GameFile[] gameFilesTemp = gameFileCache.getAllGames();
|
GameFile[] gameFilesTemp = gameFileCache.getAllGames();
|
||||||
Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle()));
|
Arrays.sort(gameFilesTemp, (lhs, rhs) -> lhs.getTitle().compareToIgnoreCase(rhs.getTitle()));
|
||||||
gameFiles.set(gameFilesTemp);
|
gameFiles.set(gameFilesTemp);
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_ACTION));
|
LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(BROADCAST_ACTION));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,142 +25,143 @@ import java.util.List;
|
||||||
|
|
||||||
public class SyncChannelJobService extends JobService
|
public class SyncChannelJobService extends JobService
|
||||||
{
|
{
|
||||||
private static final String TAG = "ChannelJobSvc";
|
private static final String TAG = "ChannelJobSvc";
|
||||||
|
|
||||||
private SyncChannelTask mSyncChannelTask;
|
private SyncChannelTask mSyncChannelTask;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onStartJob(final JobParameters jobParameters)
|
public boolean onStartJob(final JobParameters jobParameters)
|
||||||
{
|
{
|
||||||
Log.d(TAG, "Starting channel creation job");
|
Log.d(TAG, "Starting channel creation job");
|
||||||
mSyncChannelTask =
|
mSyncChannelTask =
|
||||||
new SyncChannelTask(getApplicationContext())
|
new SyncChannelTask(getApplicationContext())
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Boolean success)
|
protected void onPostExecute(Boolean success)
|
||||||
{
|
{
|
||||||
super.onPostExecute(success);
|
super.onPostExecute(success);
|
||||||
jobFinished(jobParameters, !success);
|
jobFinished(jobParameters, !success);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mSyncChannelTask.execute();
|
mSyncChannelTask.execute();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onStopJob(JobParameters jobParameters)
|
public boolean onStopJob(JobParameters jobParameters)
|
||||||
{
|
{
|
||||||
if (mSyncChannelTask != null)
|
if (mSyncChannelTask != null)
|
||||||
{
|
{
|
||||||
mSyncChannelTask.cancel(true);
|
mSyncChannelTask.cancel(true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SyncChannelTask extends AsyncTask<Void, Void, Boolean>
|
private static class SyncChannelTask extends AsyncTask<Void, Void, Boolean>
|
||||||
{
|
{
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
SyncChannelTask(Context context)
|
SyncChannelTask(Context context)
|
||||||
{
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup channels
|
* Setup channels
|
||||||
*/
|
*/
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(Void... voids)
|
protected Boolean doInBackground(Void... voids)
|
||||||
{
|
{
|
||||||
List<HomeScreenChannel> subscriptions;
|
List<HomeScreenChannel> subscriptions;
|
||||||
List<Channel> channels = TvUtil.getAllChannels(context);
|
List<Channel> channels = TvUtil.getAllChannels(context);
|
||||||
List<Long> channelIds = new ArrayList<>();
|
List<Long> channelIds = new ArrayList<>();
|
||||||
// Checks if the default channels are added.
|
// Checks if the default channels are added.
|
||||||
// If not, create the channels
|
// If not, create the channels
|
||||||
if (!channels.isEmpty())
|
if (!channels.isEmpty())
|
||||||
{
|
{
|
||||||
channels.forEach(channel -> channelIds.add(channel.getId()));
|
channels.forEach(channel -> channelIds.add(channel.getId()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
subscriptions = TvUtil.createUniversalSubscriptions();
|
subscriptions = TvUtil.createUniversalSubscriptions();
|
||||||
for (HomeScreenChannel subscription : subscriptions)
|
for (HomeScreenChannel subscription : subscriptions)
|
||||||
{
|
{
|
||||||
long channelId = createChannel(subscription);
|
long channelId = createChannel(subscription);
|
||||||
channelIds.add(channelId);
|
channelIds.add(channelId);
|
||||||
subscription.setChannelId(channelId);
|
subscription.setChannelId(channelId);
|
||||||
// Only the first channel added can be browsable without user intervention.
|
// Only the first channel added can be browsable without user intervention.
|
||||||
TvContractCompat.requestChannelBrowsable(context, channelId);
|
TvContractCompat.requestChannelBrowsable(context, channelId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Schedule triggers to update programs
|
// Schedule triggers to update programs
|
||||||
channelIds.forEach(channel -> TvUtil.scheduleSyncingProgramsForChannel(context, channel));
|
channelIds.forEach(channel -> TvUtil.scheduleSyncingProgramsForChannel(context, channel));
|
||||||
// Update all channels
|
// Update all channels
|
||||||
TvUtil.updateAllChannels(context);
|
TvUtil.updateAllChannels(context);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long createChannel(HomeScreenChannel subscription)
|
private long createChannel(HomeScreenChannel subscription)
|
||||||
{
|
{
|
||||||
long channelId = getChannelIdFromTvProvider(context, subscription);
|
long channelId = getChannelIdFromTvProvider(context, subscription);
|
||||||
if (channelId != -1L)
|
if (channelId != -1L)
|
||||||
{
|
{
|
||||||
return channelId;
|
return channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the channel since it has not been added to the TV Provider.
|
// Create the channel since it has not been added to the TV Provider.
|
||||||
Uri appLinkIntentUri = Uri.parse(subscription.getAppLinkIntentUri());
|
Uri appLinkIntentUri = Uri.parse(subscription.getAppLinkIntentUri());
|
||||||
|
|
||||||
Channel.Builder builder = new Channel.Builder();
|
Channel.Builder builder = new Channel.Builder();
|
||||||
builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
|
builder.setType(TvContractCompat.Channels.TYPE_PREVIEW)
|
||||||
.setDisplayName(subscription.getName())
|
.setDisplayName(subscription.getName())
|
||||||
.setDescription(subscription.getDescription())
|
.setDescription(subscription.getDescription())
|
||||||
.setAppLinkIntentUri(appLinkIntentUri);
|
.setAppLinkIntentUri(appLinkIntentUri);
|
||||||
|
|
||||||
Log.d(TAG, "Creating channel: " + subscription.getName());
|
Log.d(TAG, "Creating channel: " + subscription.getName());
|
||||||
Uri channelUrl =
|
Uri channelUrl =
|
||||||
context.getContentResolver()
|
context.getContentResolver()
|
||||||
.insert(
|
.insert(
|
||||||
TvContractCompat.Channels.CONTENT_URI,
|
TvContractCompat.Channels.CONTENT_URI,
|
||||||
builder.build().toContentValues());
|
builder.build().toContentValues());
|
||||||
|
|
||||||
channelId = ContentUris.parseId(channelUrl);
|
channelId = ContentUris.parseId(channelUrl);
|
||||||
Bitmap bitmap = TvUtil.convertToBitmap(context, R.drawable.ic_launcher);
|
Bitmap bitmap = TvUtil.convertToBitmap(context, R.drawable.ic_launcher);
|
||||||
ChannelLogoUtils.storeChannelLogo(context, channelId, bitmap);
|
ChannelLogoUtils.storeChannelLogo(context, channelId, bitmap);
|
||||||
|
|
||||||
return channelId;
|
return channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getChannelIdFromTvProvider(Context context, HomeScreenChannel subscription)
|
private long getChannelIdFromTvProvider(Context context, HomeScreenChannel subscription)
|
||||||
{
|
{
|
||||||
Cursor cursor =
|
Cursor cursor =
|
||||||
context.getContentResolver().query(
|
context.getContentResolver().query(
|
||||||
TvContractCompat.Channels.CONTENT_URI,
|
TvContractCompat.Channels.CONTENT_URI,
|
||||||
new String[]{
|
new String[]{
|
||||||
TvContractCompat.Channels._ID,
|
TvContractCompat.Channels._ID,
|
||||||
TvContract.Channels.COLUMN_DISPLAY_NAME
|
TvContract.Channels.COLUMN_DISPLAY_NAME
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
if (cursor != null && cursor.moveToFirst())
|
if (cursor != null && cursor.moveToFirst())
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Channel channel = Channel.fromCursor(cursor);
|
Channel channel = Channel.fromCursor(cursor);
|
||||||
if (subscription.getName().equals(channel.getDisplayName()))
|
if (subscription.getName().equals(channel.getDisplayName()))
|
||||||
{
|
{
|
||||||
Log.d(
|
Log.d(
|
||||||
TAG,
|
TAG,
|
||||||
"Channel already exists. Returning channel "
|
"Channel already exists. Returning channel "
|
||||||
+ channel.getId()
|
+ channel.getId()
|
||||||
+ " from TV Provider.");
|
+ " from TV Provider.");
|
||||||
return channel.getId();
|
return channel.getId();
|
||||||
}
|
}
|
||||||
} while (cursor.moveToNext());
|
}
|
||||||
}
|
while (cursor.moveToNext());
|
||||||
return -1L;
|
}
|
||||||
}
|
return -1L;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@ package org.dolphinemu.dolphinemu.services;
|
||||||
|
|
||||||
import android.app.job.JobParameters;
|
import android.app.job.JobParameters;
|
||||||
import android.app.job.JobService;
|
import android.app.job.JobService;
|
||||||
import android.content.ContentUris;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
|
@ -25,138 +23,138 @@ import java.util.List;
|
||||||
|
|
||||||
public class SyncProgramsJobService extends JobService
|
public class SyncProgramsJobService extends JobService
|
||||||
{
|
{
|
||||||
private static final String TAG = "SyncProgramsJobService";
|
private static final String TAG = "SyncProgramsJobService";
|
||||||
|
|
||||||
private SyncProgramsTask mSyncProgramsTask;
|
private SyncProgramsTask mSyncProgramsTask;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onStartJob(final JobParameters jobParameters)
|
public boolean onStartJob(final JobParameters jobParameters)
|
||||||
{
|
{
|
||||||
Log.d(TAG, "onStartJob(): " + jobParameters);
|
Log.d(TAG, "onStartJob(): " + jobParameters);
|
||||||
final long channelId = getChannelId(jobParameters);
|
final long channelId = getChannelId(jobParameters);
|
||||||
if (channelId == -1L)
|
if (channelId == -1L)
|
||||||
{
|
{
|
||||||
Log.d(TAG, "Failed to find channel");
|
Log.d(TAG, "Failed to find channel");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSyncProgramsTask =
|
mSyncProgramsTask =
|
||||||
new SyncProgramsTask(getApplicationContext())
|
new SyncProgramsTask(getApplicationContext())
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Boolean finished)
|
protected void onPostExecute(Boolean finished)
|
||||||
{
|
{
|
||||||
super.onPostExecute(finished);
|
super.onPostExecute(finished);
|
||||||
mSyncProgramsTask = null;
|
mSyncProgramsTask = null;
|
||||||
jobFinished(jobParameters, !finished);
|
jobFinished(jobParameters, !finished);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mSyncProgramsTask.execute(channelId);
|
mSyncProgramsTask.execute(channelId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onStopJob(JobParameters jobParameters)
|
public boolean onStopJob(JobParameters jobParameters)
|
||||||
{
|
{
|
||||||
if (mSyncProgramsTask != null)
|
if (mSyncProgramsTask != null)
|
||||||
{
|
{
|
||||||
mSyncProgramsTask.cancel(true);
|
mSyncProgramsTask.cancel(true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getChannelId(JobParameters jobParameters)
|
private long getChannelId(JobParameters jobParameters)
|
||||||
{
|
{
|
||||||
PersistableBundle extras = jobParameters.getExtras();
|
PersistableBundle extras = jobParameters.getExtras();
|
||||||
return extras.getLong(TvContractCompat.EXTRA_CHANNEL_ID, -1L);
|
return extras.getLong(TvContractCompat.EXTRA_CHANNEL_ID, -1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SyncProgramsTask extends AsyncTask<Long, Void, Boolean>
|
private static class SyncProgramsTask extends AsyncTask<Long, Void, Boolean>
|
||||||
{
|
{
|
||||||
private Context context;
|
private Context context;
|
||||||
private List<GameFile> updatePrograms;
|
private List<GameFile> updatePrograms;
|
||||||
|
|
||||||
private SyncProgramsTask(Context context)
|
private SyncProgramsTask(Context context)
|
||||||
{
|
{
|
||||||
this.context = context;
|
this.context = context;
|
||||||
updatePrograms = new ArrayList<>();
|
updatePrograms = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines which channel to update, get the game files for the channel,
|
* Determines which channel to update, get the game files for the channel,
|
||||||
* then updates the list
|
* then updates the list
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Boolean doInBackground(Long... channelIds)
|
protected Boolean doInBackground(Long... channelIds)
|
||||||
{
|
{
|
||||||
List<Long> params = Arrays.asList(channelIds);
|
List<Long> params = Arrays.asList(channelIds);
|
||||||
if (!params.isEmpty())
|
if (!params.isEmpty())
|
||||||
{
|
{
|
||||||
for (Long channelId : params)
|
for (Long channelId : params)
|
||||||
{
|
{
|
||||||
Channel channel = TvUtil.getChannelById(context, channelId);
|
Channel channel = TvUtil.getChannelById(context, channelId);
|
||||||
for (Platform platform : Platform.values())
|
for (Platform platform : Platform.values())
|
||||||
{
|
{
|
||||||
if (channel != null && channel.getDisplayName().equals(platform.getHeaderName()))
|
if (channel != null && channel.getDisplayName().equals(platform.getHeaderName()))
|
||||||
{
|
{
|
||||||
getGamesByPlatform(platform);
|
getGamesByPlatform(platform);
|
||||||
syncPrograms(channelId);
|
syncPrograms(channelId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getGamesByPlatform(Platform platform)
|
private void getGamesByPlatform(Platform platform)
|
||||||
{
|
{
|
||||||
updatePrograms = GameFileCacheService.getGameFilesForPlatform(platform);
|
updatePrograms = GameFileCacheService.getGameFilesForPlatform(platform);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void syncPrograms(long channelId)
|
private void syncPrograms(long channelId)
|
||||||
{
|
{
|
||||||
Log.d(TAG, "Sync programs for channel: " + channelId);
|
Log.d(TAG, "Sync programs for channel: " + channelId);
|
||||||
deletePrograms(channelId);
|
deletePrograms(channelId);
|
||||||
createPrograms(channelId);
|
createPrograms(channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createPrograms(long channelId)
|
private void createPrograms(long channelId)
|
||||||
{
|
{
|
||||||
for (GameFile game : updatePrograms)
|
for (GameFile game : updatePrograms)
|
||||||
{
|
{
|
||||||
PreviewProgram previewProgram = buildProgram(channelId, game);
|
PreviewProgram previewProgram = buildProgram(channelId, game);
|
||||||
|
|
||||||
context.getContentResolver()
|
context.getContentResolver()
|
||||||
.insert(
|
.insert(
|
||||||
TvContractCompat.PreviewPrograms.CONTENT_URI,
|
TvContractCompat.PreviewPrograms.CONTENT_URI,
|
||||||
previewProgram.toContentValues());
|
previewProgram.toContentValues());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deletePrograms(long channelId)
|
private void deletePrograms(long channelId)
|
||||||
{
|
{
|
||||||
context.getContentResolver().delete(
|
context.getContentResolver().delete(
|
||||||
TvContractCompat.buildPreviewProgramsUriForChannel(channelId),
|
TvContractCompat.buildPreviewProgramsUriForChannel(channelId),
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PreviewProgram buildProgram(long channelId, GameFile game)
|
private PreviewProgram buildProgram(long channelId, GameFile game)
|
||||||
{
|
{
|
||||||
Uri appLinkUri = AppLinkHelper.buildGameUri(channelId, game.getGameId());
|
Uri appLinkUri = AppLinkHelper.buildGameUri(channelId, game.getGameId());
|
||||||
Uri banner = TvUtil.buildBanner(game, context);
|
Uri banner = TvUtil.buildBanner(game, context);
|
||||||
if (banner == null)
|
if (banner == null)
|
||||||
banner = TvUtil.getUriToResource(context, R.drawable.banner_tv);
|
banner = TvUtil.getUriToResource(context, R.drawable.banner_tv);
|
||||||
|
|
||||||
PreviewProgram.Builder builder = new PreviewProgram.Builder();
|
PreviewProgram.Builder builder = new PreviewProgram.Builder();
|
||||||
builder.setChannelId(channelId)
|
builder.setChannelId(channelId)
|
||||||
.setType(TvContractCompat.PreviewProgramColumns.TYPE_GAME)
|
.setType(TvContractCompat.PreviewProgramColumns.TYPE_GAME)
|
||||||
.setTitle(game.getTitle())
|
.setTitle(game.getTitle())
|
||||||
.setDescription(game.getDescription())
|
.setDescription(game.getDescription())
|
||||||
.setPosterArtUri(banner)
|
.setPosterArtUri(banner)
|
||||||
.setPosterArtAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_2_3)
|
.setPosterArtAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_2_3)
|
||||||
.setIntentUri(appLinkUri);
|
.setIntentUri(appLinkUri);
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,15 @@ import android.content.Intent;
|
||||||
|
|
||||||
public final class USBPermService extends IntentService
|
public final class USBPermService extends IntentService
|
||||||
{
|
{
|
||||||
public USBPermService() { super("USBPermService"); }
|
public USBPermService()
|
||||||
|
{
|
||||||
|
super("USBPermService");
|
||||||
|
}
|
||||||
|
|
||||||
// Needed when extending IntentService.
|
// Needed when extending IntentService.
|
||||||
// We don't care about the results of the intent handler for this.
|
// We don't care about the results of the intent handler for this.
|
||||||
@Override
|
@Override
|
||||||
protected void onHandleIntent(Intent intent) {}
|
protected void onHandleIntent(Intent intent)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,141 +17,141 @@ import android.view.View;
|
||||||
public final class DividerItemDecoration extends RecyclerView.ItemDecoration
|
public final class DividerItemDecoration extends RecyclerView.ItemDecoration
|
||||||
{
|
{
|
||||||
|
|
||||||
private Drawable mDivider;
|
private Drawable mDivider;
|
||||||
private boolean mShowFirstDivider = false;
|
private boolean mShowFirstDivider = false;
|
||||||
private boolean mShowLastDivider = false;
|
private boolean mShowLastDivider = false;
|
||||||
|
|
||||||
|
|
||||||
public DividerItemDecoration(Context context, AttributeSet attrs)
|
public DividerItemDecoration(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
final TypedArray a = context
|
final TypedArray a = context
|
||||||
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
|
.obtainStyledAttributes(attrs, new int[]{android.R.attr.listDivider});
|
||||||
mDivider = a.getDrawable(0);
|
mDivider = a.getDrawable(0);
|
||||||
a.recycle();
|
a.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
|
public DividerItemDecoration(Context context, AttributeSet attrs, boolean showFirstDivider,
|
||||||
boolean showLastDivider)
|
boolean showLastDivider)
|
||||||
{
|
{
|
||||||
this(context, attrs);
|
this(context, attrs);
|
||||||
mShowFirstDivider = showFirstDivider;
|
mShowFirstDivider = showFirstDivider;
|
||||||
mShowLastDivider = showLastDivider;
|
mShowLastDivider = showLastDivider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DividerItemDecoration(Drawable divider)
|
public DividerItemDecoration(Drawable divider)
|
||||||
{
|
{
|
||||||
mDivider = divider;
|
mDivider = divider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
|
public DividerItemDecoration(Drawable divider, boolean showFirstDivider,
|
||||||
boolean showLastDivider)
|
boolean showLastDivider)
|
||||||
{
|
{
|
||||||
this(divider);
|
this(divider);
|
||||||
mShowFirstDivider = showFirstDivider;
|
mShowFirstDivider = showFirstDivider;
|
||||||
mShowLastDivider = showLastDivider;
|
mShowLastDivider = showLastDivider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||||
RecyclerView.State state)
|
RecyclerView.State state)
|
||||||
{
|
{
|
||||||
super.getItemOffsets(outRect, view, parent, state);
|
super.getItemOffsets(outRect, view, parent, state);
|
||||||
if (mDivider == null)
|
if (mDivider == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (parent.getChildPosition(view) < 1)
|
if (parent.getChildPosition(view) < 1)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
|
if (getOrientation(parent) == LinearLayoutManager.VERTICAL)
|
||||||
{
|
{
|
||||||
outRect.top = mDivider.getIntrinsicHeight();
|
outRect.top = mDivider.getIntrinsicHeight();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
outRect.left = mDivider.getIntrinsicWidth();
|
outRect.left = mDivider.getIntrinsicWidth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state)
|
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state)
|
||||||
{
|
{
|
||||||
if (mDivider == null)
|
if (mDivider == null)
|
||||||
{
|
{
|
||||||
super.onDrawOver(c, parent, state);
|
super.onDrawOver(c, parent, state);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialization needed to avoid compiler warning
|
// Initialization needed to avoid compiler warning
|
||||||
int left = 0, right = 0, top = 0, bottom = 0, size;
|
int left = 0, right = 0, top = 0, bottom = 0, size;
|
||||||
int orientation = getOrientation(parent);
|
int orientation = getOrientation(parent);
|
||||||
int childCount = parent.getChildCount();
|
int childCount = parent.getChildCount();
|
||||||
|
|
||||||
if (orientation == LinearLayoutManager.VERTICAL)
|
if (orientation == LinearLayoutManager.VERTICAL)
|
||||||
{
|
{
|
||||||
size = mDivider.getIntrinsicHeight();
|
size = mDivider.getIntrinsicHeight();
|
||||||
left = parent.getPaddingLeft();
|
left = parent.getPaddingLeft();
|
||||||
right = parent.getWidth() - parent.getPaddingRight();
|
right = parent.getWidth() - parent.getPaddingRight();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ //horizontal
|
{ //horizontal
|
||||||
size = mDivider.getIntrinsicWidth();
|
size = mDivider.getIntrinsicWidth();
|
||||||
top = parent.getPaddingTop();
|
top = parent.getPaddingTop();
|
||||||
bottom = parent.getHeight() - parent.getPaddingBottom();
|
bottom = parent.getHeight() - parent.getPaddingBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++)
|
for (int i = mShowFirstDivider ? 0 : 1; i < childCount; i++)
|
||||||
{
|
{
|
||||||
View child = parent.getChildAt(i);
|
View child = parent.getChildAt(i);
|
||||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||||
|
|
||||||
if (orientation == LinearLayoutManager.VERTICAL)
|
if (orientation == LinearLayoutManager.VERTICAL)
|
||||||
{
|
{
|
||||||
top = child.getTop() - params.topMargin;
|
top = child.getTop() - params.topMargin;
|
||||||
bottom = top + size;
|
bottom = top + size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ //horizontal
|
{ //horizontal
|
||||||
left = child.getLeft() - params.leftMargin;
|
left = child.getLeft() - params.leftMargin;
|
||||||
right = left + size;
|
right = left + size;
|
||||||
}
|
}
|
||||||
mDivider.setBounds(left, top, right, bottom);
|
mDivider.setBounds(left, top, right, bottom);
|
||||||
mDivider.draw(c);
|
mDivider.draw(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// show last divider
|
// show last divider
|
||||||
if (mShowLastDivider && childCount > 0)
|
if (mShowLastDivider && childCount > 0)
|
||||||
{
|
{
|
||||||
View child = parent.getChildAt(childCount - 1);
|
View child = parent.getChildAt(childCount - 1);
|
||||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||||
if (orientation == LinearLayoutManager.VERTICAL)
|
if (orientation == LinearLayoutManager.VERTICAL)
|
||||||
{
|
{
|
||||||
top = child.getBottom() + params.bottomMargin;
|
top = child.getBottom() + params.bottomMargin;
|
||||||
bottom = top + size;
|
bottom = top + size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // horizontal
|
{ // horizontal
|
||||||
left = child.getRight() + params.rightMargin;
|
left = child.getRight() + params.rightMargin;
|
||||||
right = left + size;
|
right = left + size;
|
||||||
}
|
}
|
||||||
mDivider.setBounds(left, top, right, bottom);
|
mDivider.setBounds(left, top, right, bottom);
|
||||||
mDivider.draw(c);
|
mDivider.draw(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getOrientation(RecyclerView parent)
|
private int getOrientation(RecyclerView parent)
|
||||||
{
|
{
|
||||||
if (parent.getLayoutManager() instanceof LinearLayoutManager)
|
if (parent.getLayoutManager() instanceof LinearLayoutManager)
|
||||||
{
|
{
|
||||||
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
|
LinearLayoutManager layoutManager = (LinearLayoutManager) parent.getLayoutManager();
|
||||||
return layoutManager.getOrientation();
|
return layoutManager.getOrientation();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"DividerItemDecoration can only be used with a LinearLayoutManager.");
|
"DividerItemDecoration can only be used with a LinearLayoutManager.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@ import android.view.View;
|
||||||
*/
|
*/
|
||||||
public final class NVidiaShieldWorkaroundView extends View
|
public final class NVidiaShieldWorkaroundView extends View
|
||||||
{
|
{
|
||||||
public NVidiaShieldWorkaroundView(Context context, AttributeSet attrs)
|
public NVidiaShieldWorkaroundView(Context context, AttributeSet attrs)
|
||||||
{
|
{
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
|
|
||||||
// Setting this seems to workaround the bug
|
// Setting this seems to workaround the bug
|
||||||
setWillNotDraw(false);
|
setWillNotDraw(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,70 +11,72 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
|
|
||||||
public class CustomTitleView extends LinearLayout implements TitleViewAdapter.Provider {
|
public class CustomTitleView extends LinearLayout implements TitleViewAdapter.Provider
|
||||||
private final TextView mTitleView;
|
{
|
||||||
private final View mBadgeView;
|
private final TextView mTitleView;
|
||||||
|
private final View mBadgeView;
|
||||||
|
|
||||||
private final TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter() {
|
private final TitleViewAdapter mTitleViewAdapter = new TitleViewAdapter()
|
||||||
@Override
|
{
|
||||||
public View getSearchAffordanceView()
|
@Override
|
||||||
{
|
public View getSearchAffordanceView()
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setTitle(CharSequence titleText)
|
|
||||||
{
|
|
||||||
CustomTitleView.this.setTitle(titleText);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setBadgeDrawable(Drawable drawable)
|
|
||||||
{
|
|
||||||
CustomTitleView.this.setBadgeDrawable(drawable);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public CustomTitleView(Context context)
|
|
||||||
{
|
{
|
||||||
this(context, null);
|
return 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
|
@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;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -17,12 +17,12 @@ import android.widget.Toast;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.adapters.PlatformPagerAdapter;
|
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.DirectoryInitializationService;
|
||||||
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
||||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
||||||
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
|
import org.dolphinemu.dolphinemu.ui.platform.PlatformGamesView;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
|
||||||
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity;
|
|
||||||
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
|
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
|
||||||
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
||||||
import org.dolphinemu.dolphinemu.utils.StartupHandler;
|
import org.dolphinemu.dolphinemu.utils.StartupHandler;
|
||||||
|
@ -33,206 +33,211 @@ import org.dolphinemu.dolphinemu.utils.StartupHandler;
|
||||||
*/
|
*/
|
||||||
public final class MainActivity extends AppCompatActivity implements MainView
|
public final class MainActivity extends AppCompatActivity implements MainView
|
||||||
{
|
{
|
||||||
private ViewPager mViewPager;
|
private ViewPager mViewPager;
|
||||||
private Toolbar mToolbar;
|
private Toolbar mToolbar;
|
||||||
private TabLayout mTabLayout;
|
private TabLayout mTabLayout;
|
||||||
private FloatingActionButton mFab;
|
private FloatingActionButton mFab;
|
||||||
|
|
||||||
private MainPresenter mPresenter = new MainPresenter(this, this);
|
private MainPresenter mPresenter = new MainPresenter(this, this);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_main);
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
findViews();
|
findViews();
|
||||||
|
|
||||||
setSupportActionBar(mToolbar);
|
setSupportActionBar(mToolbar);
|
||||||
|
|
||||||
mTabLayout.setupWithViewPager(mViewPager);
|
mTabLayout.setupWithViewPager(mViewPager);
|
||||||
|
|
||||||
// Set up the FAB.
|
// Set up the FAB.
|
||||||
mFab.setOnClickListener(view -> mPresenter.onFabClick());
|
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)
|
// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
|
||||||
if (savedInstanceState == null)
|
if (savedInstanceState == null)
|
||||||
StartupHandler.HandleInit(this);
|
StartupHandler.HandleInit(this);
|
||||||
|
|
||||||
if (PermissionsHandler.hasWriteAccess(this))
|
if (PermissionsHandler.hasWriteAccess(this))
|
||||||
{
|
{
|
||||||
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
|
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
|
||||||
getSupportFragmentManager(), this);
|
getSupportFragmentManager(), this);
|
||||||
mViewPager.setAdapter(platformPagerAdapter);
|
mViewPager.setAdapter(platformPagerAdapter);
|
||||||
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount());
|
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount());
|
||||||
showGames();
|
showGames();
|
||||||
GameFileCacheService.startLoad(this);
|
GameFileCacheService.startLoad(this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mViewPager.setVisibility(View.INVISIBLE);
|
mViewPager.setVisibility(View.INVISIBLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume()
|
protected void onResume()
|
||||||
{
|
{
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mPresenter.addDirIfNeeded(this);
|
mPresenter.addDirIfNeeded(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy()
|
protected void onDestroy()
|
||||||
{
|
{
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
mPresenter.onDestroy();
|
mPresenter.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart()
|
protected void onStart()
|
||||||
{
|
{
|
||||||
super.onStart();
|
super.onStart();
|
||||||
StartupHandler.checkSessionReset(this);
|
StartupHandler.checkSessionReset(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop()
|
protected void onStop()
|
||||||
{
|
{
|
||||||
super.onStop();
|
super.onStop();
|
||||||
StartupHandler.setSessionTime(this);
|
StartupHandler.setSessionTime(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace with a ButterKnife injection.
|
// TODO: Replace with a ButterKnife injection.
|
||||||
private void findViews()
|
private void findViews()
|
||||||
{
|
{
|
||||||
mToolbar = (Toolbar) findViewById(R.id.toolbar_main);
|
mToolbar = (Toolbar) findViewById(R.id.toolbar_main);
|
||||||
mViewPager = (ViewPager) findViewById(R.id.pager_platforms);
|
mViewPager = (ViewPager) findViewById(R.id.pager_platforms);
|
||||||
mTabLayout = (TabLayout) findViewById(R.id.tabs_platforms);
|
mTabLayout = (TabLayout) findViewById(R.id.tabs_platforms);
|
||||||
mFab = (FloatingActionButton) findViewById(R.id.button_add_directory);
|
mFab = (FloatingActionButton) findViewById(R.id.button_add_directory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu)
|
public boolean onCreateOptionsMenu(Menu menu)
|
||||||
{
|
{
|
||||||
MenuInflater inflater = getMenuInflater();
|
MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.menu_game_grid, menu);
|
inflater.inflate(R.menu.menu_game_grid, menu);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MainView
|
* MainView
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setVersionString(String version)
|
public void setVersionString(String version)
|
||||||
{
|
{
|
||||||
mToolbar.setSubtitle(version);
|
mToolbar.setSubtitle(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refreshFragmentScreenshot(int fragmentPosition)
|
public void refreshFragmentScreenshot(int fragmentPosition)
|
||||||
{
|
{
|
||||||
// Invalidate Picasso image so that the new screenshot is animated in.
|
// Invalidate Picasso image so that the new screenshot is animated in.
|
||||||
Platform platform = Platform.fromPosition(mViewPager.getCurrentItem());
|
Platform platform = Platform.fromPosition(mViewPager.getCurrentItem());
|
||||||
PlatformGamesView fragment = getPlatformGamesView(platform);
|
PlatformGamesView fragment = getPlatformGamesView(platform);
|
||||||
|
|
||||||
if (fragment != null)
|
if (fragment != null)
|
||||||
{
|
{
|
||||||
fragment.refreshScreenshotAtPosition(fragmentPosition);
|
fragment.refreshScreenshotAtPosition(fragmentPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void launchSettingsActivity(MenuTag menuTag)
|
public void launchSettingsActivity(MenuTag menuTag)
|
||||||
{
|
{
|
||||||
SettingsActivity.launch(this, menuTag, "");
|
SettingsActivity.launch(this, menuTag, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void launchFileListActivity()
|
public void launchFileListActivity()
|
||||||
{
|
{
|
||||||
FileBrowserHelper.openDirectoryPicker(this);
|
FileBrowserHelper.openDirectoryPicker(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param requestCode An int describing whether the Activity that is returning did so successfully.
|
* @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 resultCode An int describing what Activity is giving us this callback.
|
||||||
* @param result The information the returning Activity is providing us.
|
* @param result The information the returning Activity is providing us.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent result)
|
protected void onActivityResult(int requestCode, int resultCode, Intent result)
|
||||||
{
|
{
|
||||||
switch (requestCode)
|
switch (requestCode)
|
||||||
{
|
{
|
||||||
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
||||||
// If the user picked a file, as opposed to just backing out.
|
// If the user picked a file, as opposed to just backing out.
|
||||||
if (resultCode == MainActivity.RESULT_OK)
|
if (resultCode == MainActivity.RESULT_OK)
|
||||||
{
|
{
|
||||||
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MainPresenter.REQUEST_EMULATE_GAME:
|
case MainPresenter.REQUEST_EMULATE_GAME:
|
||||||
mPresenter.refreshFragmentScreenshot(resultCode);
|
mPresenter.refreshFragmentScreenshot(resultCode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
|
||||||
switch (requestCode) {
|
{
|
||||||
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
switch (requestCode)
|
||||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
{
|
||||||
DirectoryInitializationService.startService(this);
|
case PermissionsHandler.REQUEST_CODE_WRITE_PERMISSION:
|
||||||
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
|
if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||||
getSupportFragmentManager(), this);
|
{
|
||||||
mViewPager.setAdapter(platformPagerAdapter);
|
DirectoryInitializationService.startService(this);
|
||||||
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount());
|
PlatformPagerAdapter platformPagerAdapter = new PlatformPagerAdapter(
|
||||||
mTabLayout.setupWithViewPager(mViewPager);
|
getSupportFragmentManager(), this);
|
||||||
mViewPager.setVisibility(View.VISIBLE);
|
mViewPager.setAdapter(platformPagerAdapter);
|
||||||
GameFileCacheService.startLoad(this);
|
mViewPager.setOffscreenPageLimit(platformPagerAdapter.getCount());
|
||||||
} else {
|
mTabLayout.setupWithViewPager(mViewPager);
|
||||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
mViewPager.setVisibility(View.VISIBLE);
|
||||||
.show();
|
GameFileCacheService.startLoad(this);
|
||||||
}
|
}
|
||||||
break;
|
else
|
||||||
default:
|
{
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||||
break;
|
.show();
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
default:
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the framework whenever any actionbar/toolbar icon is clicked.
|
* Called by the framework whenever any actionbar/toolbar icon is clicked.
|
||||||
*
|
*
|
||||||
* @param item The icon that was clicked on.
|
* @param item The icon that was clicked on.
|
||||||
* @return True if the event was handled, false to bubble it up to the OS.
|
* @return True if the event was handled, false to bubble it up to the OS.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item)
|
public boolean onOptionsItemSelected(MenuItem item)
|
||||||
{
|
{
|
||||||
return mPresenter.handleOptionSelection(item.getItemId(), this);
|
return mPresenter.handleOptionSelection(item.getItemId(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showGames()
|
public void showGames()
|
||||||
{
|
{
|
||||||
for (Platform platform : Platform.values())
|
for (Platform platform : Platform.values())
|
||||||
{
|
{
|
||||||
PlatformGamesView fragment = getPlatformGamesView(platform);
|
PlatformGamesView fragment = getPlatformGamesView(platform);
|
||||||
if (fragment != null)
|
if (fragment != null)
|
||||||
{
|
{
|
||||||
fragment.showGames();
|
fragment.showGames();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private PlatformGamesView getPlatformGamesView(Platform platform)
|
private PlatformGamesView getPlatformGamesView(Platform platform)
|
||||||
{
|
{
|
||||||
String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform.toInt();
|
String fragmentTag = "android:switcher:" + mViewPager.getId() + ":" + platform.toInt();
|
||||||
|
|
||||||
return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag);
|
return (PlatformGamesView) getSupportFragmentManager().findFragmentByTag(fragmentTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,106 +8,106 @@ import android.support.v4.content.LocalBroadcastManager;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.BuildConfig;
|
import org.dolphinemu.dolphinemu.BuildConfig;
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
|
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
||||||
import org.dolphinemu.dolphinemu.model.GameFileCache;
|
import org.dolphinemu.dolphinemu.model.GameFileCache;
|
||||||
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
||||||
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
|
||||||
|
|
||||||
public final class MainPresenter
|
public final class MainPresenter
|
||||||
{
|
{
|
||||||
public static final int REQUEST_ADD_DIRECTORY = 1;
|
public static final int REQUEST_ADD_DIRECTORY = 1;
|
||||||
public static final int REQUEST_EMULATE_GAME = 2;
|
public static final int REQUEST_EMULATE_GAME = 2;
|
||||||
|
|
||||||
private final MainView mView;
|
private final MainView mView;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private BroadcastReceiver mBroadcastReceiver = null;
|
private BroadcastReceiver mBroadcastReceiver = null;
|
||||||
private String mDirToAdd;
|
private String mDirToAdd;
|
||||||
|
|
||||||
public MainPresenter(MainView view, Context context)
|
public MainPresenter(MainView view, Context context)
|
||||||
{
|
{
|
||||||
mView = view;
|
mView = view;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onCreate()
|
public void onCreate()
|
||||||
{
|
{
|
||||||
String versionName = BuildConfig.VERSION_NAME;
|
String versionName = BuildConfig.VERSION_NAME;
|
||||||
mView.setVersionString(versionName);
|
mView.setVersionString(versionName);
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(GameFileCacheService.BROADCAST_ACTION);
|
filter.addAction(GameFileCacheService.BROADCAST_ACTION);
|
||||||
mBroadcastReceiver = new BroadcastReceiver()
|
mBroadcastReceiver = new BroadcastReceiver()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent)
|
public void onReceive(Context context, Intent intent)
|
||||||
{
|
{
|
||||||
mView.showGames();
|
mView.showGames();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
LocalBroadcastManager.getInstance(mContext).registerReceiver(mBroadcastReceiver, filter);
|
LocalBroadcastManager.getInstance(mContext).registerReceiver(mBroadcastReceiver, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDestroy()
|
public void onDestroy()
|
||||||
{
|
{
|
||||||
if (mBroadcastReceiver != null)
|
if (mBroadcastReceiver != null)
|
||||||
{
|
{
|
||||||
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mBroadcastReceiver);
|
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mBroadcastReceiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onFabClick()
|
public void onFabClick()
|
||||||
{
|
{
|
||||||
mView.launchFileListActivity();
|
mView.launchFileListActivity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean handleOptionSelection(int itemId, Context context)
|
public boolean handleOptionSelection(int itemId, Context context)
|
||||||
{
|
{
|
||||||
switch (itemId)
|
switch (itemId)
|
||||||
{
|
{
|
||||||
case R.id.menu_settings_core:
|
case R.id.menu_settings_core:
|
||||||
mView.launchSettingsActivity(MenuTag.CONFIG);
|
mView.launchSettingsActivity(MenuTag.CONFIG);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.menu_settings_graphics:
|
case R.id.menu_settings_graphics:
|
||||||
mView.launchSettingsActivity(MenuTag.GRAPHICS);
|
mView.launchSettingsActivity(MenuTag.GRAPHICS);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.menu_settings_gcpad:
|
case R.id.menu_settings_gcpad:
|
||||||
mView.launchSettingsActivity(MenuTag.GCPAD_TYPE);
|
mView.launchSettingsActivity(MenuTag.GCPAD_TYPE);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.menu_settings_wiimote:
|
case R.id.menu_settings_wiimote:
|
||||||
mView.launchSettingsActivity(MenuTag.WIIMOTE);
|
mView.launchSettingsActivity(MenuTag.WIIMOTE);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.menu_refresh:
|
case R.id.menu_refresh:
|
||||||
GameFileCacheService.startRescan(context);
|
GameFileCacheService.startRescan(context);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.button_add_directory:
|
case R.id.button_add_directory:
|
||||||
mView.launchFileListActivity();
|
mView.launchFileListActivity();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addDirIfNeeded(Context context)
|
public void addDirIfNeeded(Context context)
|
||||||
{
|
{
|
||||||
if (mDirToAdd != null)
|
if (mDirToAdd != null)
|
||||||
{
|
{
|
||||||
GameFileCache.addGameFolder(mDirToAdd, context);
|
GameFileCache.addGameFolder(mDirToAdd, context);
|
||||||
mDirToAdd = null;
|
mDirToAdd = null;
|
||||||
GameFileCacheService.startRescan(context);
|
GameFileCacheService.startRescan(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDirectorySelected(String dir)
|
public void onDirectorySelected(String dir)
|
||||||
{
|
{
|
||||||
mDirToAdd = dir;
|
mDirToAdd = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshFragmentScreenshot(int resultCode)
|
public void refreshFragmentScreenshot(int resultCode)
|
||||||
{
|
{
|
||||||
mView.refreshFragmentScreenshot(resultCode);
|
mView.refreshFragmentScreenshot(resultCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,29 +9,29 @@ import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
|
||||||
*/
|
*/
|
||||||
public interface MainView
|
public interface MainView
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Pass the view the native library's version string. Displaying
|
* Pass the view the native library's version string. Displaying
|
||||||
* it is optional.
|
* it is optional.
|
||||||
*
|
*
|
||||||
* @param version A string pulled from native code.
|
* @param version A string pulled from native code.
|
||||||
*/
|
*/
|
||||||
void setVersionString(String version);
|
void setVersionString(String version);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tell the view to tell the currently displayed {@link android.support.v4.app.Fragment}
|
* 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.
|
* 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.
|
* @param fragmentPosition An index corresponding to the list or grid of games.
|
||||||
*/
|
*/
|
||||||
void refreshFragmentScreenshot(int fragmentPosition);
|
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.
|
* To be called when the game file cache is updated.
|
||||||
*/
|
*/
|
||||||
void showGames();
|
void showGames();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,13 +18,13 @@ import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
|
import org.dolphinemu.dolphinemu.adapters.GameRowPresenter;
|
||||||
import org.dolphinemu.dolphinemu.adapters.SettingsRowPresenter;
|
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.GameFile;
|
||||||
import org.dolphinemu.dolphinemu.model.TvSettingsItem;
|
import org.dolphinemu.dolphinemu.model.TvSettingsItem;
|
||||||
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
||||||
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
||||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
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.FileBrowserHelper;
|
||||||
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
||||||
import org.dolphinemu.dolphinemu.utils.StartupHandler;
|
import org.dolphinemu.dolphinemu.utils.StartupHandler;
|
||||||
|
@ -35,249 +35,257 @@ import java.util.Collection;
|
||||||
|
|
||||||
public final class TvMainActivity extends FragmentActivity implements MainView
|
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
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_tv_main);
|
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)
|
// Stuff in this block only happens when this activity is newly created (i.e. not a rotation)
|
||||||
if (savedInstanceState == null)
|
if (savedInstanceState == null)
|
||||||
{
|
{
|
||||||
StartupHandler.HandleInit(this);
|
StartupHandler.HandleInit(this);
|
||||||
}
|
}
|
||||||
// Setup and/or sync channels
|
// Setup and/or sync channels
|
||||||
TvUtil.scheduleSyncingChannel(getApplicationContext());
|
TvUtil.scheduleSyncingChannel(getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onResume()
|
protected void onResume()
|
||||||
{
|
{
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mPresenter.addDirIfNeeded(this);
|
mPresenter.addDirIfNeeded(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy()
|
protected void onDestroy()
|
||||||
{
|
{
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
mPresenter.onDestroy();
|
mPresenter.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStart()
|
protected void onStart()
|
||||||
{
|
{
|
||||||
super.onStart();
|
super.onStart();
|
||||||
StartupHandler.checkSessionReset(this);
|
StartupHandler.checkSessionReset(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop()
|
protected void onStop()
|
||||||
{
|
{
|
||||||
super.onStop();
|
super.onStop();
|
||||||
StartupHandler.setSessionTime(this);
|
StartupHandler.setSessionTime(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupUI() {
|
void setupUI()
|
||||||
final FragmentManager fragmentManager = getSupportFragmentManager();
|
{
|
||||||
mBrowseFragment = new BrowseSupportFragment();
|
final FragmentManager fragmentManager = getSupportFragmentManager();
|
||||||
fragmentManager
|
mBrowseFragment = new BrowseSupportFragment();
|
||||||
.beginTransaction()
|
fragmentManager
|
||||||
.add(R.id.content, mBrowseFragment, "BrowseFragment")
|
.beginTransaction()
|
||||||
.commit();
|
.add(R.id.content, mBrowseFragment, "BrowseFragment")
|
||||||
|
.commit();
|
||||||
|
|
||||||
// Set display parameters for the BrowseFragment
|
// Set display parameters for the BrowseFragment
|
||||||
mBrowseFragment.setHeadersState(BrowseFragment.HEADERS_ENABLED);
|
mBrowseFragment.setHeadersState(BrowseFragment.HEADERS_ENABLED);
|
||||||
mBrowseFragment.setBrandColor(ContextCompat.getColor(this, R.color.dolphin_blue_dark));
|
mBrowseFragment.setBrandColor(ContextCompat.getColor(this, R.color.dolphin_blue_dark));
|
||||||
buildRowsAdapter();
|
buildRowsAdapter();
|
||||||
|
|
||||||
mBrowseFragment.setOnItemViewClickedListener(
|
mBrowseFragment.setOnItemViewClickedListener(
|
||||||
(itemViewHolder, item, rowViewHolder, row) ->
|
(itemViewHolder, item, rowViewHolder, row) ->
|
||||||
{
|
{
|
||||||
// Special case: user clicked on a settings row item.
|
// Special case: user clicked on a settings row item.
|
||||||
if (item instanceof TvSettingsItem)
|
if (item instanceof TvSettingsItem)
|
||||||
{
|
{
|
||||||
TvSettingsItem settingsItem = (TvSettingsItem) item;
|
TvSettingsItem settingsItem = (TvSettingsItem) item;
|
||||||
mPresenter.handleOptionSelection(settingsItem.getItemId(), this);
|
mPresenter.handleOptionSelection(settingsItem.getItemId(), this);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;
|
TvGameViewHolder holder = (TvGameViewHolder) itemViewHolder;
|
||||||
|
|
||||||
// Start the emulation activity and send the path of the clicked ISO to it.
|
// Start the emulation activity and send the path of the clicked ISO to it.
|
||||||
EmulationActivity.launch(TvMainActivity.this,
|
EmulationActivity.launch(TvMainActivity.this,
|
||||||
holder.gameFile,
|
holder.gameFile,
|
||||||
-1,
|
-1,
|
||||||
holder.imageScreenshot);
|
holder.imageScreenshot);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* MainView
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setVersionString(String version)
|
* MainView
|
||||||
{
|
*/
|
||||||
mBrowseFragment.setTitle(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refreshFragmentScreenshot(int fragmentPosition)
|
public void setVersionString(String version)
|
||||||
{
|
{
|
||||||
mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
|
mBrowseFragment.setTitle(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void launchSettingsActivity(MenuTag menuTag)
|
public void refreshFragmentScreenshot(int fragmentPosition)
|
||||||
{
|
{
|
||||||
SettingsActivity.launch(this, menuTag, "");
|
mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void launchFileListActivity()
|
public void launchSettingsActivity(MenuTag menuTag)
|
||||||
{
|
{
|
||||||
FileBrowserHelper.openDirectoryPicker(this);
|
SettingsActivity.launch(this, menuTag, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showGames()
|
public void launchFileListActivity()
|
||||||
{
|
{
|
||||||
// Kicks off the program services to update all channels
|
FileBrowserHelper.openDirectoryPicker(this);
|
||||||
TvUtil.updateAllChannels(getApplicationContext());
|
}
|
||||||
|
|
||||||
recreate();
|
@Override
|
||||||
}
|
public void showGames()
|
||||||
|
{
|
||||||
|
// Kicks off the program services to update all channels
|
||||||
|
TvUtil.updateAllChannels(getApplicationContext());
|
||||||
|
|
||||||
/**
|
recreate();
|
||||||
* Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity.
|
}
|
||||||
*
|
|
||||||
* @param requestCode An int describing whether the Activity that is returning did so successfully.
|
|
||||||
* @param resultCode An int describing what Activity is giving us this callback.
|
|
||||||
* @param result The information the returning Activity is providing us.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent result)
|
|
||||||
{
|
|
||||||
switch (requestCode)
|
|
||||||
{
|
|
||||||
case MainPresenter.REQUEST_ADD_DIRECTORY:
|
|
||||||
// If the user picked a file, as opposed to just backing out.
|
|
||||||
if (resultCode == MainActivity.RESULT_OK)
|
|
||||||
{
|
|
||||||
mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MainPresenter.REQUEST_EMULATE_GAME:
|
/**
|
||||||
mPresenter.refreshFragmentScreenshot(resultCode);
|
* Callback from AddDirectoryActivity. Applies any changes necessary to the GameGridActivity.
|
||||||
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;
|
||||||
|
|
||||||
@Override
|
case MainPresenter.REQUEST_EMULATE_GAME:
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
mPresenter.refreshFragmentScreenshot(resultCode);
|
||||||
switch (requestCode) {
|
break;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildRowsAdapter()
|
@Override
|
||||||
{
|
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
|
||||||
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
{
|
||||||
|
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))
|
private void buildRowsAdapter()
|
||||||
{
|
{
|
||||||
GameFileCacheService.startLoad(this);
|
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
|
||||||
}
|
|
||||||
|
|
||||||
for (Platform platform : Platform.values())
|
if (PermissionsHandler.hasWriteAccess(this))
|
||||||
{
|
{
|
||||||
ListRow row = buildGamesRow(platform, GameFileCacheService.getGameFilesForPlatform(platform));
|
GameFileCacheService.startLoad(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Add row to the adapter only if it is not empty.
|
for (Platform platform : Platform.values())
|
||||||
if (row != null)
|
{
|
||||||
{
|
ListRow row = buildGamesRow(platform, GameFileCacheService.getGameFilesForPlatform(platform));
|
||||||
mRowsAdapter.add(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
mBrowseFragment.setAdapter(mRowsAdapter);
|
||||||
{
|
}
|
||||||
// If there are no games, don't return a Row.
|
|
||||||
if (gameFiles.size() == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an adapter for this row.
|
private ListRow buildGamesRow(Platform platform, Collection<GameFile> gameFiles)
|
||||||
ArrayObjectAdapter row = new ArrayObjectAdapter(new GameRowPresenter());
|
{
|
||||||
row.addAll(0, gameFiles);
|
// If there are no games, don't return a Row.
|
||||||
|
if (gameFiles.size() == 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a header for this row.
|
// Create an adapter for this row.
|
||||||
HeaderItem header = new HeaderItem(platform.toInt(), platform.getHeaderName());
|
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.
|
// Create a header for this row.
|
||||||
return new ListRow(header, row);
|
HeaderItem header = new HeaderItem(platform.toInt(), platform.getHeaderName());
|
||||||
}
|
|
||||||
|
|
||||||
private ListRow buildSettingsRow()
|
// Create the row, passing it the filled adapter and the header, and give it to the master adapter.
|
||||||
{
|
return new ListRow(header, row);
|
||||||
ArrayObjectAdapter rowItems = new ArrayObjectAdapter(new SettingsRowPresenter());
|
}
|
||||||
|
|
||||||
rowItems.add(new TvSettingsItem(R.id.menu_settings_core,
|
private ListRow buildSettingsRow()
|
||||||
R.drawable.ic_settings_core_tv,
|
{
|
||||||
R.string.grid_menu_config));
|
ArrayObjectAdapter rowItems = new ArrayObjectAdapter(new SettingsRowPresenter());
|
||||||
|
|
||||||
rowItems.add(new TvSettingsItem(R.id.menu_settings_graphics,
|
rowItems.add(new TvSettingsItem(R.id.menu_settings_core,
|
||||||
R.drawable.ic_settings_graphics_tv,
|
R.drawable.ic_settings_core_tv,
|
||||||
R.string.grid_menu_graphics_settings));
|
R.string.grid_menu_config));
|
||||||
|
|
||||||
rowItems.add(new TvSettingsItem(R.id.menu_settings_gcpad,
|
rowItems.add(new TvSettingsItem(R.id.menu_settings_graphics,
|
||||||
R.drawable.ic_settings_gcpad,
|
R.drawable.ic_settings_graphics_tv,
|
||||||
R.string.grid_menu_gcpad_settings));
|
R.string.grid_menu_graphics_settings));
|
||||||
|
|
||||||
rowItems.add(new TvSettingsItem(R.id.menu_settings_wiimote,
|
rowItems.add(new TvSettingsItem(R.id.menu_settings_gcpad,
|
||||||
R.drawable.ic_settings_wiimote,
|
R.drawable.ic_settings_gcpad,
|
||||||
R.string.grid_menu_wiimote_settings));
|
R.string.grid_menu_gcpad_settings));
|
||||||
|
|
||||||
rowItems.add(new TvSettingsItem(R.id.button_add_directory,
|
rowItems.add(new TvSettingsItem(R.id.menu_settings_wiimote,
|
||||||
R.drawable.ic_add_tv,
|
R.drawable.ic_settings_wiimote,
|
||||||
R.string.add_directory_title));
|
R.string.grid_menu_wiimote_settings));
|
||||||
|
|
||||||
rowItems.add(new TvSettingsItem(R.id.menu_refresh,
|
rowItems.add(new TvSettingsItem(R.id.button_add_directory,
|
||||||
R.drawable.ic_refresh_tv,
|
R.drawable.ic_add_tv,
|
||||||
R.string.grid_menu_refresh));
|
R.string.add_directory_title));
|
||||||
|
|
||||||
// Create a header for this row.
|
rowItems.add(new TvSettingsItem(R.id.menu_refresh,
|
||||||
HeaderItem header = new HeaderItem(R.string.preferences_settings, getString(R.string.preferences_settings));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +1,47 @@
|
||||||
package org.dolphinemu.dolphinemu.ui.platform;
|
package org.dolphinemu.dolphinemu.ui.platform;
|
||||||
|
|
||||||
/** Enum to represent platform (eg GameCube, Wii). */
|
/**
|
||||||
|
* Enum to represent platform (eg GameCube, Wii).
|
||||||
|
*/
|
||||||
public enum Platform
|
public enum Platform
|
||||||
{
|
{
|
||||||
GAMECUBE(0, "GameCube Games"),
|
GAMECUBE(0, "GameCube Games"),
|
||||||
WII(1, "Wii Games"),
|
WII(1, "Wii Games"),
|
||||||
WIIWARE(2, "WiiWare Games");
|
WIIWARE(2, "WiiWare Games");
|
||||||
|
|
||||||
private final int value;
|
private final int value;
|
||||||
private final String headerName;
|
private final String headerName;
|
||||||
|
|
||||||
Platform(int value, String headerName)
|
Platform(int value, String headerName)
|
||||||
{
|
{
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.headerName = headerName;
|
this.headerName = headerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Platform fromInt(int i)
|
public static Platform fromInt(int i)
|
||||||
{
|
{
|
||||||
return values()[i];
|
return values()[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Platform fromNativeInt(int i)
|
public static Platform fromNativeInt(int i)
|
||||||
{
|
{
|
||||||
// TODO: Proper support for DOL and ELF files
|
// TODO: Proper support for DOL and ELF files
|
||||||
boolean in_range = i >= 0 && i < values().length;
|
boolean in_range = i >= 0 && i < values().length;
|
||||||
return values()[in_range ? i : WIIWARE.value];
|
return values()[in_range ? i : WIIWARE.value];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Platform fromPosition(int position)
|
public static Platform fromPosition(int position)
|
||||||
{
|
{
|
||||||
return values()[position];
|
return values()[position];
|
||||||
}
|
}
|
||||||
|
|
||||||
public int toInt()
|
public int toInt()
|
||||||
{
|
{
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHeaderName()
|
public String getHeaderName()
|
||||||
{
|
{
|
||||||
return headerName;
|
return headerName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,85 +11,82 @@ import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
import org.dolphinemu.dolphinemu.R;
|
||||||
import org.dolphinemu.dolphinemu.adapters.GameAdapter;
|
import org.dolphinemu.dolphinemu.adapters.GameAdapter;
|
||||||
import org.dolphinemu.dolphinemu.model.GameFile;
|
|
||||||
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public final class PlatformGamesFragment extends Fragment implements PlatformGamesView
|
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 GameAdapter mAdapter;
|
||||||
private RecyclerView mRecyclerView;
|
private RecyclerView mRecyclerView;
|
||||||
|
|
||||||
public static PlatformGamesFragment newInstance(Platform platform)
|
public static PlatformGamesFragment newInstance(Platform platform)
|
||||||
{
|
{
|
||||||
PlatformGamesFragment fragment = new PlatformGamesFragment();
|
PlatformGamesFragment fragment = new PlatformGamesFragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putSerializable(ARG_PLATFORM, platform);
|
args.putSerializable(ARG_PLATFORM, platform);
|
||||||
|
|
||||||
fragment.setArguments(args);
|
fragment.setArguments(args);
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState)
|
public void onCreate(Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
View rootView = inflater.inflate(R.layout.fragment_grid, container, false);
|
View rootView = inflater.inflate(R.layout.fragment_grid, container, false);
|
||||||
|
|
||||||
findViews(rootView);
|
findViews(rootView);
|
||||||
|
|
||||||
return rootView;
|
return rootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState)
|
public void onViewCreated(View view, Bundle savedInstanceState)
|
||||||
{
|
{
|
||||||
int columns = getResources().getInteger(R.integer.game_grid_columns);
|
int columns = getResources().getInteger(R.integer.game_grid_columns);
|
||||||
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns);
|
RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), columns);
|
||||||
mAdapter = new GameAdapter();
|
mAdapter = new GameAdapter();
|
||||||
|
|
||||||
mRecyclerView.setLayoutManager(layoutManager);
|
mRecyclerView.setLayoutManager(layoutManager);
|
||||||
mRecyclerView.setAdapter(mAdapter);
|
mRecyclerView.setAdapter(mAdapter);
|
||||||
|
|
||||||
mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8));
|
mRecyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8));
|
||||||
|
|
||||||
showGames();
|
showGames();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void refreshScreenshotAtPosition(int position)
|
public void refreshScreenshotAtPosition(int position)
|
||||||
{
|
{
|
||||||
mAdapter.notifyItemChanged(position);
|
mAdapter.notifyItemChanged(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(String gameId)
|
public void onItemClick(String gameId)
|
||||||
{
|
{
|
||||||
// No-op for now
|
// No-op for now
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showGames()
|
public void showGames()
|
||||||
{
|
{
|
||||||
if (mAdapter != null)
|
if (mAdapter != null)
|
||||||
{
|
{
|
||||||
Platform platform = (Platform) getArguments().getSerializable(ARG_PLATFORM);
|
Platform platform = (Platform) getArguments().getSerializable(ARG_PLATFORM);
|
||||||
mAdapter.swapDataSet(GameFileCacheService.getGameFilesForPlatform(platform));
|
mAdapter.swapDataSet(GameFileCacheService.getGameFilesForPlatform(platform));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findViews(View root)
|
private void findViews(View root)
|
||||||
{
|
{
|
||||||
mRecyclerView = (RecyclerView) root.findViewById(R.id.grid_games);
|
mRecyclerView = (RecyclerView) root.findViewById(R.id.grid_games);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,28 @@
|
||||||
package org.dolphinemu.dolphinemu.ui.platform;
|
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.
|
* Abstraction for a screen representing a single platform's games.
|
||||||
*/
|
*/
|
||||||
public interface PlatformGamesView
|
public interface PlatformGamesView
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Tell the view that a certain game's screenshot has been updated,
|
* Tell the view that a certain game's screenshot has been updated,
|
||||||
* and should be redrawn on-screen.
|
* and should be redrawn on-screen.
|
||||||
*
|
*
|
||||||
* @param position The index of the game that should be redrawn.
|
* @param position The index of the game that should be redrawn.
|
||||||
*/
|
*/
|
||||||
void refreshScreenshotAtPosition(int position);
|
void refreshScreenshotAtPosition(int position);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pass a click event to the view's Presenter. Typically called from the
|
* Pass a click event to the view's Presenter. Typically called from the
|
||||||
* view's list adapter.
|
* view's list adapter.
|
||||||
*
|
*
|
||||||
* @param gameId The ID of the game that was clicked.
|
* @param gameId The ID of the game that was clicked.
|
||||||
*/
|
*/
|
||||||
void onItemClick(String gameId);
|
void onItemClick(String gameId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To be called when the game file cache is updated.
|
* To be called when the game file cache is updated.
|
||||||
*/
|
*/
|
||||||
void showGames();
|
void showGames();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,108 +18,111 @@ import org.dolphinemu.dolphinemu.services.DirectoryInitializationService;
|
||||||
|
|
||||||
public class Analytics
|
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 analyticsAsked =
|
||||||
private static final String analyticsEnabled = Settings.SECTION_ANALYTICS + "_" + SettingsFile.KEY_ANALYTICS_ENABLED;
|
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_MANUFACTURER = "DEVICE_MANUFACTURER";
|
||||||
private static final String DEVICE_OS = "DEVICE_OS";
|
private static final String DEVICE_OS = "DEVICE_OS";
|
||||||
private static final String DEVICE_MODEL = "DEVICE_MODEL";
|
private static final String DEVICE_MODEL = "DEVICE_MODEL";
|
||||||
private static final String DEVICE_TYPE = "DEVICE_TYPE";
|
private static final String DEVICE_TYPE = "DEVICE_TYPE";
|
||||||
|
|
||||||
private static String deviceType;
|
private static String deviceType;
|
||||||
|
|
||||||
public static void checkAnalyticsInit(Context context)
|
public static void checkAnalyticsInit(Context context)
|
||||||
{
|
{
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
if (!preferences.getBoolean(analyticsAsked, false))
|
if (!preferences.getBoolean(analyticsAsked, false))
|
||||||
{
|
{
|
||||||
if (!DirectoryInitializationService.areDolphinDirectoriesReady())
|
if (!DirectoryInitializationService.areDolphinDirectoriesReady())
|
||||||
{
|
{
|
||||||
// Wait for directories to get initialized
|
// Wait for directories to get initialized
|
||||||
IntentFilter statusIntentFilter = new IntentFilter(
|
IntentFilter statusIntentFilter = new IntentFilter(
|
||||||
DirectoryInitializationService.BROADCAST_ACTION);
|
DirectoryInitializationService.BROADCAST_ACTION);
|
||||||
|
|
||||||
directoryStateReceiver = new DirectoryStateReceiver(directoryInitializationState ->
|
directoryStateReceiver = new DirectoryStateReceiver(directoryInitializationState ->
|
||||||
{
|
{
|
||||||
if (directoryInitializationState == DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
if (directoryInitializationState ==
|
||||||
{
|
DirectoryInitializationService.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
||||||
LocalBroadcastManager.getInstance(context).unregisterReceiver(directoryStateReceiver);
|
{
|
||||||
directoryStateReceiver = null;
|
LocalBroadcastManager.getInstance(context).unregisterReceiver(directoryStateReceiver);
|
||||||
showMessage(context, preferences);
|
directoryStateReceiver = null;
|
||||||
}
|
showMessage(context, preferences);
|
||||||
});
|
}
|
||||||
// Registers the DirectoryStateReceiver and its intent filters
|
});
|
||||||
LocalBroadcastManager.getInstance(context).registerReceiver(
|
// Registers the DirectoryStateReceiver and its intent filters
|
||||||
directoryStateReceiver,
|
LocalBroadcastManager.getInstance(context).registerReceiver(
|
||||||
statusIntentFilter);
|
directoryStateReceiver,
|
||||||
}
|
statusIntentFilter);
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
showMessage(context, preferences);
|
{
|
||||||
}
|
showMessage(context, preferences);
|
||||||
}
|
}
|
||||||
// Get device type now since we have a context
|
}
|
||||||
deviceType = TvUtil.isLeanback(context) ? "android-tv" : "android-mobile";
|
// 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)
|
private static void showMessage(Context context, SharedPreferences preferences)
|
||||||
{
|
{
|
||||||
// We asked, set to true regardless of answer
|
// We asked, set to true regardless of answer
|
||||||
SharedPreferences.Editor sPrefsEditor = preferences.edit();
|
SharedPreferences.Editor sPrefsEditor = preferences.edit();
|
||||||
sPrefsEditor.putBoolean(analyticsAsked, true);
|
sPrefsEditor.putBoolean(analyticsAsked, true);
|
||||||
sPrefsEditor.apply();
|
sPrefsEditor.apply();
|
||||||
|
|
||||||
new AlertDialog.Builder(context)
|
new AlertDialog.Builder(context)
|
||||||
.setTitle(context.getString(R.string.analytics))
|
.setTitle(context.getString(R.string.analytics))
|
||||||
.setMessage(context.getString(R.string.analytics_desc))
|
.setMessage(context.getString(R.string.analytics_desc))
|
||||||
.setPositiveButton(R.string.yes, (dialogInterface, i) ->
|
.setPositiveButton(R.string.yes, (dialogInterface, i) ->
|
||||||
{
|
{
|
||||||
sPrefsEditor.putBoolean(analyticsEnabled, true);
|
sPrefsEditor.putBoolean(analyticsEnabled, true);
|
||||||
sPrefsEditor.apply();
|
sPrefsEditor.apply();
|
||||||
SettingsFile.firstAnalyticsAdd(true);
|
SettingsFile.firstAnalyticsAdd(true);
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.no, (dialogInterface, i) ->
|
.setNegativeButton(R.string.no, (dialogInterface, i) ->
|
||||||
{
|
{
|
||||||
sPrefsEditor.putBoolean(analyticsEnabled, false);
|
sPrefsEditor.putBoolean(analyticsEnabled, false);
|
||||||
sPrefsEditor.apply();
|
sPrefsEditor.apply();
|
||||||
SettingsFile.firstAnalyticsAdd(false);
|
SettingsFile.firstAnalyticsAdd(false);
|
||||||
})
|
})
|
||||||
.create()
|
.create()
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendReport(String endpoint, byte[] data)
|
public static void sendReport(String endpoint, byte[] data)
|
||||||
{
|
{
|
||||||
StringRequest request = new StringRequest(Request.Method.POST, endpoint,
|
StringRequest request = new StringRequest(Request.Method.POST, endpoint,
|
||||||
null, error -> Log.debug("Send Report Failure code: "
|
null, error -> Log.debug("Send Report Failure code: "
|
||||||
+ error.networkResponse.statusCode))
|
+ error.networkResponse.statusCode))
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
public byte[] getBody()
|
public byte[] getBody()
|
||||||
{
|
{
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
VolleyUtil.getQueue().add(request);
|
VolleyUtil.getQueue().add(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getValue(String key)
|
public static String getValue(String key)
|
||||||
{
|
{
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case DEVICE_MODEL:
|
case DEVICE_MODEL:
|
||||||
return Build.MODEL;
|
return Build.MODEL;
|
||||||
case DEVICE_MANUFACTURER:
|
case DEVICE_MANUFACTURER:
|
||||||
return Build.MANUFACTURER;
|
return Build.MANUFACTURER;
|
||||||
case DEVICE_OS:
|
case DEVICE_OS:
|
||||||
return String.valueOf(Build.VERSION.SDK_INT);
|
return String.valueOf(Build.VERSION.SDK_INT);
|
||||||
case DEVICE_TYPE:
|
case DEVICE_TYPE:
|
||||||
return deviceType;
|
return deviceType;
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,25 +5,25 @@ import android.view.ViewPropertyAnimator;
|
||||||
|
|
||||||
public final class Animations
|
public final class Animations
|
||||||
{
|
{
|
||||||
private Animations()
|
private Animations()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ViewPropertyAnimator fadeViewIn(View view)
|
public static ViewPropertyAnimator fadeViewIn(View view)
|
||||||
{
|
{
|
||||||
view.setVisibility(View.VISIBLE);
|
view.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
return view.animate()
|
return view.animate()
|
||||||
.withLayer()
|
.withLayer()
|
||||||
.setDuration(100)
|
.setDuration(100)
|
||||||
.alpha(1.0f);
|
.alpha(1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ViewPropertyAnimator fadeViewOut(View view)
|
public static ViewPropertyAnimator fadeViewOut(View view)
|
||||||
{
|
{
|
||||||
return view.animate()
|
return view.animate()
|
||||||
.withLayer()
|
.withLayer()
|
||||||
.setDuration(300)
|
.setDuration(300)
|
||||||
.alpha(0.0f);
|
.alpha(0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,150 +10,150 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public class AppLinkHelper
|
public class AppLinkHelper
|
||||||
{
|
{
|
||||||
public static final String PLAY = "play";
|
public static final String PLAY = "play";
|
||||||
public static final String BROWSE = "browse";
|
public static final String BROWSE = "browse";
|
||||||
private static final String SCHEMA_URI_PREFIX = "dolphinemu://app/";
|
private static final String SCHEMA_URI_PREFIX = "dolphinemu://app/";
|
||||||
private static final String URI_PLAY = SCHEMA_URI_PREFIX + PLAY;
|
private static final String URI_PLAY = SCHEMA_URI_PREFIX + PLAY;
|
||||||
private static final String URI_VIEW = SCHEMA_URI_PREFIX + BROWSE;
|
private static final String URI_VIEW = SCHEMA_URI_PREFIX + BROWSE;
|
||||||
private static final int URI_INDEX_OPTION = 0;
|
private static final int URI_INDEX_OPTION = 0;
|
||||||
private static final int URI_INDEX_CHANNEL = 1;
|
private static final int URI_INDEX_CHANNEL = 1;
|
||||||
private static final int URI_INDEX_GAME = 2;
|
private static final int URI_INDEX_GAME = 2;
|
||||||
|
|
||||||
public static Uri buildGameUri(long channelId, String gameId)
|
public static Uri buildGameUri(long channelId, String gameId)
|
||||||
{
|
{
|
||||||
return Uri.parse(URI_PLAY)
|
return Uri.parse(URI_PLAY)
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.appendPath(String.valueOf(channelId))
|
.appendPath(String.valueOf(channelId))
|
||||||
.appendPath(String.valueOf(gameId))
|
.appendPath(String.valueOf(gameId))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri buildBrowseUri(String subscriptionName)
|
public static Uri buildBrowseUri(String subscriptionName)
|
||||||
{
|
{
|
||||||
return Uri.parse(URI_VIEW).buildUpon().appendPath(subscriptionName).build();
|
return Uri.parse(URI_VIEW).buildUpon().appendPath(subscriptionName).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AppLinkAction extractAction(Uri uri)
|
public static AppLinkAction extractAction(Uri uri)
|
||||||
{
|
{
|
||||||
if (isGameUri(uri))
|
if (isGameUri(uri))
|
||||||
return new PlayAction(extractChannelId(uri), extractGameId(uri));
|
return new PlayAction(extractChannelId(uri), extractGameId(uri));
|
||||||
else if (isBrowseUri(uri))
|
else if (isBrowseUri(uri))
|
||||||
return new BrowseAction(extractSubscriptionName(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)
|
private static boolean isGameUri(Uri uri)
|
||||||
{
|
{
|
||||||
if (uri.getPathSegments().isEmpty())
|
if (uri.getPathSegments().isEmpty())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String option = uri.getPathSegments().get(URI_INDEX_OPTION);
|
String option = uri.getPathSegments().get(URI_INDEX_OPTION);
|
||||||
return PLAY.equals(option);
|
return PLAY.equals(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isBrowseUri(Uri uri)
|
private static boolean isBrowseUri(Uri uri)
|
||||||
{
|
{
|
||||||
if (uri.getPathSegments().isEmpty())
|
if (uri.getPathSegments().isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
String option = uri.getPathSegments().get(URI_INDEX_OPTION);
|
String option = uri.getPathSegments().get(URI_INDEX_OPTION);
|
||||||
return BROWSE.equals(option);
|
return BROWSE.equals(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String extractSubscriptionName(Uri uri)
|
private static String extractSubscriptionName(Uri uri)
|
||||||
{
|
{
|
||||||
return extract(uri, URI_INDEX_CHANNEL);
|
return extract(uri, URI_INDEX_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long extractChannelId(Uri uri)
|
private static long extractChannelId(Uri uri)
|
||||||
{
|
{
|
||||||
return extractLong(uri, URI_INDEX_CHANNEL);
|
return extractLong(uri, URI_INDEX_CHANNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String extractGameId(Uri uri)
|
private static String extractGameId(Uri uri)
|
||||||
{
|
{
|
||||||
return extract(uri, URI_INDEX_GAME);
|
return extract(uri, URI_INDEX_GAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static long extractLong(Uri uri, int index)
|
private static long extractLong(Uri uri, int index)
|
||||||
{
|
{
|
||||||
return Long.valueOf(extract(uri, index));
|
return Long.valueOf(extract(uri, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String extract(Uri uri, int index)
|
private static String extract(Uri uri, int index)
|
||||||
{
|
{
|
||||||
List<String> pathSegments = uri.getPathSegments();
|
List<String> pathSegments = uri.getPathSegments();
|
||||||
if (pathSegments.isEmpty() || pathSegments.size() < index)
|
if (pathSegments.isEmpty() || pathSegments.size() < index)
|
||||||
return null;
|
return null;
|
||||||
return pathSegments.get(index);
|
return pathSegments.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@StringDef({BROWSE, PLAY})
|
@StringDef({BROWSE, PLAY})
|
||||||
public @interface ActionFlags
|
public @interface ActionFlags
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action for deep linking.
|
* Action for deep linking.
|
||||||
*/
|
*/
|
||||||
public interface AppLinkAction
|
public interface AppLinkAction
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Returns an string representation of the action.
|
* Returns an string representation of the action.
|
||||||
*/
|
*/
|
||||||
@ActionFlags
|
@ActionFlags
|
||||||
String getAction();
|
String getAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action when clicking the channel icon
|
* Action when clicking the channel icon
|
||||||
*/
|
*/
|
||||||
public static class BrowseAction implements AppLinkAction
|
public static class BrowseAction implements AppLinkAction
|
||||||
{
|
{
|
||||||
private final String mSubscriptionName;
|
private final String mSubscriptionName;
|
||||||
|
|
||||||
private BrowseAction(String subscriptionName)
|
private BrowseAction(String subscriptionName)
|
||||||
{
|
{
|
||||||
this.mSubscriptionName = subscriptionName;
|
this.mSubscriptionName = subscriptionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAction()
|
public String getAction()
|
||||||
{
|
{
|
||||||
return BROWSE;
|
return BROWSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action when clicking a program(game)
|
* Action when clicking a program(game)
|
||||||
*/
|
*/
|
||||||
public static class PlayAction implements AppLinkAction
|
public static class PlayAction implements AppLinkAction
|
||||||
{
|
{
|
||||||
private final long channelId;
|
private final long channelId;
|
||||||
private final String gameId;
|
private final String gameId;
|
||||||
|
|
||||||
private PlayAction(long channelId, String gameId)
|
private PlayAction(long channelId, String gameId)
|
||||||
{
|
{
|
||||||
this.channelId = channelId;
|
this.channelId = channelId;
|
||||||
this.gameId = gameId;
|
this.gameId = gameId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getChannelId()
|
public long getChannelId()
|
||||||
{
|
{
|
||||||
return channelId;
|
return channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getGameId()
|
public String getGameId()
|
||||||
{
|
{
|
||||||
return gameId;
|
return gameId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAction()
|
public String getAction()
|
||||||
{
|
{
|
||||||
return PLAY;
|
return PLAY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,22 +6,22 @@ import java.util.Map;
|
||||||
public class BiMap<K, V>
|
public class BiMap<K, V>
|
||||||
{
|
{
|
||||||
|
|
||||||
private Map<K, V> forward = new HashMap<K, V>();
|
private Map<K, V> forward = new HashMap<K, V>();
|
||||||
private Map<V, K> backward = new HashMap<V, K>();
|
private Map<V, K> backward = new HashMap<V, K>();
|
||||||
|
|
||||||
public synchronized void add(K key, V value)
|
public synchronized void add(K key, V value)
|
||||||
{
|
{
|
||||||
forward.put(key, value);
|
forward.put(key, value);
|
||||||
backward.put(value, key);
|
backward.put(value, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized V getForward(K key)
|
public synchronized V getForward(K key)
|
||||||
{
|
{
|
||||||
return forward.get(key);
|
return forward.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized K getBackward(V key)
|
public synchronized K getBackward(V key)
|
||||||
{
|
{
|
||||||
return backward.get(key);
|
return backward.get(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,54 +4,61 @@ import android.view.InputDevice;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
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
|
public class ControllerMappingHelper
|
||||||
{
|
{
|
||||||
/** Some controllers report extra button presses that can be ignored. */
|
/**
|
||||||
public static boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode)
|
* Some controllers report extra button presses that can be ignored.
|
||||||
{
|
*/
|
||||||
if (isDualShock4(inputDevice)) {
|
public static boolean shouldKeyBeIgnored(InputDevice inputDevice, int keyCode)
|
||||||
// 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
|
if (isDualShock4(inputDevice))
|
||||||
// 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;
|
// 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
|
||||||
return false;
|
// 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)
|
* Scale an axis to be zero-centered with a proper range.
|
||||||
{
|
*/
|
||||||
if (isDualShock4(inputDevice))
|
public static float scaleAxis(InputDevice inputDevice, int axis, float value)
|
||||||
{
|
{
|
||||||
// Android doesn't have correct mappings for this controller's triggers. It reports them
|
if (isDualShock4(inputDevice))
|
||||||
// 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].
|
// Android doesn't have correct mappings for this controller's triggers. It reports them
|
||||||
if (axis == MotionEvent.AXIS_RX || axis == MotionEvent.AXIS_RY)
|
// 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].
|
||||||
return (value + 1) / 2.0f;
|
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.
|
else if (isXboxOneWireless(inputDevice))
|
||||||
if (axis == MotionEvent.AXIS_Z || axis == MotionEvent.AXIS_RZ)
|
{
|
||||||
{
|
// Same as the DualShock 4, the mappings are missing.
|
||||||
return (value + 1) / 2.0f;
|
if (axis == MotionEvent.AXIS_Z || axis == MotionEvent.AXIS_RZ)
|
||||||
}
|
{
|
||||||
}
|
return (value + 1) / 2.0f;
|
||||||
return value;
|
}
|
||||||
}
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isDualShock4(InputDevice inputDevice)
|
private static boolean isDualShock4(InputDevice inputDevice)
|
||||||
{
|
{
|
||||||
// Sony DualShock 4 controller
|
// Sony DualShock 4 controller
|
||||||
return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc;
|
return inputDevice.getVendorId() == 0x54c && inputDevice.getProductId() == 0x9cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isXboxOneWireless(InputDevice inputDevice)
|
private static boolean isXboxOneWireless(InputDevice inputDevice)
|
||||||
{
|
{
|
||||||
// Microsoft Xbox One controller
|
// Microsoft Xbox One controller
|
||||||
return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0;
|
return inputDevice.getVendorId() == 0x45e && inputDevice.getProductId() == 0x2e0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,79 +3,78 @@ package org.dolphinemu.dolphinemu.utils;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.model.GameFile;
|
import org.dolphinemu.dolphinemu.model.GameFile;
|
||||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
public final class CoverHelper
|
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)
|
public static String buildGameTDBUrl(GameFile game, String region)
|
||||||
{
|
{
|
||||||
String gameId = game.getGameId();
|
String gameId = game.getGameId();
|
||||||
if(game.getPlatform() == 2) // WiiWare
|
if (game.getPlatform() == 2) // WiiWare
|
||||||
gameId = gameId.substring(0,4);
|
gameId = gameId.substring(0, 4);
|
||||||
return String.format(baseUrl, region, gameId);
|
return String.format(baseUrl, region, gameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getRegion(GameFile game)
|
public static String getRegion(GameFile game)
|
||||||
{
|
{
|
||||||
String region;
|
String region;
|
||||||
switch(game.getRegion())
|
switch (game.getRegion())
|
||||||
{
|
{
|
||||||
case 0: // NTSC_J
|
case 0: // NTSC_J
|
||||||
region = "JA";
|
region = "JA";
|
||||||
break;
|
break;
|
||||||
case 1: // NTSC_U
|
case 1: // NTSC_U
|
||||||
region = "US";
|
region = "US";
|
||||||
break;
|
break;
|
||||||
case 4: // NTSC_K
|
case 4: // NTSC_K
|
||||||
region = "KO";
|
region = "KO";
|
||||||
break;
|
break;
|
||||||
case 2: // PAL
|
case 2: // PAL
|
||||||
switch (game.getCountry())
|
switch (game.getCountry())
|
||||||
{
|
{
|
||||||
case 2: // German
|
case 2: // German
|
||||||
region = "DE";
|
region = "DE";
|
||||||
break;
|
break;
|
||||||
case 3: // French
|
case 3: // French
|
||||||
region = "FR";
|
region = "FR";
|
||||||
break;
|
break;
|
||||||
case 4: // Spanish
|
case 4: // Spanish
|
||||||
region = "ES";
|
region = "ES";
|
||||||
break;
|
break;
|
||||||
case 5: // Italian
|
case 5: // Italian
|
||||||
region = "IT";
|
region = "IT";
|
||||||
break;
|
break;
|
||||||
case 6: // Dutch
|
case 6: // Dutch
|
||||||
region = "NL";
|
region = "NL";
|
||||||
break;
|
break;
|
||||||
case 1: // English
|
case 1: // English
|
||||||
default:
|
default:
|
||||||
region = "EN";
|
region = "EN";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3: // Unknown
|
case 3: // Unknown
|
||||||
default:
|
default:
|
||||||
region = "EN";
|
region = "EN";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveCover(Bitmap cover, String path)
|
public static void saveCover(Bitmap cover, String path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FileOutputStream out = new FileOutputStream(path);
|
FileOutputStream out = new FileOutputStream(path);
|
||||||
cover.compress(Bitmap.CompressFormat.PNG, 100, out);
|
cover.compress(Bitmap.CompressFormat.PNG, 100, out);
|
||||||
out.close();
|
out.close();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -9,16 +9,20 @@ import org.dolphinemu.dolphinemu.services.DirectoryInitializationService.Directo
|
||||||
|
|
||||||
import rx.functions.Action1;
|
import rx.functions.Action1;
|
||||||
|
|
||||||
public class DirectoryStateReceiver extends BroadcastReceiver {
|
public class DirectoryStateReceiver extends BroadcastReceiver
|
||||||
Action1<DirectoryInitializationState> callback;
|
{
|
||||||
public DirectoryStateReceiver(Action1<DirectoryInitializationState> callback) {
|
Action1<DirectoryInitializationState> callback;
|
||||||
this.callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public DirectoryStateReceiver(Action1<DirectoryInitializationState> callback)
|
||||||
public void onReceive(Context context, Intent intent)
|
{
|
||||||
{
|
this.callback = callback;
|
||||||
DirectoryInitializationState state = (DirectoryInitializationState) intent.getSerializableExtra(DirectoryInitializationService.EXTRA_STATE);
|
}
|
||||||
callback.call(state);
|
|
||||||
}
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent)
|
||||||
|
{
|
||||||
|
DirectoryInitializationState state = (DirectoryInitializationState) intent
|
||||||
|
.getSerializableExtra(DirectoryInitializationService.EXTRA_STATE);
|
||||||
|
callback.call(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,367 +24,366 @@ import javax.microedition.khronos.opengles.GL10;
|
||||||
*/
|
*/
|
||||||
public final class EGLHelper
|
public final class EGLHelper
|
||||||
{
|
{
|
||||||
private final EGL10 mEGL;
|
private final EGL10 mEGL;
|
||||||
private final EGLDisplay mDisplay;
|
private final EGLDisplay mDisplay;
|
||||||
private EGLConfig[] mEGLConfigs;
|
private EGLConfig[] mEGLConfigs;
|
||||||
private EGLContext mEGLContext;
|
private EGLContext mEGLContext;
|
||||||
private EGLSurface mEGLSurface;
|
private EGLSurface mEGLSurface;
|
||||||
private GL10 mGL;
|
private GL10 mGL;
|
||||||
|
|
||||||
// GL support flags
|
// GL support flags
|
||||||
private boolean supportGL;
|
private boolean supportGL;
|
||||||
private boolean supportGLES2;
|
private boolean supportGLES2;
|
||||||
private boolean supportGLES3;
|
private boolean supportGLES3;
|
||||||
|
|
||||||
// Renderable type bitmasks
|
// Renderable type bitmasks
|
||||||
public static final int EGL_OPENGL_ES_BIT = 0x0001;
|
public static final int EGL_OPENGL_ES_BIT = 0x0001;
|
||||||
public static final int EGL_OPENGL_ES2_BIT = 0x0004;
|
public static final int EGL_OPENGL_ES2_BIT = 0x0004;
|
||||||
public static final int EGL_OPENGL_BIT = 0x0008;
|
public static final int EGL_OPENGL_BIT = 0x0008;
|
||||||
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
|
public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
|
||||||
|
|
||||||
// API types
|
// API types
|
||||||
public static final int EGL_OPENGL_ES_API = 0x30A0;
|
public static final int EGL_OPENGL_ES_API = 0x30A0;
|
||||||
public static final int EGL_OPENGL_API = 0x30A2;
|
public static final int EGL_OPENGL_API = 0x30A2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* <p>
|
* <p>
|
||||||
* Initializes the underlying {@link EGLSurface} with a width and height of 1.
|
* 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
|
* This is useful if all you need to use this class for is to query information
|
||||||
* from specific API contexts.
|
* from specific API contexts.
|
||||||
*
|
*
|
||||||
* @param renderableType Bitmask indicating which types of client API contexts
|
* @param renderableType Bitmask indicating which types of client API contexts
|
||||||
* the framebuffer config must support.
|
* the framebuffer config must support.
|
||||||
*/
|
*/
|
||||||
public EGLHelper(int renderableType)
|
public EGLHelper(int renderableType)
|
||||||
{
|
{
|
||||||
this(1, 1, renderableType);
|
this(1, 1, renderableType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* @param width Width of the underlying {@link EGLSurface}.
|
* @param width Width of the underlying {@link EGLSurface}.
|
||||||
* @param height Height of the underlying {@link EGLSurface}.
|
* @param height Height of the underlying {@link EGLSurface}.
|
||||||
* @param renderableType Bitmask indicating which types of client API contexts
|
* @param renderableType Bitmask indicating which types of client API contexts
|
||||||
* the framebuffer config must support.
|
* the framebuffer config must support.
|
||||||
*/
|
*/
|
||||||
public EGLHelper(int width, int height, int renderableType)
|
public EGLHelper(int width, int height, int renderableType)
|
||||||
{
|
{
|
||||||
// Initialize handle to an EGL display.
|
// Initialize handle to an EGL display.
|
||||||
mEGL = (EGL10) EGLContext.getEGL();
|
mEGL = (EGL10) EGLContext.getEGL();
|
||||||
mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
mDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
||||||
|
|
||||||
// If a display is present, initialize EGL.
|
// If a display is present, initialize EGL.
|
||||||
if (mDisplay != EGL10.EGL_NO_DISPLAY)
|
if (mDisplay != EGL10.EGL_NO_DISPLAY)
|
||||||
{
|
{
|
||||||
int[] version = new int[2];
|
int[] version = new int[2];
|
||||||
if (mEGL.eglInitialize(mDisplay, version))
|
if (mEGL.eglInitialize(mDisplay, version))
|
||||||
{
|
{
|
||||||
// Detect supported GL APIs, initialize configs, etc.
|
// Detect supported GL APIs, initialize configs, etc.
|
||||||
detect();
|
detect();
|
||||||
|
|
||||||
// Create context and surface
|
// Create context and surface
|
||||||
create(width, height, renderableType);
|
create(width, height, renderableType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.error("[EGLHelper] Error initializing EGL.");
|
Log.error("[EGLHelper] Error initializing EGL.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.error("[EGLHelper] Error initializing EGL display.");
|
Log.error("[EGLHelper] Error initializing EGL display.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases all resources associated with this helper.
|
* Releases all resources associated with this helper.
|
||||||
* <p>
|
* <p>
|
||||||
* This should be called whenever this helper is no longer needed.
|
* This should be called whenever this helper is no longer needed.
|
||||||
*/
|
*/
|
||||||
public void closeHelper()
|
public void closeHelper()
|
||||||
{
|
{
|
||||||
mEGL.eglTerminate(mDisplay);
|
mEGL.eglTerminate(mDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets information through EGL.<br/>
|
* Gets information through EGL.<br/>
|
||||||
* <p>
|
* <p>
|
||||||
* Index 0: Vendor <br/>
|
* Index 0: Vendor <br/>
|
||||||
* Index 1: Version <br/>
|
* Index 1: Version <br/>
|
||||||
* Index 2: Renderer <br/>
|
* Index 2: Renderer <br/>
|
||||||
* Index 3: Extensions <br/>
|
* Index 3: Extensions <br/>
|
||||||
*
|
*
|
||||||
* @return information retrieved through EGL.
|
* @return information retrieved through EGL.
|
||||||
*/
|
*/
|
||||||
public String[] getEGLInfo()
|
public String[] getEGLInfo()
|
||||||
{
|
{
|
||||||
return new String[] {
|
return new String[]{
|
||||||
mGL.glGetString(GL10.GL_VENDOR),
|
mGL.glGetString(GL10.GL_VENDOR),
|
||||||
mGL.glGetString(GL10.GL_VERSION),
|
mGL.glGetString(GL10.GL_VERSION),
|
||||||
mGL.glGetString(GL10.GL_RENDERER),
|
mGL.glGetString(GL10.GL_RENDERER),
|
||||||
mGL.glGetString(GL10.GL_EXTENSIONS),
|
mGL.glGetString(GL10.GL_EXTENSIONS),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not this device supports OpenGL.
|
* Whether or not this device supports OpenGL.
|
||||||
*
|
*
|
||||||
* @return true if this device supports OpenGL; false otherwise.
|
* @return true if this device supports OpenGL; false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean supportsOpenGL()
|
public boolean supportsOpenGL()
|
||||||
{
|
{
|
||||||
return supportGL;
|
return supportGL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not this device supports OpenGL ES 2.
|
* Whether or not this device supports OpenGL ES 2.
|
||||||
* <br/>
|
* <br/>
|
||||||
* Note that if this returns true, then OpenGL ES 1 is also supported.
|
* Note that if this returns true, then OpenGL ES 1 is also supported.
|
||||||
*
|
*
|
||||||
* @return true if this device supports OpenGL ES 2; false otherwise.
|
* @return true if this device supports OpenGL ES 2; false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean supportsGLES2()
|
public boolean supportsGLES2()
|
||||||
{
|
{
|
||||||
return supportGLES2;
|
return supportGLES2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not this device supports OpenGL ES 3.
|
* Whether or not this device supports OpenGL ES 3.
|
||||||
* <br/>
|
* <br/>
|
||||||
* Note that if this returns true, then OpenGL ES 1 and 2 are also supported.
|
* 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.
|
* @return true if this device supports OpenGL ES 3; false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean supportsGLES3()
|
public boolean supportsGLES3()
|
||||||
{
|
{
|
||||||
return supportGLES3;
|
return supportGLES3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the underlying {@link EGL10} instance.
|
* Gets the underlying {@link EGL10} instance.
|
||||||
*
|
*
|
||||||
* @return the underlying {@link EGL10} instance.
|
* @return the underlying {@link EGL10} instance.
|
||||||
*/
|
*/
|
||||||
public EGL10 getEGL()
|
public EGL10 getEGL()
|
||||||
{
|
{
|
||||||
return mEGL;
|
return mEGL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the underlying {@link GL10} instance.
|
* Gets the underlying {@link GL10} instance.
|
||||||
*
|
*
|
||||||
* @return the underlying {@link GL10} instance.
|
* @return the underlying {@link GL10} instance.
|
||||||
*/
|
*/
|
||||||
public GL10 getGL()
|
public GL10 getGL()
|
||||||
{
|
{
|
||||||
return mGL;
|
return mGL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the underlying {@link EGLDisplay}.
|
* Gets the underlying {@link EGLDisplay}.
|
||||||
*
|
*
|
||||||
* @return the underlying {@link EGLDisplay}
|
* @return the underlying {@link EGLDisplay}
|
||||||
*/
|
*/
|
||||||
public EGLDisplay getDisplay()
|
public EGLDisplay getDisplay()
|
||||||
{
|
{
|
||||||
return mDisplay;
|
return mDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all supported framebuffer configurations for this device.
|
* Gets all supported framebuffer configurations for this device.
|
||||||
*
|
*
|
||||||
* @return all supported framebuffer configurations for this device.
|
* @return all supported framebuffer configurations for this device.
|
||||||
*/
|
*/
|
||||||
public EGLConfig[] getConfigs()
|
public EGLConfig[] getConfigs()
|
||||||
{
|
{
|
||||||
return mEGLConfigs;
|
return mEGLConfigs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the underlying {@link EGLContext}.
|
* Gets the underlying {@link EGLContext}.
|
||||||
*
|
*
|
||||||
* @return the underlying {@link EGLContext}.
|
* @return the underlying {@link EGLContext}.
|
||||||
*/
|
*/
|
||||||
public EGLContext getContext()
|
public EGLContext getContext()
|
||||||
{
|
{
|
||||||
return mEGLContext;
|
return mEGLContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the underlying {@link EGLSurface}.
|
* Gets the underlying {@link EGLSurface}.
|
||||||
*
|
*
|
||||||
* @return the underlying {@link EGLSurface}.
|
* @return the underlying {@link EGLSurface}.
|
||||||
*/
|
*/
|
||||||
public EGLSurface getSurface()
|
public EGLSurface getSurface()
|
||||||
{
|
{
|
||||||
return mEGLSurface;
|
return mEGLSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detects the specific kind of GL modes that are supported
|
// Detects the specific kind of GL modes that are supported
|
||||||
private boolean detect()
|
private boolean detect()
|
||||||
{
|
{
|
||||||
// Get total number of configs available.
|
// Get total number of configs available.
|
||||||
int[] numConfigs = new int[1];
|
int[] numConfigs = new int[1];
|
||||||
if (!mEGL.eglGetConfigs(mDisplay, null, 0, numConfigs))
|
if (!mEGL.eglGetConfigs(mDisplay, null, 0, numConfigs))
|
||||||
{
|
{
|
||||||
Log.error("[EGLHelper] Error retrieving number of EGL configs available.");
|
Log.error("[EGLHelper] Error retrieving number of EGL configs available.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now get all the configurations
|
// Now get all the configurations
|
||||||
mEGLConfigs = new EGLConfig[numConfigs[0]];
|
mEGLConfigs = new EGLConfig[numConfigs[0]];
|
||||||
if (!mEGL.eglGetConfigs(mDisplay, mEGLConfigs, mEGLConfigs.length, numConfigs))
|
if (!mEGL.eglGetConfigs(mDisplay, mEGLConfigs, mEGLConfigs.length, numConfigs))
|
||||||
{
|
{
|
||||||
Log.error("[EGLHelper] Error retrieving all EGL configs.");
|
Log.error("[EGLHelper] Error retrieving all EGL configs.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (EGLConfig mEGLConfig : mEGLConfigs)
|
for (EGLConfig mEGLConfig : mEGLConfigs)
|
||||||
{
|
{
|
||||||
int[] attribVal = new int[1];
|
int[] attribVal = new int[1];
|
||||||
boolean ret = mEGL.eglGetConfigAttrib(mDisplay, mEGLConfig, EGL10.EGL_RENDERABLE_TYPE, attribVal);
|
boolean ret =
|
||||||
if (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_BIT) != 0)
|
||||||
|
supportGL = true;
|
||||||
|
|
||||||
if ((attribVal[0] & EGL_OPENGL_ES2_BIT) != 0)
|
if ((attribVal[0] & EGL_OPENGL_ES2_BIT) != 0)
|
||||||
supportGLES2 = true;
|
supportGLES2 = true;
|
||||||
|
|
||||||
if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0)
|
if ((attribVal[0] & EGL_OPENGL_ES3_BIT_KHR) != 0)
|
||||||
supportGLES3 = true;
|
supportGLES3 = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates the context and surface.
|
// Creates the context and surface.
|
||||||
private void create(int width, int height, int renderableType)
|
private void create(int width, int height, int renderableType)
|
||||||
{
|
{
|
||||||
int[] attribs = {
|
int[] attribs = {
|
||||||
EGL10.EGL_WIDTH, width,
|
EGL10.EGL_WIDTH, width,
|
||||||
EGL10.EGL_HEIGHT, height,
|
EGL10.EGL_HEIGHT, height,
|
||||||
EGL10.EGL_NONE
|
EGL10.EGL_NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initially we just assume GLES2 will be the default context.
|
// Initially we just assume GLES2 will be the default context.
|
||||||
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
||||||
int[] ctx_attribs = {
|
int[] ctx_attribs = {
|
||||||
EGL_CONTEXT_CLIENT_VERSION, 2,
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||||||
EGL10.EGL_NONE
|
EGL10.EGL_NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
// Determine the type of context that will be created
|
// Determine the type of context that will be created
|
||||||
// and change the attribute arrays accordingly.
|
// and change the attribute arrays accordingly.
|
||||||
switch (renderableType)
|
switch (renderableType)
|
||||||
{
|
{
|
||||||
case EGL_OPENGL_ES_BIT:
|
case EGL_OPENGL_ES_BIT:
|
||||||
ctx_attribs[1] = 1;
|
ctx_attribs[1] = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EGL_OPENGL_BIT:
|
case EGL_OPENGL_BIT:
|
||||||
ctx_attribs[0] = EGL10.EGL_NONE;
|
ctx_attribs[0] = EGL10.EGL_NONE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EGL_OPENGL_ES3_BIT_KHR:
|
case EGL_OPENGL_ES3_BIT_KHR:
|
||||||
ctx_attribs[1] = 3;
|
ctx_attribs[1] = 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EGL_OPENGL_ES2_BIT:
|
case EGL_OPENGL_ES2_BIT:
|
||||||
default: // Fall-back to GLES 2.
|
default: // Fall-back to GLES 2.
|
||||||
ctx_attribs[1] = 2;
|
ctx_attribs[1] = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (renderableType == EGL_OPENGL_BIT)
|
if (renderableType == EGL_OPENGL_BIT)
|
||||||
NativeLibrary.eglBindAPI(EGL_OPENGL_API);
|
NativeLibrary.eglBindAPI(EGL_OPENGL_API);
|
||||||
else
|
else
|
||||||
NativeLibrary.eglBindAPI(EGL_OPENGL_ES_API);
|
NativeLibrary.eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
|
|
||||||
mEGLContext = mEGL.eglCreateContext(mDisplay, mEGLConfigs[0], EGL10.EGL_NO_CONTEXT, ctx_attribs);
|
mEGLContext =
|
||||||
mEGLSurface = mEGL.eglCreatePbufferSurface(mDisplay, mEGLConfigs[0], attribs);
|
mEGL.eglCreateContext(mDisplay, mEGLConfigs[0], EGL10.EGL_NO_CONTEXT, ctx_attribs);
|
||||||
mEGL.eglMakeCurrent(mDisplay, mEGLSurface, mEGLSurface, mEGLContext);
|
mEGLSurface = mEGL.eglCreatePbufferSurface(mDisplay, mEGLConfigs[0], attribs);
|
||||||
mGL = (GL10) mEGLContext.getGL();
|
mEGL.eglMakeCurrent(mDisplay, mEGLSurface, mEGLSurface, mEGLContext);
|
||||||
}
|
mGL = (GL10) mEGLContext.getGL();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplified call to {@link GL10#glGetString(int)}
|
* Simplified call to {@link GL10#glGetString(int)}
|
||||||
* <p>
|
* <p>
|
||||||
* Accepts the following constants:
|
* Accepts the following constants:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
||||||
* <li>GL_VERSION - Version or release number.</li>
|
* <li>GL_VERSION - Version or release number.</li>
|
||||||
* <li>GL_RENDERER - Name of the renderer</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_SHADING_LANGUAGE_VERSION - Version or release number of the shading language </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param glEnum A symbolic constant within {@link GL10}.
|
* @param glEnum A symbolic constant within {@link GL10}.
|
||||||
*
|
* @return the string information represented by {@code glEnum}.
|
||||||
* @return the string information represented by {@code glEnum}.
|
*/
|
||||||
*/
|
public String glGetString(int glEnum)
|
||||||
public String glGetString(int glEnum)
|
{
|
||||||
{
|
return mGL.glGetString(glEnum);
|
||||||
return mGL.glGetString(glEnum);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplified call to {@link GLES30#glGetStringi(int, int)}
|
* Simplified call to {@link GLES30#glGetStringi(int, int)}
|
||||||
* <p>
|
* <p>
|
||||||
* Accepts the following constants:
|
* Accepts the following constants:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
* <li>GL_VENDOR - Company responsible for the GL implementation.</li>
|
||||||
* <li>GL_VERSION - Version or release number.</li>
|
* <li>GL_VERSION - Version or release number.</li>
|
||||||
* <li>GL_RENDERER - Name of the renderer</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_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>
|
* <li>GL_EXTENSIONS - Extension string supported by the implementation at {@code index}.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param glEnum A symbolic GL constant
|
* @param glEnum A symbolic GL constant
|
||||||
* @param index The index of the string to return.
|
* @param index The index of the string to return.
|
||||||
*
|
* @return the string information represented by {@code glEnum} and {@code index}.
|
||||||
* @return the string information represented by {@code glEnum} and {@code index}.
|
*/
|
||||||
*/
|
public String glGetStringi(int glEnum, int index)
|
||||||
public String glGetStringi(int glEnum, int index)
|
{
|
||||||
{
|
return GLES30.glGetStringi(glEnum, index);
|
||||||
return GLES30.glGetStringi(glEnum, index);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public boolean SupportsExtension(String extension)
|
public boolean SupportsExtension(String extension)
|
||||||
{
|
{
|
||||||
int[] num_ext = new int[1];
|
int[] num_ext = new int[1];
|
||||||
GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, num_ext, 0);
|
GLES30.glGetIntegerv(GLES30.GL_NUM_EXTENSIONS, num_ext, 0);
|
||||||
|
|
||||||
for (int i = 0; i < num_ext[0]; ++i)
|
for (int i = 0; i < num_ext[0]; ++i)
|
||||||
{
|
{
|
||||||
String ext = GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i);
|
String ext = GLES30.glGetStringi(GLES30.GL_EXTENSIONS, i);
|
||||||
if (ext.equals(extension))
|
if (ext.equals(extension))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetVersion()
|
public int GetVersion()
|
||||||
{
|
{
|
||||||
int[] major = new int[1];
|
int[] major = new int[1];
|
||||||
int[] minor = new int[1];
|
int[] minor = new int[1];
|
||||||
GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, major, 0);
|
GLES30.glGetIntegerv(GLES30.GL_MAJOR_VERSION, major, 0);
|
||||||
GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, minor, 0);
|
GLES30.glGetIntegerv(GLES30.GL_MINOR_VERSION, minor, 0);
|
||||||
return major[0] * 100 + minor[0] * 10;
|
return major[0] * 100 + minor[0] * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplified call to {@link GL10#glGetIntegerv(int, int[], int)
|
* Simplified call to {@link GL10#glGetIntegerv(int, int[], int)
|
||||||
*
|
*
|
||||||
* @param glEnum A symbolic GL constant.
|
* @param glEnum A symbolic GL constant.
|
||||||
*
|
* @return the integer information represented by {@code glEnum}.
|
||||||
* @return the integer information represented by {@code glEnum}.
|
*/
|
||||||
*/
|
public int glGetInteger(int glEnum)
|
||||||
public int glGetInteger(int glEnum)
|
{
|
||||||
{
|
int[] val = new int[1];
|
||||||
int[] val = new int[1];
|
mGL.glGetIntegerv(glEnum, val, 0);
|
||||||
mGL.glGetIntegerv(glEnum, val, 0);
|
return val[0];
|
||||||
return val[0];
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,41 +17,43 @@ import java.util.List;
|
||||||
|
|
||||||
public final class FileBrowserHelper
|
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);
|
File file = Utils.getFileForUri(files.get(0));
|
||||||
|
return file.getAbsolutePath();
|
||||||
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)
|
return null;
|
||||||
{
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,134 +19,143 @@ import org.dolphinemu.dolphinemu.services.USBPermService;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Java_GCAdapter {
|
public class Java_GCAdapter
|
||||||
public static UsbManager manager;
|
{
|
||||||
static byte[] controller_payload = new byte[37];
|
public static UsbManager manager;
|
||||||
|
static byte[] controller_payload = new byte[37];
|
||||||
|
|
||||||
static UsbDeviceConnection usb_con;
|
static UsbDeviceConnection usb_con;
|
||||||
static UsbInterface usb_intf;
|
static UsbInterface usb_intf;
|
||||||
static UsbEndpoint usb_in;
|
static UsbEndpoint usb_in;
|
||||||
static UsbEndpoint usb_out;
|
static UsbEndpoint usb_out;
|
||||||
|
|
||||||
private static void RequestPermission()
|
private static void RequestPermission()
|
||||||
{
|
{
|
||||||
Context context = NativeLibrary.sEmulationActivity.get();
|
Context context = NativeLibrary.sEmulationActivity.get();
|
||||||
if (context != null)
|
if (context != null)
|
||||||
{
|
{
|
||||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
||||||
{
|
{
|
||||||
UsbDevice dev = pair.getValue();
|
UsbDevice dev = pair.getValue();
|
||||||
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e)
|
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e)
|
||||||
{
|
{
|
||||||
if (!manager.hasPermission(dev))
|
if (!manager.hasPermission(dev))
|
||||||
{
|
{
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
PendingIntent pend_intent;
|
PendingIntent pend_intent;
|
||||||
intent.setClass(context, USBPermService.class);
|
intent.setClass(context, USBPermService.class);
|
||||||
pend_intent = PendingIntent.getService(context, 0, intent, 0);
|
pend_intent = PendingIntent.getService(context, 0, intent, 0);
|
||||||
manager.requestPermission(dev, pend_intent);
|
manager.requestPermission(dev, pend_intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.warning("Cannot request GameCube Adapter permission as EmulationActivity is null.");
|
Log.warning("Cannot request GameCube Adapter permission as EmulationActivity is null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shutdown()
|
public static void Shutdown()
|
||||||
{
|
{
|
||||||
usb_con.close();
|
usb_con.close();
|
||||||
}
|
}
|
||||||
public static int GetFD() { return usb_con.getFileDescriptor(); }
|
|
||||||
|
|
||||||
public static boolean QueryAdapter()
|
public static int GetFD()
|
||||||
{
|
{
|
||||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
return usb_con.getFileDescriptor();
|
||||||
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 void InitAdapter()
|
public static boolean QueryAdapter()
|
||||||
{
|
{
|
||||||
byte[] init = { 0x13 };
|
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||||
usb_con.bulkTransfer(usb_in, init, init.length, 0);
|
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() {
|
public static void InitAdapter()
|
||||||
return usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 16);
|
{
|
||||||
}
|
byte[] init = {0x13};
|
||||||
|
usb_con.bulkTransfer(usb_in, init, init.length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public static int Output(byte[] rumble) {
|
public static int Input()
|
||||||
return usb_con.bulkTransfer(usb_out, rumble, 5, 16);
|
{
|
||||||
}
|
return usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 16);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean OpenAdapter()
|
public static int Output(byte[] rumble)
|
||||||
{
|
{
|
||||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
return usb_con.bulkTransfer(usb_out, rumble, 5, 16);
|
||||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
}
|
||||||
{
|
|
||||||
UsbDevice dev = pair.getValue();
|
|
||||||
if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e)
|
|
||||||
{
|
|
||||||
if (manager.hasPermission(dev))
|
|
||||||
{
|
|
||||||
usb_con = manager.openDevice(dev);
|
|
||||||
|
|
||||||
Log.info("GCAdapter: Number of configurations: " + dev.getConfigurationCount());
|
public static boolean OpenAdapter()
|
||||||
Log.info("GCAdapter: Number of interfaces: " + dev.getInterfaceCount());
|
{
|
||||||
|
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)
|
Log.info("GCAdapter: Number of configurations: " + dev.getConfigurationCount());
|
||||||
{
|
Log.info("GCAdapter: Number of interfaces: " + dev.getInterfaceCount());
|
||||||
UsbConfiguration conf = dev.getConfiguration(0);
|
|
||||||
usb_intf = conf.getInterface(0);
|
|
||||||
usb_con.claimInterface(usb_intf, true);
|
|
||||||
|
|
||||||
Log.info("GCAdapter: Number of endpoints: " + usb_intf.getEndpointCount());
|
if (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)
|
Log.info("GCAdapter: Number of endpoints: " + usb_intf.getEndpointCount());
|
||||||
{
|
|
||||||
for (int i = 0; i < usb_intf.getEndpointCount(); ++i)
|
|
||||||
if (usb_intf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
|
|
||||||
usb_in = usb_intf.getEndpoint(i);
|
|
||||||
else
|
|
||||||
usb_out = usb_intf.getEndpoint(i);
|
|
||||||
|
|
||||||
InitAdapter();
|
if (usb_intf.getEndpointCount() == 2)
|
||||||
return true;
|
{
|
||||||
}
|
for (int i = 0; i < usb_intf.getEndpointCount(); ++i)
|
||||||
else
|
if (usb_intf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN)
|
||||||
{
|
usb_in = usb_intf.getEndpoint(i);
|
||||||
usb_con.releaseInterface(usb_intf);
|
else
|
||||||
}
|
usb_out = usb_intf.getEndpoint(i);
|
||||||
}
|
|
||||||
|
|
||||||
final Activity emulationActivity = NativeLibrary.sEmulationActivity.get();
|
InitAdapter();
|
||||||
if (emulationActivity != null)
|
return true;
|
||||||
{
|
}
|
||||||
emulationActivity.runOnUiThread(() -> Toast.makeText(emulationActivity, "GameCube Adapter couldn't be opened. Please re-plug the device.", Toast.LENGTH_LONG).show());
|
else
|
||||||
}
|
{
|
||||||
else
|
usb_con.releaseInterface(usb_intf);
|
||||||
{
|
}
|
||||||
Log.warning("Cannot show toast for GameCube Adapter failure.");
|
}
|
||||||
}
|
|
||||||
usb_con.close();
|
final Activity emulationActivity = NativeLibrary.sEmulationActivity.get();
|
||||||
}
|
if (emulationActivity != null)
|
||||||
}
|
{
|
||||||
}
|
emulationActivity.runOnUiThread(() -> Toast.makeText(emulationActivity,
|
||||||
return false;
|
"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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,145 +19,148 @@ import java.util.Map;
|
||||||
|
|
||||||
public class Java_WiimoteAdapter
|
public class Java_WiimoteAdapter
|
||||||
{
|
{
|
||||||
final static int MAX_PAYLOAD = 23;
|
final static int MAX_PAYLOAD = 23;
|
||||||
final static int MAX_WIIMOTES = 4;
|
final static int MAX_WIIMOTES = 4;
|
||||||
final static int TIMEOUT = 200;
|
final static int TIMEOUT = 200;
|
||||||
final static short NINTENDO_VENDOR_ID = 0x057e;
|
final static short NINTENDO_VENDOR_ID = 0x057e;
|
||||||
final static short NINTENDO_WIIMOTE_PRODUCT_ID = 0x0306;
|
final static short NINTENDO_WIIMOTE_PRODUCT_ID = 0x0306;
|
||||||
public static UsbManager manager;
|
public static UsbManager manager;
|
||||||
|
|
||||||
static UsbDeviceConnection usb_con;
|
static UsbDeviceConnection usb_con;
|
||||||
static UsbInterface[] usb_intf = new UsbInterface[MAX_WIIMOTES];
|
static UsbInterface[] usb_intf = new UsbInterface[MAX_WIIMOTES];
|
||||||
static UsbEndpoint[] usb_in = new UsbEndpoint[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()
|
private static void RequestPermission()
|
||||||
{
|
{
|
||||||
Context context = NativeLibrary.sEmulationActivity.get();
|
Context context = NativeLibrary.sEmulationActivity.get();
|
||||||
if (context != null)
|
if (context != null)
|
||||||
{
|
{
|
||||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
||||||
{
|
{
|
||||||
UsbDevice dev = pair.getValue();
|
UsbDevice dev = pair.getValue();
|
||||||
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID && dev.getVendorId() == NINTENDO_VENDOR_ID)
|
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID &&
|
||||||
{
|
dev.getVendorId() == NINTENDO_VENDOR_ID)
|
||||||
if (!manager.hasPermission(dev))
|
{
|
||||||
{
|
if (!manager.hasPermission(dev))
|
||||||
Log.warning("Requesting permission for Wii Remote adapter");
|
{
|
||||||
Intent intent = new Intent();
|
Log.warning("Requesting permission for Wii Remote adapter");
|
||||||
PendingIntent pend_intent;
|
Intent intent = new Intent();
|
||||||
intent.setClass(context, USBPermService.class);
|
PendingIntent pend_intent;
|
||||||
pend_intent = PendingIntent.getService(context, 0, intent, 0);
|
intent.setClass(context, USBPermService.class);
|
||||||
manager.requestPermission(dev, pend_intent);
|
pend_intent = PendingIntent.getService(context, 0, intent, 0);
|
||||||
}
|
manager.requestPermission(dev, pend_intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
Log.warning("Cannot request Wiimote adapter permission as EmulationActivity is null.");
|
{
|
||||||
}
|
Log.warning("Cannot request Wiimote adapter permission as EmulationActivity is null.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean QueryAdapter()
|
public static boolean QueryAdapter()
|
||||||
{
|
{
|
||||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
||||||
{
|
{
|
||||||
UsbDevice dev = pair.getValue();
|
UsbDevice dev = pair.getValue();
|
||||||
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID && dev.getVendorId() == NINTENDO_VENDOR_ID)
|
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID &&
|
||||||
{
|
dev.getVendorId() == NINTENDO_VENDOR_ID)
|
||||||
if (manager.hasPermission(dev))
|
{
|
||||||
return true;
|
if (manager.hasPermission(dev))
|
||||||
else
|
return true;
|
||||||
RequestPermission();
|
else
|
||||||
}
|
RequestPermission();
|
||||||
}
|
}
|
||||||
return false;
|
}
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static int Input(int index)
|
public static int Input(int index)
|
||||||
{
|
{
|
||||||
return usb_con.bulkTransfer(usb_in[index], wiimote_payload[index], MAX_PAYLOAD, TIMEOUT);
|
return usb_con.bulkTransfer(usb_in[index], wiimote_payload[index], MAX_PAYLOAD, TIMEOUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int Output(int index, byte[] buf, int size)
|
public static int Output(int index, byte[] buf, int size)
|
||||||
{
|
{
|
||||||
byte report_number = buf[0];
|
byte report_number = buf[0];
|
||||||
|
|
||||||
// Remove the report number from the buffer
|
// Remove the report number from the buffer
|
||||||
buf = Arrays.copyOfRange(buf, 1, buf.length);
|
buf = Arrays.copyOfRange(buf, 1, buf.length);
|
||||||
size--;
|
size--;
|
||||||
|
|
||||||
final int LIBUSB_REQUEST_TYPE_CLASS = (1 << 5);
|
final int LIBUSB_REQUEST_TYPE_CLASS = (1 << 5);
|
||||||
final int LIBUSB_RECIPIENT_INTERFACE = 0x1;
|
final int LIBUSB_RECIPIENT_INTERFACE = 0x1;
|
||||||
final int LIBUSB_ENDPOINT_OUT = 0;
|
final int LIBUSB_ENDPOINT_OUT = 0;
|
||||||
|
|
||||||
final int HID_SET_REPORT = 0x9;
|
final int HID_SET_REPORT = 0x9;
|
||||||
final int HID_OUTPUT = (2 << 8);
|
final int HID_OUTPUT = (2 << 8);
|
||||||
|
|
||||||
int write = usb_con.controlTransfer(
|
int write = usb_con.controlTransfer(
|
||||||
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
|
LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT,
|
||||||
HID_SET_REPORT,
|
HID_SET_REPORT,
|
||||||
HID_OUTPUT | report_number,
|
HID_OUTPUT | report_number,
|
||||||
index,
|
index,
|
||||||
buf, size,
|
buf, size,
|
||||||
1000);
|
1000);
|
||||||
|
|
||||||
if (write < 0)
|
if (write < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return write + 1;
|
return write + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean OpenAdapter()
|
public static boolean OpenAdapter()
|
||||||
{
|
{
|
||||||
// If the adapter is already open. Don't attempt to do it again
|
// If the adapter is already open. Don't attempt to do it again
|
||||||
if (usb_con != null && usb_con.getFileDescriptor() != -1)
|
if (usb_con != null && usb_con.getFileDescriptor() != -1)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
HashMap<String, UsbDevice> devices = manager.getDeviceList();
|
||||||
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
for (Map.Entry<String, UsbDevice> pair : devices.entrySet())
|
||||||
{
|
{
|
||||||
UsbDevice dev = pair.getValue();
|
UsbDevice dev = pair.getValue();
|
||||||
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID && dev.getVendorId() == NINTENDO_VENDOR_ID)
|
if (dev.getProductId() == NINTENDO_WIIMOTE_PRODUCT_ID &&
|
||||||
{
|
dev.getVendorId() == NINTENDO_VENDOR_ID)
|
||||||
if (manager.hasPermission(dev))
|
{
|
||||||
{
|
if (manager.hasPermission(dev))
|
||||||
usb_con = manager.openDevice(dev);
|
{
|
||||||
UsbConfiguration conf = dev.getConfiguration(0);
|
usb_con = manager.openDevice(dev);
|
||||||
|
UsbConfiguration conf = dev.getConfiguration(0);
|
||||||
|
|
||||||
Log.info("Number of configurations: " + dev.getConfigurationCount());
|
Log.info("Number of configurations: " + dev.getConfigurationCount());
|
||||||
Log.info("Number of Interfaces: " + dev.getInterfaceCount());
|
Log.info("Number of Interfaces: " + dev.getInterfaceCount());
|
||||||
Log.info("Number of Interfaces from conf: " + conf.getInterfaceCount());
|
Log.info("Number of Interfaces from conf: " + conf.getInterfaceCount());
|
||||||
|
|
||||||
// Sometimes the interface count is returned as zero.
|
// Sometimes the interface count is returned as zero.
|
||||||
// Means the device needs to be unplugged and plugged back in again
|
// Means the device needs to be unplugged and plugged back in again
|
||||||
if (dev.getInterfaceCount() > 0)
|
if (dev.getInterfaceCount() > 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAX_WIIMOTES; ++i)
|
for (int i = 0; i < MAX_WIIMOTES; ++i)
|
||||||
{
|
{
|
||||||
// One interface per Wii Remote
|
// One interface per Wii Remote
|
||||||
usb_intf[i] = dev.getInterface(i);
|
usb_intf[i] = dev.getInterface(i);
|
||||||
usb_con.claimInterface(usb_intf[i], true);
|
usb_con.claimInterface(usb_intf[i], true);
|
||||||
|
|
||||||
// One endpoint per Wii Remote. Input only
|
// One endpoint per Wii Remote. Input only
|
||||||
// Output reports go through the control channel.
|
// Output reports go through the control channel.
|
||||||
usb_in[i] = usb_intf[i].getEndpoint(0);
|
usb_in[i] = usb_intf[i].getEndpoint(0);
|
||||||
Log.info("Interface " + i + " endpoint count:" + usb_intf[i].getEndpointCount());
|
Log.info("Interface " + i + " endpoint count:" + usb_intf[i].getEndpointCount());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// XXX: Message that the device was found, but it needs to be unplugged and plugged back in?
|
// XXX: Message that the device was found, but it needs to be unplugged and plugged back in?
|
||||||
usb_con.close();
|
usb_con.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,45 +9,45 @@ import org.dolphinemu.dolphinemu.BuildConfig;
|
||||||
*/
|
*/
|
||||||
public final class Log
|
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)
|
public static void verbose(String message)
|
||||||
{
|
{
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
{
|
{
|
||||||
android.util.Log.v(TAG, message);
|
android.util.Log.v(TAG, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void debug(String message)
|
public static void debug(String message)
|
||||||
{
|
{
|
||||||
if (BuildConfig.DEBUG)
|
if (BuildConfig.DEBUG)
|
||||||
{
|
{
|
||||||
android.util.Log.d(TAG, message);
|
android.util.Log.d(TAG, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void info(String message)
|
public static void info(String message)
|
||||||
{
|
{
|
||||||
android.util.Log.i(TAG, message);
|
android.util.Log.i(TAG, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void warning(String message)
|
public static void warning(String message)
|
||||||
{
|
{
|
||||||
android.util.Log.w(TAG, message);
|
android.util.Log.w(TAG, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void error(String message)
|
public static void error(String message)
|
||||||
{
|
{
|
||||||
android.util.Log.e(TAG, message);
|
android.util.Log.e(TAG, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void wtf(String message)
|
public static void wtf(String message)
|
||||||
{
|
{
|
||||||
android.util.Log.wtf(TAG, message);
|
android.util.Log.wtf(TAG, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,49 +14,59 @@ import org.dolphinemu.dolphinemu.R;
|
||||||
|
|
||||||
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
|
||||||
|
|
||||||
public class PermissionsHandler {
|
public class PermissionsHandler
|
||||||
public static final int REQUEST_CODE_WRITE_PERMISSION = 500;
|
{
|
||||||
|
public static final int REQUEST_CODE_WRITE_PERMISSION = 500;
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.M)
|
@TargetApi(Build.VERSION_CODES.M)
|
||||||
public static boolean checkWritePermission(final FragmentActivity activity) {
|
public static boolean checkWritePermission(final FragmentActivity activity)
|
||||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
{
|
||||||
return true;
|
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 (hasWritePermission != PackageManager.PERMISSION_GRANTED)
|
||||||
if (activity.shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE)) {
|
{
|
||||||
showMessageOKCancel(activity, activity.getString(R.string.write_permission_needed),
|
if (activity.shouldShowRequestPermissionRationale(WRITE_EXTERNAL_STORAGE))
|
||||||
(dialog, which) -> activity.requestPermissions(new String[] {WRITE_EXTERNAL_STORAGE},
|
{
|
||||||
REQUEST_CODE_WRITE_PERMISSION));
|
showMessageOKCancel(activity, activity.getString(R.string.write_permission_needed),
|
||||||
return false;
|
(dialog, which) -> activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
|
||||||
}
|
REQUEST_CODE_WRITE_PERMISSION));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
activity.requestPermissions(new String[] {WRITE_EXTERNAL_STORAGE},
|
activity.requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
|
||||||
REQUEST_CODE_WRITE_PERMISSION);
|
REQUEST_CODE_WRITE_PERMISSION);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasWriteAccess(Context context) {
|
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);
|
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||||
return hasWritePermission == PackageManager.PERMISSION_GRANTED;
|
{
|
||||||
}
|
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) {
|
private static void showMessageOKCancel(final FragmentActivity activity, String message,
|
||||||
new AlertDialog.Builder(activity)
|
DialogInterface.OnClickListener okListener)
|
||||||
.setMessage(message)
|
{
|
||||||
.setPositiveButton(android.R.string.ok, okListener)
|
new AlertDialog.Builder(activity)
|
||||||
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) ->
|
.setMessage(message)
|
||||||
Toast.makeText(activity, R.string.write_permission_needed, Toast.LENGTH_SHORT).show())
|
.setPositiveButton(android.R.string.ok, okListener)
|
||||||
.create()
|
.setNegativeButton(android.R.string.cancel, (dialogInterface, i) ->
|
||||||
.show();
|
Toast.makeText(activity, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
||||||
}
|
.show())
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,98 +12,105 @@ import org.dolphinemu.dolphinemu.model.GameFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
public class PicassoUtils {
|
public class PicassoUtils
|
||||||
public static void loadGameBanner(ImageView imageView, GameFile gameFile)
|
{
|
||||||
{
|
public static void loadGameBanner(ImageView imageView, GameFile gameFile)
|
||||||
File cover = new File(gameFile.getCustomCoverPath());
|
{
|
||||||
if (cover.exists())
|
File cover = new File(gameFile.getCustomCoverPath());
|
||||||
{
|
if (cover.exists())
|
||||||
Picasso.with(imageView.getContext())
|
{
|
||||||
.load(cover)
|
Picasso.with(imageView.getContext())
|
||||||
.fit()
|
.load(cover)
|
||||||
.noFade()
|
.fit()
|
||||||
.noPlaceholder()
|
.noFade()
|
||||||
.config(Bitmap.Config.ARGB_8888)
|
.noPlaceholder()
|
||||||
.error(R.drawable.no_banner)
|
.config(Bitmap.Config.ARGB_8888)
|
||||||
.into(imageView);
|
.error(R.drawable.no_banner)
|
||||||
}
|
.into(imageView);
|
||||||
else if ((cover = new File(gameFile.getCoverPath())).exists())
|
}
|
||||||
{
|
else if ((cover = new File(gameFile.getCoverPath())).exists())
|
||||||
Picasso.with(imageView.getContext())
|
{
|
||||||
.load(cover)
|
Picasso.with(imageView.getContext())
|
||||||
.fit()
|
.load(cover)
|
||||||
.noFade()
|
.fit()
|
||||||
.noPlaceholder()
|
.noFade()
|
||||||
.config(Bitmap.Config.ARGB_8888)
|
.noPlaceholder()
|
||||||
.error(R.drawable.no_banner)
|
.config(Bitmap.Config.ARGB_8888)
|
||||||
.into(imageView);
|
.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.
|
* 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
|
*/
|
||||||
{
|
else
|
||||||
Picasso.with(imageView.getContext())
|
{
|
||||||
.load(CoverHelper.buildGameTDBUrl(gameFile, CoverHelper.getRegion(gameFile)))
|
Picasso.with(imageView.getContext())
|
||||||
.fit()
|
.load(CoverHelper.buildGameTDBUrl(gameFile, CoverHelper.getRegion(gameFile)))
|
||||||
.noFade()
|
.fit()
|
||||||
.noPlaceholder()
|
.noFade()
|
||||||
.config(Bitmap.Config.ARGB_8888)
|
.noPlaceholder()
|
||||||
.error(R.drawable.no_banner)
|
.config(Bitmap.Config.ARGB_8888)
|
||||||
.into(imageView, new Callback()
|
.error(R.drawable.no_banner)
|
||||||
{
|
.into(imageView, new Callback()
|
||||||
@Override
|
{
|
||||||
public void onSuccess()
|
@Override
|
||||||
{
|
public void onSuccess()
|
||||||
CoverHelper.saveCover(((BitmapDrawable) imageView.getDrawable()).getBitmap(),
|
{
|
||||||
gameFile.getCoverPath());
|
CoverHelper.saveCover(((BitmapDrawable) imageView.getDrawable()).getBitmap(),
|
||||||
}
|
gameFile.getCoverPath());
|
||||||
@Override
|
}
|
||||||
public void onError() // Second pass using US region
|
|
||||||
{
|
@Override
|
||||||
Picasso.with(imageView.getContext())
|
public void onError() // Second pass using US region
|
||||||
.load(CoverHelper.buildGameTDBUrl(gameFile, "US"))
|
{
|
||||||
.fit()
|
Picasso.with(imageView.getContext())
|
||||||
.noFade()
|
.load(CoverHelper.buildGameTDBUrl(gameFile, "US"))
|
||||||
.noPlaceholder()
|
.fit()
|
||||||
.config(Bitmap.Config.ARGB_8888)
|
.noFade()
|
||||||
.error(R.drawable.no_banner)
|
.noPlaceholder()
|
||||||
.into(imageView, new Callback()
|
.config(Bitmap.Config.ARGB_8888)
|
||||||
{
|
.error(R.drawable.no_banner)
|
||||||
@Override
|
.into(imageView, new Callback()
|
||||||
public void onSuccess()
|
{
|
||||||
{
|
@Override
|
||||||
CoverHelper.saveCover(((BitmapDrawable) imageView.getDrawable()).getBitmap(),
|
public void onSuccess()
|
||||||
gameFile.getCoverPath());
|
{
|
||||||
}
|
CoverHelper.saveCover(
|
||||||
@Override
|
((BitmapDrawable) imageView.getDrawable()).getBitmap(),
|
||||||
public void onError() // Third and last pass using EN region
|
gameFile.getCoverPath());
|
||||||
{
|
}
|
||||||
Picasso.with(imageView.getContext())
|
|
||||||
.load(CoverHelper.buildGameTDBUrl(gameFile, "EN"))
|
@Override
|
||||||
.fit()
|
public void onError() // Third and last pass using EN region
|
||||||
.noFade()
|
{
|
||||||
.noPlaceholder()
|
Picasso.with(imageView.getContext())
|
||||||
.config(Bitmap.Config.ARGB_8888)
|
.load(CoverHelper.buildGameTDBUrl(gameFile, "EN"))
|
||||||
.error(R.drawable.no_banner)
|
.fit()
|
||||||
.into(imageView, new Callback()
|
.noFade()
|
||||||
{
|
.noPlaceholder()
|
||||||
@Override
|
.config(Bitmap.Config.ARGB_8888)
|
||||||
public void onSuccess()
|
.error(R.drawable.no_banner)
|
||||||
{
|
.into(imageView, new Callback()
|
||||||
CoverHelper.saveCover(((BitmapDrawable) imageView.getDrawable()).getBitmap(),
|
{
|
||||||
gameFile.getCoverPath());
|
@Override
|
||||||
}
|
public void onSuccess()
|
||||||
@Override
|
{
|
||||||
public void onError()
|
CoverHelper.saveCover(
|
||||||
{
|
((BitmapDrawable) imageView.getDrawable())
|
||||||
}
|
.getBitmap(),
|
||||||
});
|
gameFile.getCoverPath());
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
@Override
|
||||||
});
|
public void onError()
|
||||||
}
|
{
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,61 +14,61 @@ import java.util.Date;
|
||||||
|
|
||||||
public final class StartupHandler
|
public final class StartupHandler
|
||||||
{
|
{
|
||||||
public static final String NEW_SESSION = "NEW_SESSION";
|
public static final String NEW_SESSION = "NEW_SESSION";
|
||||||
public static final String LAST_CLOSED = "LAST_CLOSED";
|
public static final String LAST_CLOSED = "LAST_CLOSED";
|
||||||
public static final Long SESSION_TIMEOUT = 21600000L; // 6 hours in milliseconds
|
public static final Long SESSION_TIMEOUT = 21600000L; // 6 hours in milliseconds
|
||||||
|
|
||||||
public static void HandleInit(FragmentActivity parent)
|
public static void HandleInit(FragmentActivity parent)
|
||||||
{
|
{
|
||||||
// Ask the user to grant write permission if it's not already granted
|
// Ask the user to grant write permission if it's not already granted
|
||||||
PermissionsHandler.checkWritePermission(parent);
|
PermissionsHandler.checkWritePermission(parent);
|
||||||
|
|
||||||
// Ask the user if he wants to enable analytics if we haven't yet.
|
// Ask the user if he wants to enable analytics if we haven't yet.
|
||||||
Analytics.checkAnalyticsInit(parent);
|
Analytics.checkAnalyticsInit(parent);
|
||||||
|
|
||||||
String start_file = "";
|
String start_file = "";
|
||||||
Bundle extras = parent.getIntent().getExtras();
|
Bundle extras = parent.getIntent().getExtras();
|
||||||
if (extras != null)
|
if (extras != null)
|
||||||
{
|
{
|
||||||
start_file = extras.getString("AutoStartFile");
|
start_file = extras.getString("AutoStartFile");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(start_file))
|
if (!TextUtils.isEmpty(start_file))
|
||||||
{
|
{
|
||||||
// Start the emulation activity, send the ISO passed in and finish the main activity
|
// Start the emulation activity, send the ISO passed in and finish the main activity
|
||||||
Intent emulation_intent = new Intent(parent, EmulationActivity.class);
|
Intent emulation_intent = new Intent(parent, EmulationActivity.class);
|
||||||
emulation_intent.putExtra("SelectedGame", start_file);
|
emulation_intent.putExtra("SelectedGame", start_file);
|
||||||
parent.startActivity(emulation_intent);
|
parent.startActivity(emulation_intent);
|
||||||
parent.finish();
|
parent.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* There isn't a good way to determine a new session. setSessionTime is called if the main
|
* There isn't a good way to determine a new session. setSessionTime is called if the main
|
||||||
* activity goes into the background.
|
* activity goes into the background.
|
||||||
*/
|
*/
|
||||||
public static void setSessionTime(Context context)
|
public static void setSessionTime(Context context)
|
||||||
{
|
{
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
SharedPreferences.Editor sPrefsEditor = preferences.edit();
|
SharedPreferences.Editor sPrefsEditor = preferences.edit();
|
||||||
sPrefsEditor.putLong(LAST_CLOSED, new Date(System.currentTimeMillis()).getTime());
|
sPrefsEditor.putLong(LAST_CLOSED, new Date(System.currentTimeMillis()).getTime());
|
||||||
sPrefsEditor.apply();
|
sPrefsEditor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to determine if we treat this activity start as a new session.
|
* Called to determine if we treat this activity start as a new session.
|
||||||
*/
|
*/
|
||||||
public static void checkSessionReset(Context context)
|
public static void checkSessionReset(Context context)
|
||||||
{
|
{
|
||||||
Long currentTime = new Date(System.currentTimeMillis()).getTime();
|
Long currentTime = new Date(System.currentTimeMillis()).getTime();
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
Long lastOpen = preferences.getLong(LAST_CLOSED, 0);
|
Long lastOpen = preferences.getLong(LAST_CLOSED, 0);
|
||||||
if (currentTime > (lastOpen + SESSION_TIMEOUT))
|
if (currentTime > (lastOpen + SESSION_TIMEOUT))
|
||||||
{
|
{
|
||||||
// Passed at emulation start to trigger first open event.
|
// Passed at emulation start to trigger first open event.
|
||||||
SharedPreferences.Editor sPrefsEditor = preferences.edit();
|
SharedPreferences.Editor sPrefsEditor = preferences.edit();
|
||||||
sPrefsEditor.putBoolean(NEW_SESSION, true);
|
sPrefsEditor.putBoolean(NEW_SESSION, true);
|
||||||
sPrefsEditor.apply();
|
sPrefsEditor.apply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ import android.graphics.drawable.VectorDrawable;
|
||||||
import android.media.tv.TvContract;
|
import android.media.tv.TvContract;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
import android.support.annotation.AnyRes;
|
import android.support.annotation.AnyRes;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
|
@ -25,7 +24,6 @@ import android.support.media.tv.Channel;
|
||||||
import android.support.media.tv.TvContractCompat;
|
import android.support.media.tv.TvContractCompat;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
|
||||||
import org.dolphinemu.dolphinemu.model.GameFile;
|
import org.dolphinemu.dolphinemu.model.GameFile;
|
||||||
import org.dolphinemu.dolphinemu.model.HomeScreenChannel;
|
import org.dolphinemu.dolphinemu.model.HomeScreenChannel;
|
||||||
import org.dolphinemu.dolphinemu.services.SyncChannelJobService;
|
import org.dolphinemu.dolphinemu.services.SyncChannelJobService;
|
||||||
|
@ -33,7 +31,6 @@ import org.dolphinemu.dolphinemu.services.SyncProgramsJobService;
|
||||||
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -45,232 +42,234 @@ import static android.support.v4.content.FileProvider.getUriForFile;
|
||||||
*/
|
*/
|
||||||
public class TvUtil
|
public class TvUtil
|
||||||
{
|
{
|
||||||
private static final String TAG = "TvUtil";
|
private static final String TAG = "TvUtil";
|
||||||
private static final long CHANNEL_JOB_ID_OFFSET = 1000;
|
private static final long CHANNEL_JOB_ID_OFFSET = 1000;
|
||||||
|
|
||||||
private static final String[] CHANNELS_PROJECTION = {
|
private static final String[] CHANNELS_PROJECTION = {
|
||||||
TvContractCompat.Channels._ID,
|
TvContractCompat.Channels._ID,
|
||||||
TvContract.Channels.COLUMN_DISPLAY_NAME,
|
TvContract.Channels.COLUMN_DISPLAY_NAME,
|
||||||
TvContractCompat.Channels.COLUMN_BROWSABLE
|
TvContractCompat.Channels.COLUMN_BROWSABLE
|
||||||
};
|
};
|
||||||
private static final String LEANBACK_PACKAGE = "com.google.android.tvlauncher";
|
private static final String LEANBACK_PACKAGE = "com.google.android.tvlauncher";
|
||||||
|
|
||||||
public static int getNumberOfChannels(Context context)
|
public static int getNumberOfChannels(Context context)
|
||||||
{
|
{
|
||||||
Cursor cursor =
|
Cursor cursor =
|
||||||
context.getContentResolver()
|
context.getContentResolver()
|
||||||
.query(
|
.query(
|
||||||
TvContractCompat.Channels.CONTENT_URI,
|
TvContractCompat.Channels.CONTENT_URI,
|
||||||
CHANNELS_PROJECTION,
|
CHANNELS_PROJECTION,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
return cursor != null ? cursor.getCount() : 0;
|
return cursor != null ? cursor.getCount() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Channel> getAllChannels(Context context)
|
public static List<Channel> getAllChannels(Context context)
|
||||||
{
|
{
|
||||||
List<Channel> channels = new ArrayList<>();
|
List<Channel> channels = new ArrayList<>();
|
||||||
Cursor cursor =
|
Cursor cursor =
|
||||||
context.getContentResolver()
|
context.getContentResolver()
|
||||||
.query(
|
.query(
|
||||||
TvContractCompat.Channels.CONTENT_URI,
|
TvContractCompat.Channels.CONTENT_URI,
|
||||||
CHANNELS_PROJECTION,
|
CHANNELS_PROJECTION,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
if (cursor != null && cursor.moveToFirst())
|
if (cursor != null && cursor.moveToFirst())
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
channels.add(Channel.fromCursor(cursor));
|
channels.add(Channel.fromCursor(cursor));
|
||||||
} while (cursor.moveToNext());
|
}
|
||||||
}
|
while (cursor.moveToNext());
|
||||||
return channels;
|
}
|
||||||
}
|
return channels;
|
||||||
|
}
|
||||||
|
|
||||||
public static Channel getChannelById(Context context, long channelId)
|
public static Channel getChannelById(Context context, long channelId)
|
||||||
{
|
{
|
||||||
for (Channel channel : getAllChannels(context))
|
for (Channel channel : getAllChannels(context))
|
||||||
{
|
{
|
||||||
if (channel.getId() == channelId)
|
if (channel.getId() == channelId)
|
||||||
{
|
{
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates all Leanback homescreen channels
|
* Updates all Leanback homescreen channels
|
||||||
*/
|
*/
|
||||||
public static void updateAllChannels(Context context)
|
public static void updateAllChannels(Context context)
|
||||||
{
|
{
|
||||||
if (Build.VERSION.SDK_INT < 26)
|
if (Build.VERSION.SDK_INT < 26)
|
||||||
return;
|
return;
|
||||||
for (Channel channel : getAllChannels(context))
|
for (Channel channel : getAllChannels(context))
|
||||||
{
|
{
|
||||||
context.getContentResolver()
|
context.getContentResolver()
|
||||||
.update(
|
.update(
|
||||||
TvContractCompat.buildChannelUri(channel.getId()),
|
TvContractCompat.buildChannelUri(channel.getId()),
|
||||||
channel.toContentValues(),
|
channel.toContentValues(),
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Uri getUriToResource(Context context, @AnyRes int resId)
|
public static Uri getUriToResource(Context context, @AnyRes int resId)
|
||||||
throws Resources.NotFoundException
|
throws Resources.NotFoundException
|
||||||
{
|
{
|
||||||
Resources res = context.getResources();
|
Resources res = context.getResources();
|
||||||
Uri resUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
|
Uri resUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE +
|
||||||
"://" + res.getResourcePackageName(resId)
|
"://" + res.getResourcePackageName(resId)
|
||||||
+ '/' + res.getResourceTypeName(resId)
|
+ '/' + res.getResourceTypeName(resId)
|
||||||
+ '/' + res.getResourceEntryName(resId));
|
+ '/' + res.getResourceEntryName(resId));
|
||||||
return resUri;
|
return resUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a resource into a {@link Bitmap}. If the resource is a vector drawable, it will be
|
* 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.
|
* drawn into a new Bitmap. Otherwise the {@link BitmapFactory} will decode the resource.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static Bitmap convertToBitmap(Context context, int resourceId)
|
public static Bitmap convertToBitmap(Context context, int resourceId)
|
||||||
{
|
{
|
||||||
Drawable drawable = context.getDrawable(resourceId);
|
Drawable drawable = context.getDrawable(resourceId);
|
||||||
if (drawable instanceof VectorDrawable)
|
if (drawable instanceof VectorDrawable)
|
||||||
{
|
{
|
||||||
Bitmap bitmap =
|
Bitmap bitmap =
|
||||||
Bitmap.createBitmap(
|
Bitmap.createBitmap(
|
||||||
drawable.getIntrinsicWidth(),
|
drawable.getIntrinsicWidth(),
|
||||||
drawable.getIntrinsicHeight(),
|
drawable.getIntrinsicHeight(),
|
||||||
Bitmap.Config.ARGB_8888);
|
Bitmap.Config.ARGB_8888);
|
||||||
Canvas canvas = new Canvas(bitmap);
|
Canvas canvas = new Canvas(bitmap);
|
||||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||||
drawable.draw(canvas);
|
drawable.draw(canvas);
|
||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
return BitmapFactory.decodeResource(context.getResources(), resourceId);
|
return BitmapFactory.decodeResource(context.getResources(), resourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leanback lanucher requires a uri for poster art so we create a contentUri and
|
* Leanback lanucher requires a uri for poster art so we create a contentUri and
|
||||||
* pass that to LEANBACK_PACKAGE
|
* pass that to LEANBACK_PACKAGE
|
||||||
*/
|
*/
|
||||||
public static Uri buildBanner(GameFile game, Context context)
|
public static Uri buildBanner(GameFile game, Context context)
|
||||||
{
|
{
|
||||||
Uri contentUri = null;
|
Uri contentUri = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File cover = new File(game.getCustomCoverPath());
|
File cover = new File(game.getCustomCoverPath());
|
||||||
if(cover.exists())
|
if (cover.exists())
|
||||||
{
|
{
|
||||||
contentUri = getUriForFile(context, getFileProvider(context), cover);
|
contentUri = getUriForFile(context, getFileProvider(context), cover);
|
||||||
}
|
}
|
||||||
else if ((cover = new File(game.getCoverPath())).exists())
|
else if ((cover = new File(game.getCoverPath())).exists())
|
||||||
{
|
{
|
||||||
contentUri = getUriForFile(context, getFileProvider(context), cover);
|
contentUri = getUriForFile(context, getFileProvider(context), cover);
|
||||||
}
|
}
|
||||||
context.grantUriPermission(LEANBACK_PACKAGE, contentUri,
|
context.grantUriPermission(LEANBACK_PACKAGE, contentUri,
|
||||||
FLAG_GRANT_READ_URI_PERMISSION);
|
FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.e(TAG, "Failed to create banner");
|
Log.e(TAG, "Failed to create banner");
|
||||||
Log.e(TAG, e.getMessage());
|
Log.e(TAG, e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return contentUri;
|
return contentUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Needed since debug builds append '.debug' to the end of the package
|
* Needed since debug builds append '.debug' to the end of the package
|
||||||
*/
|
*/
|
||||||
private static String getFileProvider(Context context)
|
private static String getFileProvider(Context context)
|
||||||
{
|
{
|
||||||
return context.getPackageName() + ".filesprovider";
|
return context.getPackageName() + ".filesprovider";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedules syncing channels via a {@link JobScheduler}.
|
* Schedules syncing channels via a {@link JobScheduler}.
|
||||||
*
|
*
|
||||||
* @param context for accessing the {@link JobScheduler}.
|
* @param context for accessing the {@link JobScheduler}.
|
||||||
*/
|
*/
|
||||||
public static void scheduleSyncingChannel(Context context)
|
public static void scheduleSyncingChannel(Context context)
|
||||||
{
|
{
|
||||||
ComponentName componentName = new ComponentName(context, SyncChannelJobService.class);
|
ComponentName componentName = new ComponentName(context, SyncChannelJobService.class);
|
||||||
JobInfo.Builder builder = new JobInfo.Builder(1, componentName);
|
JobInfo.Builder builder = new JobInfo.Builder(1, componentName);
|
||||||
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||||
|
|
||||||
JobScheduler scheduler =
|
JobScheduler scheduler =
|
||||||
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||||
|
|
||||||
Log.d(TAG, "Scheduled channel creation.");
|
Log.d(TAG, "Scheduled channel creation.");
|
||||||
scheduler.schedule(builder.build());
|
scheduler.schedule(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedulers syncing programs for a channel. The scheduler will listen to a {@link Uri} for a
|
* Schedulers syncing programs for a channel. The scheduler will listen to a {@link Uri} for a
|
||||||
* particular channel.
|
* particular channel.
|
||||||
*
|
*
|
||||||
* @param context for accessing the {@link JobScheduler}.
|
* @param context for accessing the {@link JobScheduler}.
|
||||||
* @param channelId for the channel to listen for changes.
|
* @param channelId for the channel to listen for changes.
|
||||||
*/
|
*/
|
||||||
@TargetApi(Build.VERSION_CODES.O)
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
public static void scheduleSyncingProgramsForChannel(Context context, long channelId)
|
public static void scheduleSyncingProgramsForChannel(Context context, long channelId)
|
||||||
{
|
{
|
||||||
Log.d(TAG, "ProgramsRefresh job");
|
Log.d(TAG, "ProgramsRefresh job");
|
||||||
ComponentName componentName = new ComponentName(context, SyncProgramsJobService.class);
|
ComponentName componentName = new ComponentName(context, SyncProgramsJobService.class);
|
||||||
JobInfo.Builder builder =
|
JobInfo.Builder builder =
|
||||||
new JobInfo.Builder(getJobIdForChannelId(channelId), componentName);
|
new JobInfo.Builder(getJobIdForChannelId(channelId), componentName);
|
||||||
JobInfo.TriggerContentUri triggerContentUri =
|
JobInfo.TriggerContentUri triggerContentUri =
|
||||||
new JobInfo.TriggerContentUri(
|
new JobInfo.TriggerContentUri(
|
||||||
TvContractCompat.buildChannelUri(channelId),
|
TvContractCompat.buildChannelUri(channelId),
|
||||||
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS);
|
JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS);
|
||||||
builder.addTriggerContentUri(triggerContentUri);
|
builder.addTriggerContentUri(triggerContentUri);
|
||||||
builder.setTriggerContentMaxDelay(0L);
|
builder.setTriggerContentMaxDelay(0L);
|
||||||
builder.setTriggerContentUpdateDelay(0L);
|
builder.setTriggerContentUpdateDelay(0L);
|
||||||
|
|
||||||
PersistableBundle bundle = new PersistableBundle();
|
PersistableBundle bundle = new PersistableBundle();
|
||||||
bundle.putLong(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
|
bundle.putLong(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
|
||||||
builder.setExtras(bundle);
|
builder.setExtras(bundle);
|
||||||
|
|
||||||
JobScheduler scheduler =
|
JobScheduler scheduler =
|
||||||
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||||
scheduler.cancel(getJobIdForChannelId(channelId));
|
scheduler.cancel(getJobIdForChannelId(channelId));
|
||||||
scheduler.schedule(builder.build());
|
scheduler.schedule(builder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getJobIdForChannelId(long channelId)
|
private static int getJobIdForChannelId(long channelId)
|
||||||
{
|
{
|
||||||
return (int) (CHANNEL_JOB_ID_OFFSET + channelId);
|
return (int) (CHANNEL_JOB_ID_OFFSET + channelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates all subscriptions for homescreen channels.
|
* Generates all subscriptions for homescreen channels.
|
||||||
*/
|
*/
|
||||||
public static List<HomeScreenChannel> createUniversalSubscriptions()
|
public static List<HomeScreenChannel> createUniversalSubscriptions()
|
||||||
{
|
{
|
||||||
//Leaving the subs local variable in case more channels are created other than platforms.
|
//Leaving the subs local variable in case more channels are created other than platforms.
|
||||||
List<HomeScreenChannel> subs = new ArrayList<>(createPlatformSubscriptions());
|
List<HomeScreenChannel> subs = new ArrayList<>(createPlatformSubscriptions());
|
||||||
return subs;
|
return subs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<HomeScreenChannel> createPlatformSubscriptions()
|
private static List<HomeScreenChannel> createPlatformSubscriptions()
|
||||||
{
|
{
|
||||||
List<HomeScreenChannel> subs = new ArrayList<>();
|
List<HomeScreenChannel> subs = new ArrayList<>();
|
||||||
for (Platform platform : Platform.values())
|
for (Platform platform : Platform.values())
|
||||||
{
|
{
|
||||||
subs.add(new HomeScreenChannel(
|
subs.add(new HomeScreenChannel(
|
||||||
platform.getHeaderName(),
|
platform.getHeaderName(),
|
||||||
platform.getHeaderName(),
|
platform.getHeaderName(),
|
||||||
AppLinkHelper.buildBrowseUri(platform.getHeaderName()).toString()));
|
AppLinkHelper.buildBrowseUri(platform.getHeaderName()).toString()));
|
||||||
}
|
}
|
||||||
return subs;
|
return subs;
|
||||||
}
|
}
|
||||||
public static Boolean isLeanback(Context context)
|
|
||||||
{
|
public static Boolean isLeanback(Context context)
|
||||||
return(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK));
|
{
|
||||||
}
|
return (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,16 +7,16 @@ import com.android.volley.toolbox.Volley;
|
||||||
|
|
||||||
public class VolleyUtil
|
public class VolleyUtil
|
||||||
{
|
{
|
||||||
private static RequestQueue queue;
|
private static RequestQueue queue;
|
||||||
|
|
||||||
public static void init(Context context)
|
public static void init(Context context)
|
||||||
{
|
{
|
||||||
if (queue == null)
|
if (queue == null)
|
||||||
queue = Volley.newRequestQueue(context);
|
queue = Volley.newRequestQueue(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RequestQueue getQueue()
|
public static RequestQueue getQueue()
|
||||||
{
|
{
|
||||||
return queue;
|
return queue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,18 +13,18 @@ import org.dolphinemu.dolphinemu.R;
|
||||||
*/
|
*/
|
||||||
public class FileViewHolder extends RecyclerView.ViewHolder
|
public class FileViewHolder extends RecyclerView.ViewHolder
|
||||||
{
|
{
|
||||||
public View itemView;
|
public View itemView;
|
||||||
|
|
||||||
public TextView textFileName;
|
public TextView textFileName;
|
||||||
public ImageView imageType;
|
public ImageView imageType;
|
||||||
|
|
||||||
public FileViewHolder(View itemView)
|
public FileViewHolder(View itemView)
|
||||||
{
|
{
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
this.itemView = itemView;
|
this.itemView = itemView;
|
||||||
|
|
||||||
textFileName = (TextView) itemView.findViewById(R.id.text_file_name);
|
textFileName = (TextView) itemView.findViewById(R.id.text_file_name);
|
||||||
imageType = (ImageView) itemView.findViewById(R.id.image_type);
|
imageType = (ImageView) itemView.findViewById(R.id.image_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,20 +14,20 @@ import org.dolphinemu.dolphinemu.model.GameFile;
|
||||||
*/
|
*/
|
||||||
public class GameViewHolder extends RecyclerView.ViewHolder
|
public class GameViewHolder extends RecyclerView.ViewHolder
|
||||||
{
|
{
|
||||||
public ImageView imageScreenshot;
|
public ImageView imageScreenshot;
|
||||||
public TextView textGameTitle;
|
public TextView textGameTitle;
|
||||||
public TextView textCompany;
|
public TextView textCompany;
|
||||||
|
|
||||||
public GameFile gameFile;
|
public GameFile gameFile;
|
||||||
|
|
||||||
public GameViewHolder(View itemView)
|
public GameViewHolder(View itemView)
|
||||||
{
|
{
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
itemView.setTag(this);
|
itemView.setTag(this);
|
||||||
|
|
||||||
imageScreenshot = itemView.findViewById(R.id.image_game_screen);
|
imageScreenshot = itemView.findViewById(R.id.image_game_screen);
|
||||||
textGameTitle = itemView.findViewById(R.id.text_game_title);
|
textGameTitle = itemView.findViewById(R.id.text_game_title);
|
||||||
textCompany = itemView.findViewById(R.id.text_company);
|
textCompany = itemView.findViewById(R.id.text_company);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,19 +13,19 @@ import org.dolphinemu.dolphinemu.model.GameFile;
|
||||||
*/
|
*/
|
||||||
public final class TvGameViewHolder extends Presenter.ViewHolder
|
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)
|
public TvGameViewHolder(View itemView)
|
||||||
{
|
{
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
itemView.setTag(this);
|
itemView.setTag(this);
|
||||||
|
|
||||||
cardParent = (ImageCardView) itemView;
|
cardParent = (ImageCardView) itemView;
|
||||||
imageScreenshot = cardParent.getMainImageView();
|
imageScreenshot = cardParent.getMainImageView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,17 +6,17 @@ import android.view.View;
|
||||||
|
|
||||||
public final class TvSettingsViewHolder extends Presenter.ViewHolder
|
public final class TvSettingsViewHolder extends Presenter.ViewHolder
|
||||||
{
|
{
|
||||||
public ImageCardView cardParent;
|
public ImageCardView cardParent;
|
||||||
|
|
||||||
// Determines what action to take when this item is clicked.
|
// Determines what action to take when this item is clicked.
|
||||||
public int itemId;
|
public int itemId;
|
||||||
|
|
||||||
public TvSettingsViewHolder(View itemView)
|
public TvSettingsViewHolder(View itemView)
|
||||||
{
|
{
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
|
||||||
itemView.setTag(this);
|
itemView.setTag(this);
|
||||||
|
|
||||||
cardParent = (ImageCardView) itemView;
|
cardParent = (ImageCardView) itemView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,19 +3,19 @@
|
||||||
|
|
||||||
<!-- This animation is used ONLY when a submenu is replaced. -->
|
<!-- This animation is used ONLY when a submenu is replaced. -->
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:propertyName="translationX"
|
android:propertyName="translationX"
|
||||||
android:valueType="floatType"
|
android:valueType="floatType"
|
||||||
android:valueFrom="0"
|
android:valueFrom="0"
|
||||||
android:valueTo="-1280dp"
|
android:valueTo="-1280dp"
|
||||||
android:interpolator="@android:interpolator/decelerate_quad"
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
android:duration="200"/>
|
android:duration="200"/>
|
||||||
|
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:propertyName="alpha"
|
android:propertyName="alpha"
|
||||||
android:valueType="floatType"
|
android:valueType="floatType"
|
||||||
android:valueFrom="1"
|
android:valueFrom="1"
|
||||||
android:valueTo="0"
|
android:valueTo="0"
|
||||||
android:interpolator="@android:interpolator/decelerate_quad"
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
android:duration="200"/>
|
android:duration="200"/>
|
||||||
|
|
||||||
</set>
|
</set>
|
|
@ -3,19 +3,19 @@
|
||||||
|
|
||||||
<!-- This animation is used ONLY when a submenu is replaced. -->
|
<!-- This animation is used ONLY when a submenu is replaced. -->
|
||||||
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:propertyName="translationX"
|
android:propertyName="translationX"
|
||||||
android:valueType="floatType"
|
android:valueType="floatType"
|
||||||
android:valueFrom="0"
|
android:valueFrom="0"
|
||||||
android:valueTo="1280dp"
|
android:valueTo="1280dp"
|
||||||
android:interpolator="@android:interpolator/decelerate_quad"
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
android:duration="200"/>
|
android:duration="200"/>
|
||||||
|
|
||||||
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:propertyName="alpha"
|
android:propertyName="alpha"
|
||||||
android:valueType="floatType"
|
android:valueType="floatType"
|
||||||
android:valueFrom="1"
|
android:valueFrom="1"
|
||||||
android:valueTo="0"
|
android:valueTo="0"
|
||||||
android:interpolator="@android:interpolator/decelerate_quad"
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
android:duration="200"/>
|
android:duration="200"/>
|
||||||
|
|
||||||
</set>
|
</set>
|
|
@ -2,7 +2,7 @@
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
<item
|
||||||
android:state_selected="true"
|
android:state_selected="true"
|
||||||
android:drawable="@color/dolphin_accent_gamecube" />
|
android:drawable="@color/dolphin_accent_gamecube"/>
|
||||||
<item
|
<item
|
||||||
android:drawable="@color/tv_card_unselected" />
|
android:drawable="@color/tv_card_unselected"/>
|
||||||
</selector>
|
</selector>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
<item
|
||||||
android:state_selected="true"
|
android:state_selected="true"
|
||||||
android:drawable="@color/dolphin_accent_wii" />
|
android:drawable="@color/dolphin_accent_wii"/>
|
||||||
<item
|
<item
|
||||||
android:drawable="@color/tv_card_unselected" />
|
android:drawable="@color/tv_card_unselected"/>
|
||||||
</selector>
|
</selector>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
<item
|
||||||
android:state_selected="true"
|
android:state_selected="true"
|
||||||
android:drawable="@color/dolphin_accent_wiiware" />
|
android:drawable="@color/dolphin_accent_wiiware"/>
|
||||||
<item
|
<item
|
||||||
android:drawable="@color/tv_card_unselected" />
|
android:drawable="@color/tv_card_unselected"/>
|
||||||
</selector>
|
</selector>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
|
<SurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/surface_emulation"
|
android:id="@+id/surface_emulation"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
/>
|
/>
|
|
@ -1,11 +1,11 @@
|
||||||
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/grid_state_slots"
|
android:id="@+id/grid_state_slots"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:columnCount="3"
|
android:columnCount="3"
|
||||||
android:rowCount="2"
|
android:rowCount="2"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:background="#af000000">
|
android:background="#af000000">
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/loadsave_state_button_1"
|
android:id="@+id/loadsave_state_button_1"
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue