diff options
| author | 2023-01-08 17:31:30 -0800 | |
|---|---|---|
| committer | 2023-06-03 00:05:28 -0700 | |
| commit | 4f903d8d3541b8898629e5c01c48f0d2e5a2f162 (patch) | |
| tree | 90c668f6e9bd6bc01ae04e4d884e3b2339568ccf | |
| parent | externals: add adrenotools for bcenabler (diff) | |
| download | yuzu-4f903d8d3541b8898629e5c01c48f0d2e5a2f162.tar.gz yuzu-4f903d8d3541b8898629e5c01c48f0d2e5a2f162.tar.xz yuzu-4f903d8d3541b8898629e5c01c48f0d2e5a2f162.zip | |
android: Integrate settings frontend with yuzu & remove unused code.
25 files changed, 949 insertions, 1759 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.java index cd64a3298..f4fca40e4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.java | |||
| @@ -3,17 +3,13 @@ package org.yuzu.yuzu_emu.activities; | |||
| 3 | import android.app.Activity; | 3 | import android.app.Activity; |
| 4 | import android.content.Intent; | 4 | import android.content.Intent; |
| 5 | import android.content.SharedPreferences; | 5 | import android.content.SharedPreferences; |
| 6 | import android.content.pm.PackageManager; | ||
| 7 | import android.graphics.Rect; | 6 | import android.graphics.Rect; |
| 8 | import android.os.Bundle; | 7 | import android.os.Bundle; |
| 9 | import android.os.Handler; | 8 | import android.os.Handler; |
| 10 | import android.preference.PreferenceManager; | 9 | import android.preference.PreferenceManager; |
| 11 | import android.util.SparseIntArray; | ||
| 12 | import android.view.InputDevice; | 10 | import android.view.InputDevice; |
| 13 | import android.view.KeyEvent; | 11 | import android.view.KeyEvent; |
| 14 | import android.view.LayoutInflater; | 12 | import android.view.LayoutInflater; |
| 15 | import android.view.Menu; | ||
| 16 | import android.view.MenuItem; | ||
| 17 | import android.view.MotionEvent; | 13 | import android.view.MotionEvent; |
| 18 | import android.view.View; | 14 | import android.view.View; |
| 19 | import android.widget.SeekBar; | 15 | import android.widget.SeekBar; |
| @@ -31,20 +27,14 @@ import androidx.fragment.app.FragmentManager; | |||
| 31 | 27 | ||
| 32 | import org.yuzu.yuzu_emu.NativeLibrary; | 28 | import org.yuzu.yuzu_emu.NativeLibrary; |
| 33 | import org.yuzu.yuzu_emu.R; | 29 | import org.yuzu.yuzu_emu.R; |
| 34 | import org.yuzu.yuzu_emu.features.settings.model.view.InputBindingSetting; | ||
| 35 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity; | ||
| 36 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile; | ||
| 37 | import org.yuzu.yuzu_emu.fragments.EmulationFragment; | 30 | import org.yuzu.yuzu_emu.fragments.EmulationFragment; |
| 38 | import org.yuzu.yuzu_emu.fragments.MenuFragment; | 31 | import org.yuzu.yuzu_emu.fragments.MenuFragment; |
| 39 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper; | 32 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper; |
| 40 | import org.yuzu.yuzu_emu.utils.EmulationMenuSettings; | ||
| 41 | import org.yuzu.yuzu_emu.utils.ForegroundService; | 33 | import org.yuzu.yuzu_emu.utils.ForegroundService; |
| 42 | 34 | ||
| 43 | import java.lang.annotation.Retention; | 35 | import java.lang.annotation.Retention; |
| 44 | import java.util.List; | 36 | import java.util.List; |
| 45 | 37 | ||
| 46 | import static android.Manifest.permission.CAMERA; | ||
| 47 | import static android.Manifest.permission.RECORD_AUDIO; | ||
| 48 | import static java.lang.annotation.RetentionPolicy.SOURCE; | 38 | import static java.lang.annotation.RetentionPolicy.SOURCE; |
| 49 | 39 | ||
| 50 | public final class EmulationActivity extends AppCompatActivity { | 40 | public final class EmulationActivity extends AppCompatActivity { |
| @@ -198,77 +188,6 @@ public final class EmulationActivity extends AppCompatActivity { | |||
| 198 | } | 188 | } |
| 199 | } | 189 | } |
| 200 | 190 | ||
| 201 | // Gets button presses | ||
| 202 | @Override | ||
| 203 | public boolean dispatchKeyEvent(KeyEvent event) { | ||
| 204 | if (mMenuVisible || event.getKeyCode() == KeyEvent.KEYCODE_BACK) | ||
| 205 | { | ||
| 206 | return super.dispatchKeyEvent(event); | ||
| 207 | } | ||
| 208 | |||
| 209 | int action; | ||
| 210 | int button = mPreferences.getInt(InputBindingSetting.getInputButtonKey(event.getKeyCode()), event.getKeyCode()); | ||
| 211 | |||
| 212 | switch (event.getAction()) { | ||
| 213 | case KeyEvent.ACTION_DOWN: | ||
| 214 | // Handling the case where the back button is pressed. | ||
| 215 | if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { | ||
| 216 | onBackPressed(); | ||
| 217 | return true; | ||
| 218 | } | ||
| 219 | |||
| 220 | // Normal key events. | ||
| 221 | action = NativeLibrary.ButtonState.PRESSED; | ||
| 222 | break; | ||
| 223 | case KeyEvent.ACTION_UP: | ||
| 224 | action = NativeLibrary.ButtonState.RELEASED; | ||
| 225 | break; | ||
| 226 | default: | ||
| 227 | return false; | ||
| 228 | } | ||
| 229 | InputDevice input = event.getDevice(); | ||
| 230 | |||
| 231 | if (input == null) { | ||
| 232 | // Controller was disconnected | ||
| 233 | return false; | ||
| 234 | } | ||
| 235 | |||
| 236 | return NativeLibrary.onGamePadEvent(input.getDescriptor(), button, action); | ||
| 237 | } | ||
| 238 | |||
| 239 | private void toggleControls() { | ||
| 240 | final SharedPreferences.Editor editor = mPreferences.edit(); | ||
| 241 | boolean[] enabledButtons = new boolean[14]; | ||
| 242 | AlertDialog.Builder builder = new AlertDialog.Builder(this); | ||
| 243 | builder.setTitle(R.string.emulation_toggle_controls); | ||
| 244 | |||
| 245 | for (int i = 0; i < enabledButtons.length; i++) { | ||
| 246 | // Buttons that are disabled by default | ||
| 247 | boolean defaultValue = true; | ||
| 248 | switch (i) { | ||
| 249 | case 6: // ZL | ||
| 250 | case 7: // ZR | ||
| 251 | case 12: // C-stick | ||
| 252 | defaultValue = false; | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | |||
| 256 | enabledButtons[i] = mPreferences.getBoolean("buttonToggle" + i, defaultValue); | ||
| 257 | } | ||
| 258 | builder.setMultiChoiceItems(R.array.n3dsButtons, enabledButtons, | ||
| 259 | (dialog, indexSelected, isChecked) -> editor | ||
| 260 | .putBoolean("buttonToggle" + indexSelected, isChecked)); | ||
| 261 | builder.setPositiveButton(android.R.string.ok, (dialogInterface, i) -> | ||
| 262 | { | ||
| 263 | editor.apply(); | ||
| 264 | |||
| 265 | mEmulationFragment.refreshInputOverlay(); | ||
| 266 | }); | ||
| 267 | |||
| 268 | AlertDialog alertDialog = builder.create(); | ||
| 269 | alertDialog.show(); | ||
| 270 | } | ||
| 271 | |||
| 272 | private void adjustScale() { | 191 | private void adjustScale() { |
| 273 | LayoutInflater inflater = LayoutInflater.from(this); | 192 | LayoutInflater inflater = LayoutInflater.from(this); |
| 274 | View view = inflater.inflate(R.layout.dialog_seekbar, null); | 193 | View view = inflater.inflate(R.layout.dialog_seekbar, null); |
| @@ -377,122 +296,6 @@ public final class EmulationActivity extends AppCompatActivity { | |||
| 377 | return super.dispatchTouchEvent(event); | 296 | return super.dispatchTouchEvent(event); |
| 378 | } | 297 | } |
| 379 | 298 | ||
| 380 | @Override | ||
| 381 | public boolean dispatchGenericMotionEvent(MotionEvent event) { | ||
| 382 | if (mMenuVisible) | ||
| 383 | { | ||
| 384 | return false; | ||
| 385 | } | ||
| 386 | |||
| 387 | if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)) { | ||
| 388 | return super.dispatchGenericMotionEvent(event); | ||
| 389 | } | ||
| 390 | |||
| 391 | // Don't attempt to do anything if we are disconnecting a device. | ||
| 392 | if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { | ||
| 393 | return true; | ||
| 394 | } | ||
| 395 | |||
| 396 | InputDevice input = event.getDevice(); | ||
| 397 | List<InputDevice.MotionRange> motions = input.getMotionRanges(); | ||
| 398 | |||
| 399 | float[] axisValuesCirclePad = {0.0f, 0.0f}; | ||
| 400 | float[] axisValuesCStick = {0.0f, 0.0f}; | ||
| 401 | float[] axisValuesDPad = {0.0f, 0.0f}; | ||
| 402 | boolean isTriggerPressedLMapped = false; | ||
| 403 | boolean isTriggerPressedRMapped = false; | ||
| 404 | boolean isTriggerPressedZLMapped = false; | ||
| 405 | boolean isTriggerPressedZRMapped = false; | ||
| 406 | boolean isTriggerPressedL = false; | ||
| 407 | boolean isTriggerPressedR = false; | ||
| 408 | boolean isTriggerPressedZL = false; | ||
| 409 | boolean isTriggerPressedZR = false; | ||
| 410 | |||
| 411 | for (InputDevice.MotionRange range : motions) { | ||
| 412 | int axis = range.getAxis(); | ||
| 413 | float origValue = event.getAxisValue(axis); | ||
| 414 | float value = mControllerMappingHelper.scaleAxis(input, axis, origValue); | ||
| 415 | int nextMapping = mPreferences.getInt(InputBindingSetting.getInputAxisButtonKey(axis), -1); | ||
| 416 | int guestOrientation = mPreferences.getInt(InputBindingSetting.getInputAxisOrientationKey(axis), -1); | ||
| 417 | |||
| 418 | if (nextMapping == -1 || guestOrientation == -1) { | ||
| 419 | // Axis is unmapped | ||
| 420 | continue; | ||
| 421 | } | ||
| 422 | |||
| 423 | if ((value > 0.f && value < 0.1f) || (value < 0.f && value > -0.1f)) { | ||
| 424 | // Skip joystick wobble | ||
| 425 | value = 0.f; | ||
| 426 | } | ||
| 427 | |||
| 428 | if (nextMapping == NativeLibrary.ButtonType.STICK_LEFT) { | ||
| 429 | axisValuesCirclePad[guestOrientation] = value; | ||
| 430 | } else if (nextMapping == NativeLibrary.ButtonType.STICK_C) { | ||
| 431 | axisValuesCStick[guestOrientation] = value; | ||
| 432 | } else if (nextMapping == NativeLibrary.ButtonType.DPAD) { | ||
| 433 | axisValuesDPad[guestOrientation] = value; | ||
| 434 | } else if (nextMapping == NativeLibrary.ButtonType.TRIGGER_L) { | ||
| 435 | isTriggerPressedLMapped = true; | ||
| 436 | isTriggerPressedL = value != 0.f; | ||
| 437 | } else if (nextMapping == NativeLibrary.ButtonType.TRIGGER_R) { | ||
| 438 | isTriggerPressedRMapped = true; | ||
| 439 | isTriggerPressedR = value != 0.f; | ||
| 440 | } else if (nextMapping == NativeLibrary.ButtonType.BUTTON_ZL) { | ||
| 441 | isTriggerPressedZLMapped = true; | ||
| 442 | isTriggerPressedZL = value != 0.f; | ||
| 443 | } else if (nextMapping == NativeLibrary.ButtonType.BUTTON_ZR) { | ||
| 444 | isTriggerPressedZRMapped = true; | ||
| 445 | isTriggerPressedZR = value != 0.f; | ||
| 446 | } | ||
| 447 | } | ||
| 448 | |||
| 449 | // Circle-Pad and C-Stick status | ||
| 450 | NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), NativeLibrary.ButtonType.STICK_LEFT, axisValuesCirclePad[0], axisValuesCirclePad[1]); | ||
| 451 | NativeLibrary.onGamePadMoveEvent(input.getDescriptor(), NativeLibrary.ButtonType.STICK_C, axisValuesCStick[0], axisValuesCStick[1]); | ||
| 452 | |||
| 453 | // Triggers L/R and ZL/ZR | ||
| 454 | if (isTriggerPressedLMapped) { | ||
| 455 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.TRIGGER_L, isTriggerPressedL ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED); | ||
| 456 | } | ||
| 457 | if (isTriggerPressedRMapped) { | ||
| 458 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.TRIGGER_R, isTriggerPressedR ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED); | ||
| 459 | } | ||
| 460 | if (isTriggerPressedZLMapped) { | ||
| 461 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.BUTTON_ZL, isTriggerPressedZL ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED); | ||
| 462 | } | ||
| 463 | if (isTriggerPressedZRMapped) { | ||
| 464 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.BUTTON_ZR, isTriggerPressedZR ? NativeLibrary.ButtonState.PRESSED : NativeLibrary.ButtonState.RELEASED); | ||
| 465 | } | ||
| 466 | |||
| 467 | // Work-around to allow D-pad axis to be bound to emulated buttons | ||
| 468 | if (axisValuesDPad[0] == 0.f) { | ||
| 469 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED); | ||
| 470 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED); | ||
| 471 | } | ||
| 472 | if (axisValuesDPad[0] < 0.f) { | ||
| 473 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.PRESSED); | ||
| 474 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.RELEASED); | ||
| 475 | } | ||
| 476 | if (axisValuesDPad[0] > 0.f) { | ||
| 477 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_LEFT, NativeLibrary.ButtonState.RELEASED); | ||
| 478 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_RIGHT, NativeLibrary.ButtonState.PRESSED); | ||
| 479 | } | ||
| 480 | if (axisValuesDPad[1] == 0.f) { | ||
| 481 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED); | ||
| 482 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED); | ||
| 483 | } | ||
| 484 | if (axisValuesDPad[1] < 0.f) { | ||
| 485 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.PRESSED); | ||
| 486 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.RELEASED); | ||
| 487 | } | ||
| 488 | if (axisValuesDPad[1] > 0.f) { | ||
| 489 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_UP, NativeLibrary.ButtonState.RELEASED); | ||
| 490 | NativeLibrary.onGamePadEvent(NativeLibrary.TouchScreenDevice, NativeLibrary.ButtonType.DPAD_DOWN, NativeLibrary.ButtonState.PRESSED); | ||
| 491 | } | ||
| 492 | |||
| 493 | return true; | ||
| 494 | } | ||
| 495 | |||
| 496 | public boolean isActivityRecreated() { | 299 | public boolean isActivityRecreated() { |
| 497 | return activityRecreated; | 300 | return activityRecreated; |
| 498 | } | 301 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/MotionAlertDialog.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/MotionAlertDialog.java deleted file mode 100644 index 874c1acbc..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/dialogs/MotionAlertDialog.java +++ /dev/null | |||
| @@ -1,140 +0,0 @@ | |||
| 1 | package org.yuzu.yuzu_emu.dialogs; | ||
| 2 | |||
| 3 | import android.content.Context; | ||
| 4 | import android.view.InputDevice; | ||
| 5 | import android.view.KeyEvent; | ||
| 6 | import android.view.MotionEvent; | ||
| 7 | |||
| 8 | import androidx.annotation.NonNull; | ||
| 9 | import androidx.appcompat.app.AlertDialog; | ||
| 10 | |||
| 11 | import org.yuzu.yuzu_emu.features.settings.model.view.InputBindingSetting; | ||
| 12 | import org.yuzu.yuzu_emu.utils.Log; | ||
| 13 | |||
| 14 | import java.util.ArrayList; | ||
| 15 | import java.util.List; | ||
| 16 | |||
| 17 | /** | ||
| 18 | * {@link AlertDialog} derivative that listens for | ||
| 19 | * motion events from controllers and joysticks. | ||
| 20 | */ | ||
| 21 | public final class MotionAlertDialog extends AlertDialog { | ||
| 22 | // The selected input preference | ||
| 23 | private final InputBindingSetting setting; | ||
| 24 | private final ArrayList<Float> mPreviousValues = new ArrayList<>(); | ||
| 25 | private int mPrevDeviceId = 0; | ||
| 26 | private boolean mWaitingForEvent = true; | ||
| 27 | |||
| 28 | /** | ||
| 29 | * Constructor | ||
| 30 | * | ||
| 31 | * @param context The current {@link Context}. | ||
| 32 | * @param setting The Preference to show this dialog for. | ||
| 33 | */ | ||
| 34 | public MotionAlertDialog(Context context, InputBindingSetting setting) { | ||
| 35 | super(context); | ||
| 36 | |||
| 37 | this.setting = setting; | ||
| 38 | } | ||
| 39 | |||
| 40 | public boolean onKeyEvent(int keyCode, KeyEvent event) { | ||
| 41 | Log.debug("[MotionAlertDialog] Received key event: " + event.getAction()); | ||
| 42 | switch (event.getAction()) { | ||
| 43 | case KeyEvent.ACTION_UP: | ||
| 44 | setting.onKeyInput(event); | ||
| 45 | dismiss(); | ||
| 46 | // Even if we ignore the key, we still consume it. Thus return true regardless. | ||
| 47 | return true; | ||
| 48 | |||
| 49 | default: | ||
| 50 | return false; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | @Override | ||
| 55 | public boolean onKeyLongPress(int keyCode, @NonNull KeyEvent event) { | ||
| 56 | return super.onKeyLongPress(keyCode, event); | ||
| 57 | } | ||
| 58 | |||
| 59 | @Override | ||
| 60 | public boolean dispatchKeyEvent(KeyEvent event) { | ||
| 61 | // Handle this key if we care about it, otherwise pass it down the framework | ||
| 62 | return onKeyEvent(event.getKeyCode(), event) || super.dispatchKeyEvent(event); | ||
| 63 | } | ||
| 64 | |||
| 65 | @Override | ||
| 66 | public boolean dispatchGenericMotionEvent(@NonNull MotionEvent event) { | ||
| 67 | // Handle this event if we care about it, otherwise pass it down the framework | ||
| 68 | return onMotionEvent(event) || super.dispatchGenericMotionEvent(event); | ||
| 69 | } | ||
| 70 | |||
| 71 | private boolean onMotionEvent(MotionEvent event) { | ||
| 72 | if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) | ||
| 73 | return false; | ||
| 74 | if (event.getAction() != MotionEvent.ACTION_MOVE) | ||
| 75 | return false; | ||
| 76 | |||
| 77 | InputDevice input = event.getDevice(); | ||
| 78 | |||
| 79 | List<InputDevice.MotionRange> motionRanges = input.getMotionRanges(); | ||
| 80 | |||
| 81 | if (input.getId() != mPrevDeviceId) { | ||
| 82 | mPreviousValues.clear(); | ||
| 83 | } | ||
| 84 | mPrevDeviceId = input.getId(); | ||
| 85 | boolean firstEvent = mPreviousValues.isEmpty(); | ||
| 86 | |||
| 87 | int numMovedAxis = 0; | ||
| 88 | float axisMoveValue = 0.0f; | ||
| 89 | InputDevice.MotionRange lastMovedRange = null; | ||
| 90 | char lastMovedDir = '?'; | ||
| 91 | if (mWaitingForEvent) { | ||
| 92 | for (int i = 0; i < motionRanges.size(); i++) { | ||
| 93 | InputDevice.MotionRange range = motionRanges.get(i); | ||
| 94 | int axis = range.getAxis(); | ||
| 95 | float origValue = event.getAxisValue(axis); | ||
| 96 | float value = origValue;//ControllerMappingHelper.scaleAxis(input, axis, origValue); | ||
| 97 | if (firstEvent) { | ||
| 98 | mPreviousValues.add(value); | ||
| 99 | } else { | ||
| 100 | float previousValue = mPreviousValues.get(i); | ||
| 101 | |||
| 102 | // Only handle the axes that are not neutral (more than 0.5) | ||
| 103 | // but ignore any axis that has a constant value (e.g. always 1) | ||
| 104 | if (Math.abs(value) > 0.5f && value != previousValue) { | ||
| 105 | // It is common to have multiple axes with the same physical input. For example, | ||
| 106 | // shoulder butters are provided as both AXIS_LTRIGGER and AXIS_BRAKE. | ||
| 107 | // To handle this, we ignore an axis motion that's the exact same as a motion | ||
| 108 | // we already saw. This way, we ignore axes with two names, but catch the case | ||
| 109 | // where a joystick is moved in two directions. | ||
| 110 | // ref: bottom of https://developer.android.com/training/game-controllers/controller-input.html | ||
| 111 | if (value != axisMoveValue) { | ||
| 112 | axisMoveValue = value; | ||
| 113 | numMovedAxis++; | ||
| 114 | lastMovedRange = range; | ||
| 115 | lastMovedDir = value < 0.0f ? '-' : '+'; | ||
| 116 | } | ||
| 117 | } | ||
| 118 | // Special case for d-pads (axis value jumps between 0 and 1 without any values | ||
| 119 | // in between). Without this, the user would need to press the d-pad twice | ||
| 120 | // due to the first press being caught by the "if (firstEvent)" case further up. | ||
| 121 | else if (Math.abs(value) < 0.25f && Math.abs(previousValue) > 0.75f) { | ||
| 122 | numMovedAxis++; | ||
| 123 | lastMovedRange = range; | ||
| 124 | lastMovedDir = previousValue < 0.0f ? '-' : '+'; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | mPreviousValues.set(i, value); | ||
| 129 | } | ||
| 130 | |||
| 131 | // If only one axis moved, that's the winner. | ||
| 132 | if (numMovedAxis == 1) { | ||
| 133 | mWaitingForEvent = false; | ||
| 134 | setting.onMotionInput(input, lastMovedRange, lastMovedDir); | ||
| 135 | dismiss(); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | return true; | ||
| 139 | } | ||
| 140 | } \ No newline at end of file | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.java index efde45ee9..3126eba73 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.java | |||
| @@ -14,22 +14,18 @@ import java.util.Map; | |||
| 14 | import java.util.TreeMap; | 14 | import java.util.TreeMap; |
| 15 | 15 | ||
| 16 | public class Settings { | 16 | public class Settings { |
| 17 | public static final String SECTION_PREMIUM = "Premium"; | 17 | public static final String SECTION_GENERAL = "General"; |
| 18 | public static final String SECTION_CORE = "Core"; | ||
| 19 | public static final String SECTION_SYSTEM = "System"; | 18 | public static final String SECTION_SYSTEM = "System"; |
| 20 | public static final String SECTION_CONTROLS = "Controls"; | ||
| 21 | public static final String SECTION_RENDERER = "Renderer"; | 19 | public static final String SECTION_RENDERER = "Renderer"; |
| 22 | public static final String SECTION_LAYOUT = "Layout"; | ||
| 23 | public static final String SECTION_UTILITY = "Utility"; | ||
| 24 | public static final String SECTION_AUDIO = "Audio"; | 20 | public static final String SECTION_AUDIO = "Audio"; |
| 25 | public static final String SECTION_DEBUG = "Debug"; | 21 | public static final String SECTION_CPU = "Cpu"; |
| 26 | 22 | ||
| 27 | private String gameId; | 23 | private String gameId; |
| 28 | 24 | ||
| 29 | private static final Map<String, List<String>> configFileSectionsMap = new HashMap<>(); | 25 | private static final Map<String, List<String>> configFileSectionsMap = new HashMap<>(); |
| 30 | 26 | ||
| 31 | static { | 27 | static { |
| 32 | configFileSectionsMap.put(SettingsFile.FILE_NAME_CONFIG, Arrays.asList(SECTION_PREMIUM, SECTION_CORE, SECTION_SYSTEM, SECTION_CONTROLS, SECTION_RENDERER, SECTION_LAYOUT, SECTION_UTILITY, SECTION_AUDIO, SECTION_DEBUG)); | 28 | configFileSectionsMap.put(SettingsFile.FILE_NAME_CONFIG, Arrays.asList(SECTION_GENERAL, SECTION_SYSTEM, SECTION_RENDERER, SECTION_AUDIO, SECTION_CPU)); |
| 33 | } | 29 | } |
| 34 | 30 | ||
| 35 | /** | 31 | /** |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputBindingSetting.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputBindingSetting.java deleted file mode 100644 index 4ad54421e..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/InputBindingSetting.java +++ /dev/null | |||
| @@ -1,382 +0,0 @@ | |||
| 1 | package org.yuzu.yuzu_emu.features.settings.model.view; | ||
| 2 | |||
| 3 | import android.content.SharedPreferences; | ||
| 4 | import android.preference.PreferenceManager; | ||
| 5 | import android.view.InputDevice; | ||
| 6 | import android.view.KeyEvent; | ||
| 7 | import android.widget.Toast; | ||
| 8 | |||
| 9 | import org.yuzu.yuzu_emu.YuzuApplication; | ||
| 10 | import org.yuzu.yuzu_emu.NativeLibrary; | ||
| 11 | import org.yuzu.yuzu_emu.R; | ||
| 12 | import org.yuzu.yuzu_emu.features.settings.model.Setting; | ||
| 13 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting; | ||
| 14 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile; | ||
| 15 | |||
| 16 | public final class InputBindingSetting extends SettingsItem { | ||
| 17 | private static final String INPUT_MAPPING_PREFIX = "InputMapping"; | ||
| 18 | |||
| 19 | public InputBindingSetting(String key, String section, int titleId, Setting setting) { | ||
| 20 | super(key, section, setting, titleId, 0); | ||
| 21 | } | ||
| 22 | |||
| 23 | public String getValue() { | ||
| 24 | if (getSetting() == null) { | ||
| 25 | return ""; | ||
| 26 | } | ||
| 27 | |||
| 28 | StringSetting setting = (StringSetting) getSetting(); | ||
| 29 | return setting.getValue(); | ||
| 30 | } | ||
| 31 | |||
| 32 | /** | ||
| 33 | * Returns true if this key is for the 3DS Circle Pad | ||
| 34 | */ | ||
| 35 | private boolean IsCirclePad() { | ||
| 36 | switch (getKey()) { | ||
| 37 | case SettingsFile.KEY_CIRCLEPAD_AXIS_HORIZONTAL: | ||
| 38 | case SettingsFile.KEY_CIRCLEPAD_AXIS_VERTICAL: | ||
| 39 | return true; | ||
| 40 | } | ||
| 41 | return false; | ||
| 42 | } | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Returns true if this key is for a horizontal axis for a 3DS analog stick or D-pad | ||
| 46 | */ | ||
| 47 | public boolean IsHorizontalOrientation() { | ||
| 48 | switch (getKey()) { | ||
| 49 | case SettingsFile.KEY_CIRCLEPAD_AXIS_HORIZONTAL: | ||
| 50 | case SettingsFile.KEY_CSTICK_AXIS_HORIZONTAL: | ||
| 51 | case SettingsFile.KEY_DPAD_AXIS_HORIZONTAL: | ||
| 52 | return true; | ||
| 53 | } | ||
| 54 | return false; | ||
| 55 | } | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Returns true if this key is for the 3DS C-Stick | ||
| 59 | */ | ||
| 60 | private boolean IsCStick() { | ||
| 61 | switch (getKey()) { | ||
| 62 | case SettingsFile.KEY_CSTICK_AXIS_HORIZONTAL: | ||
| 63 | case SettingsFile.KEY_CSTICK_AXIS_VERTICAL: | ||
| 64 | return true; | ||
| 65 | } | ||
| 66 | return false; | ||
| 67 | } | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Returns true if this key is for the 3DS D-Pad | ||
| 71 | */ | ||
| 72 | private boolean IsDPad() { | ||
| 73 | switch (getKey()) { | ||
| 74 | case SettingsFile.KEY_DPAD_AXIS_HORIZONTAL: | ||
| 75 | case SettingsFile.KEY_DPAD_AXIS_VERTICAL: | ||
| 76 | return true; | ||
| 77 | } | ||
| 78 | return false; | ||
| 79 | } | ||
| 80 | |||
| 81 | /** | ||
| 82 | * Returns true if this key is for the 3DS L/R or ZL/ZR buttons. Note, these are not real | ||
| 83 | * triggers on the 3DS, but we support them as such on a physical gamepad. | ||
| 84 | */ | ||
| 85 | public boolean IsTrigger() { | ||
| 86 | switch (getKey()) { | ||
| 87 | case SettingsFile.KEY_BUTTON_L: | ||
| 88 | case SettingsFile.KEY_BUTTON_R: | ||
| 89 | case SettingsFile.KEY_BUTTON_ZL: | ||
| 90 | case SettingsFile.KEY_BUTTON_ZR: | ||
| 91 | return true; | ||
| 92 | } | ||
| 93 | return false; | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Returns true if a gamepad axis can be used to map this key. | ||
| 98 | */ | ||
| 99 | public boolean IsAxisMappingSupported() { | ||
| 100 | return IsCirclePad() || IsCStick() || IsDPad() || IsTrigger(); | ||
| 101 | } | ||
| 102 | |||
| 103 | /** | ||
| 104 | * Returns true if a gamepad button can be used to map this key. | ||
| 105 | */ | ||
| 106 | private boolean IsButtonMappingSupported() { | ||
| 107 | return !IsAxisMappingSupported() || IsTrigger(); | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * Returns the yuzu button code for the settings key. | ||
| 112 | */ | ||
| 113 | private int getButtonCode() { | ||
| 114 | switch (getKey()) { | ||
| 115 | case SettingsFile.KEY_BUTTON_A: | ||
| 116 | return NativeLibrary.ButtonType.BUTTON_A; | ||
| 117 | case SettingsFile.KEY_BUTTON_B: | ||
| 118 | return NativeLibrary.ButtonType.BUTTON_B; | ||
| 119 | case SettingsFile.KEY_BUTTON_X: | ||
| 120 | return NativeLibrary.ButtonType.BUTTON_X; | ||
| 121 | case SettingsFile.KEY_BUTTON_Y: | ||
| 122 | return NativeLibrary.ButtonType.BUTTON_Y; | ||
| 123 | case SettingsFile.KEY_BUTTON_L: | ||
| 124 | return NativeLibrary.ButtonType.TRIGGER_L; | ||
| 125 | case SettingsFile.KEY_BUTTON_R: | ||
| 126 | return NativeLibrary.ButtonType.TRIGGER_R; | ||
| 127 | case SettingsFile.KEY_BUTTON_ZL: | ||
| 128 | return NativeLibrary.ButtonType.BUTTON_ZL; | ||
| 129 | case SettingsFile.KEY_BUTTON_ZR: | ||
| 130 | return NativeLibrary.ButtonType.BUTTON_ZR; | ||
| 131 | case SettingsFile.KEY_BUTTON_SELECT: | ||
| 132 | return NativeLibrary.ButtonType.BUTTON_SELECT; | ||
| 133 | case SettingsFile.KEY_BUTTON_START: | ||
| 134 | return NativeLibrary.ButtonType.BUTTON_START; | ||
| 135 | case SettingsFile.KEY_BUTTON_UP: | ||
| 136 | return NativeLibrary.ButtonType.DPAD_UP; | ||
| 137 | case SettingsFile.KEY_BUTTON_DOWN: | ||
| 138 | return NativeLibrary.ButtonType.DPAD_DOWN; | ||
| 139 | case SettingsFile.KEY_BUTTON_LEFT: | ||
| 140 | return NativeLibrary.ButtonType.DPAD_LEFT; | ||
| 141 | case SettingsFile.KEY_BUTTON_RIGHT: | ||
| 142 | return NativeLibrary.ButtonType.DPAD_RIGHT; | ||
| 143 | } | ||
| 144 | return -1; | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * Returns the settings key for the specified yuzu button code. | ||
| 149 | */ | ||
| 150 | private static String getButtonKey(int buttonCode) { | ||
| 151 | switch (buttonCode) { | ||
| 152 | case NativeLibrary.ButtonType.BUTTON_A: | ||
| 153 | return SettingsFile.KEY_BUTTON_A; | ||
| 154 | case NativeLibrary.ButtonType.BUTTON_B: | ||
| 155 | return SettingsFile.KEY_BUTTON_B; | ||
| 156 | case NativeLibrary.ButtonType.BUTTON_X: | ||
| 157 | return SettingsFile.KEY_BUTTON_X; | ||
| 158 | case NativeLibrary.ButtonType.BUTTON_Y: | ||
| 159 | return SettingsFile.KEY_BUTTON_Y; | ||
| 160 | case NativeLibrary.ButtonType.TRIGGER_L: | ||
| 161 | return SettingsFile.KEY_BUTTON_L; | ||
| 162 | case NativeLibrary.ButtonType.TRIGGER_R: | ||
| 163 | return SettingsFile.KEY_BUTTON_R; | ||
| 164 | case NativeLibrary.ButtonType.BUTTON_ZL: | ||
| 165 | return SettingsFile.KEY_BUTTON_ZL; | ||
| 166 | case NativeLibrary.ButtonType.BUTTON_ZR: | ||
| 167 | return SettingsFile.KEY_BUTTON_ZR; | ||
| 168 | case NativeLibrary.ButtonType.BUTTON_SELECT: | ||
| 169 | return SettingsFile.KEY_BUTTON_SELECT; | ||
| 170 | case NativeLibrary.ButtonType.BUTTON_START: | ||
| 171 | return SettingsFile.KEY_BUTTON_START; | ||
| 172 | case NativeLibrary.ButtonType.DPAD_UP: | ||
| 173 | return SettingsFile.KEY_BUTTON_UP; | ||
| 174 | case NativeLibrary.ButtonType.DPAD_DOWN: | ||
| 175 | return SettingsFile.KEY_BUTTON_DOWN; | ||
| 176 | case NativeLibrary.ButtonType.DPAD_LEFT: | ||
| 177 | return SettingsFile.KEY_BUTTON_LEFT; | ||
| 178 | case NativeLibrary.ButtonType.DPAD_RIGHT: | ||
| 179 | return SettingsFile.KEY_BUTTON_RIGHT; | ||
| 180 | } | ||
| 181 | return ""; | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * Returns the key used to lookup the reverse mapping for this key, which is used to cleanup old | ||
| 186 | * settings on re-mapping or clearing of a setting. | ||
| 187 | */ | ||
| 188 | private String getReverseKey() { | ||
| 189 | String reverseKey = INPUT_MAPPING_PREFIX + "_ReverseMapping_" + getKey(); | ||
| 190 | |||
| 191 | if (IsAxisMappingSupported() && !IsTrigger()) { | ||
| 192 | // Triggers are the only axis-supported mappings without orientation | ||
| 193 | reverseKey += "_" + (IsHorizontalOrientation() ? 0 : 1); | ||
| 194 | } | ||
| 195 | |||
| 196 | return reverseKey; | ||
| 197 | } | ||
| 198 | |||
| 199 | /** | ||
| 200 | * Removes the old mapping for this key from the settings, e.g. on user clearing the setting. | ||
| 201 | */ | ||
| 202 | public void removeOldMapping() { | ||
| 203 | // Get preferences editor | ||
| 204 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.getAppContext()); | ||
| 205 | SharedPreferences.Editor editor = preferences.edit(); | ||
| 206 | |||
| 207 | // Try remove all possible keys we wrote for this setting | ||
| 208 | String oldKey = preferences.getString(getReverseKey(), ""); | ||
| 209 | if (!oldKey.equals("")) { | ||
| 210 | editor.remove(getKey()); // Used for ui text | ||
| 211 | editor.remove(oldKey); // Used for button mapping | ||
| 212 | editor.remove(oldKey + "_GuestOrientation"); // Used for axis orientation | ||
| 213 | editor.remove(oldKey + "_GuestButton"); // Used for axis button | ||
| 214 | } | ||
| 215 | |||
| 216 | // Apply changes | ||
| 217 | editor.apply(); | ||
| 218 | } | ||
| 219 | |||
| 220 | /** | ||
| 221 | * Helper function to get the settings key for an gamepad button. | ||
| 222 | */ | ||
| 223 | public static String getInputButtonKey(int keyCode) { | ||
| 224 | return INPUT_MAPPING_PREFIX + "_Button_" + keyCode; | ||
| 225 | } | ||
| 226 | |||
| 227 | /** | ||
| 228 | * Helper function to get the settings key for an gamepad axis. | ||
| 229 | */ | ||
| 230 | public static String getInputAxisKey(int axis) { | ||
| 231 | return INPUT_MAPPING_PREFIX + "_HostAxis_" + axis; | ||
| 232 | } | ||
| 233 | |||
| 234 | /** | ||
| 235 | * Helper function to get the settings key for an gamepad axis button (stick or trigger). | ||
| 236 | */ | ||
| 237 | public static String getInputAxisButtonKey(int axis) { | ||
| 238 | return getInputAxisKey(axis) + "_GuestButton"; | ||
| 239 | } | ||
| 240 | |||
| 241 | /** | ||
| 242 | * Helper function to get the settings key for an gamepad axis orientation. | ||
| 243 | */ | ||
| 244 | public static String getInputAxisOrientationKey(int axis) { | ||
| 245 | return getInputAxisKey(axis) + "_GuestOrientation"; | ||
| 246 | } | ||
| 247 | |||
| 248 | /** | ||
| 249 | * Helper function to write a gamepad button mapping for the setting. | ||
| 250 | */ | ||
| 251 | private void WriteButtonMapping(String key) { | ||
| 252 | // Get preferences editor | ||
| 253 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.getAppContext()); | ||
| 254 | SharedPreferences.Editor editor = preferences.edit(); | ||
| 255 | |||
| 256 | // Remove mapping for another setting using this input | ||
| 257 | int oldButtonCode = preferences.getInt(key, -1); | ||
| 258 | if (oldButtonCode != -1) { | ||
| 259 | String oldKey = getButtonKey(oldButtonCode); | ||
| 260 | editor.remove(oldKey); // Only need to remove UI text setting, others will be overwritten | ||
| 261 | } | ||
| 262 | |||
| 263 | // Cleanup old mapping for this setting | ||
| 264 | removeOldMapping(); | ||
| 265 | |||
| 266 | // Write new mapping | ||
| 267 | editor.putInt(key, getButtonCode()); | ||
| 268 | |||
| 269 | // Write next reverse mapping for future cleanup | ||
| 270 | editor.putString(getReverseKey(), key); | ||
| 271 | |||
| 272 | // Apply changes | ||
| 273 | editor.apply(); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * Helper function to write a gamepad axis mapping for the setting. | ||
| 278 | */ | ||
| 279 | private void WriteAxisMapping(int axis, int value) { | ||
| 280 | // Get preferences editor | ||
| 281 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.getAppContext()); | ||
| 282 | SharedPreferences.Editor editor = preferences.edit(); | ||
| 283 | |||
| 284 | // Cleanup old mapping | ||
| 285 | removeOldMapping(); | ||
| 286 | |||
| 287 | // Write new mapping | ||
| 288 | editor.putInt(getInputAxisOrientationKey(axis), IsHorizontalOrientation() ? 0 : 1); | ||
| 289 | editor.putInt(getInputAxisButtonKey(axis), value); | ||
| 290 | |||
| 291 | // Write next reverse mapping for future cleanup | ||
| 292 | editor.putString(getReverseKey(), getInputAxisKey(axis)); | ||
| 293 | |||
| 294 | // Apply changes | ||
| 295 | editor.apply(); | ||
| 296 | } | ||
| 297 | |||
| 298 | /** | ||
| 299 | * Saves the provided key input setting as an Android preference. | ||
| 300 | * | ||
| 301 | * @param keyEvent KeyEvent of this key press. | ||
| 302 | */ | ||
| 303 | public void onKeyInput(KeyEvent keyEvent) { | ||
| 304 | if (!IsButtonMappingSupported()) { | ||
| 305 | Toast.makeText(YuzuApplication.getAppContext(), R.string.input_message_analog_only, Toast.LENGTH_LONG).show(); | ||
| 306 | return; | ||
| 307 | } | ||
| 308 | |||
| 309 | InputDevice device = keyEvent.getDevice(); | ||
| 310 | |||
| 311 | WriteButtonMapping(getInputButtonKey(keyEvent.getKeyCode())); | ||
| 312 | |||
| 313 | String uiString = device.getName() + ": Button " + keyEvent.getKeyCode(); | ||
| 314 | setUiString(uiString); | ||
| 315 | } | ||
| 316 | |||
| 317 | /** | ||
| 318 | * Saves the provided motion input setting as an Android preference. | ||
| 319 | * | ||
| 320 | * @param device InputDevice from which the input event originated. | ||
| 321 | * @param motionRange MotionRange of the movement | ||
| 322 | * @param axisDir Either '-' or '+' (currently unused) | ||
| 323 | */ | ||
| 324 | public void onMotionInput(InputDevice device, InputDevice.MotionRange motionRange, | ||
| 325 | char axisDir) { | ||
| 326 | if (!IsAxisMappingSupported()) { | ||
| 327 | Toast.makeText(YuzuApplication.getAppContext(), R.string.input_message_button_only, Toast.LENGTH_LONG).show(); | ||
| 328 | return; | ||
| 329 | } | ||
| 330 | |||
| 331 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.getAppContext()); | ||
| 332 | SharedPreferences.Editor editor = preferences.edit(); | ||
| 333 | |||
| 334 | int button; | ||
| 335 | if (IsCirclePad()) { | ||
| 336 | button = NativeLibrary.ButtonType.STICK_LEFT; | ||
| 337 | } else if (IsCStick()) { | ||
| 338 | button = NativeLibrary.ButtonType.STICK_C; | ||
| 339 | } else if (IsDPad()) { | ||
| 340 | button = NativeLibrary.ButtonType.DPAD; | ||
| 341 | } else { | ||
| 342 | button = getButtonCode(); | ||
| 343 | } | ||
| 344 | |||
| 345 | WriteAxisMapping(motionRange.getAxis(), button); | ||
| 346 | |||
| 347 | String uiString = device.getName() + ": Axis " + motionRange.getAxis(); | ||
| 348 | setUiString(uiString); | ||
| 349 | |||
| 350 | editor.apply(); | ||
| 351 | } | ||
| 352 | |||
| 353 | /** | ||
| 354 | * Sets the string to use in the configuration UI for the gamepad input. | ||
| 355 | */ | ||
| 356 | private StringSetting setUiString(String ui) { | ||
| 357 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.getAppContext()); | ||
| 358 | SharedPreferences.Editor editor = preferences.edit(); | ||
| 359 | |||
| 360 | if (getSetting() == null) { | ||
| 361 | StringSetting setting = new StringSetting(getKey(), getSection(), ""); | ||
| 362 | setSetting(setting); | ||
| 363 | |||
| 364 | editor.putString(setting.getKey(), ui); | ||
| 365 | editor.apply(); | ||
| 366 | |||
| 367 | return setting; | ||
| 368 | } else { | ||
| 369 | StringSetting setting = (StringSetting) getSetting(); | ||
| 370 | |||
| 371 | editor.putString(setting.getKey(), ui); | ||
| 372 | editor.apply(); | ||
| 373 | |||
| 374 | return null; | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 378 | @Override | ||
| 379 | public int getType() { | ||
| 380 | return TYPE_INPUT_BINDING; | ||
| 381 | } | ||
| 382 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/PremiumHeader.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/PremiumHeader.java deleted file mode 100644 index 9bf95ce51..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/PremiumHeader.java +++ /dev/null | |||
| @@ -1,12 +0,0 @@ | |||
| 1 | package org.yuzu.yuzu_emu.features.settings.model.view; | ||
| 2 | |||
| 3 | public final class PremiumHeader extends SettingsItem { | ||
| 4 | public PremiumHeader() { | ||
| 5 | super(null, null, null, 0, 0); | ||
| 6 | } | ||
| 7 | |||
| 8 | @Override | ||
| 9 | public int getType() { | ||
| 10 | return SettingsItem.TYPE_PREMIUM; | ||
| 11 | } | ||
| 12 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/PremiumSingleChoiceSetting.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/PremiumSingleChoiceSetting.java deleted file mode 100644 index 0c4570c8d..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/PremiumSingleChoiceSetting.java +++ /dev/null | |||
| @@ -1,59 +0,0 @@ | |||
| 1 | package org.yuzu.yuzu_emu.features.settings.model.view; | ||
| 2 | |||
| 3 | import android.content.SharedPreferences; | ||
| 4 | import android.preference.PreferenceManager; | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.YuzuApplication; | ||
| 7 | import org.yuzu.yuzu_emu.R; | ||
| 8 | import org.yuzu.yuzu_emu.features.settings.model.Setting; | ||
| 9 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsFragmentView; | ||
| 10 | |||
| 11 | public final class PremiumSingleChoiceSetting extends SettingsItem { | ||
| 12 | private int mDefaultValue; | ||
| 13 | |||
| 14 | private int mChoicesId; | ||
| 15 | private int mValuesId; | ||
| 16 | private SettingsFragmentView mView; | ||
| 17 | |||
| 18 | private static SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.getAppContext()); | ||
| 19 | |||
| 20 | public PremiumSingleChoiceSetting(String key, String section, int titleId, int descriptionId, | ||
| 21 | int choicesId, int valuesId, int defaultValue, Setting setting, SettingsFragmentView view) { | ||
| 22 | super(key, section, setting, titleId, descriptionId); | ||
| 23 | mValuesId = valuesId; | ||
| 24 | mChoicesId = choicesId; | ||
| 25 | mDefaultValue = defaultValue; | ||
| 26 | mView = view; | ||
| 27 | } | ||
| 28 | |||
| 29 | public int getChoicesId() { | ||
| 30 | return mChoicesId; | ||
| 31 | } | ||
| 32 | |||
| 33 | public int getValuesId() { | ||
| 34 | return mValuesId; | ||
| 35 | } | ||
| 36 | |||
| 37 | public int getSelectedValue() { | ||
| 38 | return mPreferences.getInt(getKey(), mDefaultValue); | ||
| 39 | } | ||
| 40 | |||
| 41 | /** | ||
| 42 | * Write a value to the backing int. If that int was previously null, | ||
| 43 | * initializes a new one and returns it, so it can be added to the Hashmap. | ||
| 44 | * | ||
| 45 | * @param selection New value of the int. | ||
| 46 | * @return null if overwritten successfully otherwise; a newly created IntSetting. | ||
| 47 | */ | ||
| 48 | public void setSelectedValue(int selection) { | ||
| 49 | final SharedPreferences.Editor editor = mPreferences.edit(); | ||
| 50 | editor.putInt(getKey(), selection); | ||
| 51 | editor.apply(); | ||
| 52 | mView.showToastMessage(YuzuApplication.getAppContext().getString(R.string.design_updated), false); | ||
| 53 | } | ||
| 54 | |||
| 55 | @Override | ||
| 56 | public int getType() { | ||
| 57 | return TYPE_SINGLE_CHOICE; | ||
| 58 | } | ||
| 59 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.java index db7fb791a..e2ba9014f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.java | |||
| @@ -17,10 +17,8 @@ public abstract class SettingsItem { | |||
| 17 | public static final int TYPE_SINGLE_CHOICE = 2; | 17 | public static final int TYPE_SINGLE_CHOICE = 2; |
| 18 | public static final int TYPE_SLIDER = 3; | 18 | public static final int TYPE_SLIDER = 3; |
| 19 | public static final int TYPE_SUBMENU = 4; | 19 | public static final int TYPE_SUBMENU = 4; |
| 20 | public static final int TYPE_INPUT_BINDING = 5; | 20 | public static final int TYPE_STRING_SINGLE_CHOICE = 5; |
| 21 | public static final int TYPE_STRING_SINGLE_CHOICE = 6; | 21 | public static final int TYPE_DATETIME_SETTING = 6; |
| 22 | public static final int TYPE_DATETIME_SETTING = 7; | ||
| 23 | public static final int TYPE_PREMIUM = 8; | ||
| 24 | 22 | ||
| 25 | private String mKey; | 23 | private String mKey; |
| 26 | private String mSection; | 24 | private String mSection; |
| @@ -48,7 +46,6 @@ public abstract class SettingsItem { | |||
| 48 | mSetting = setting; | 46 | mSetting = setting; |
| 49 | mNameId = nameId; | 47 | mNameId = nameId; |
| 50 | mDescriptionId = descriptionId; | 48 | mDescriptionId = descriptionId; |
| 51 | mIsPremium = (section == Settings.SECTION_PREMIUM); | ||
| 52 | } | 49 | } |
| 53 | 50 | ||
| 54 | /** | 51 | /** |
| @@ -93,10 +90,6 @@ public abstract class SettingsItem { | |||
| 93 | return mDescriptionId; | 90 | return mDescriptionId; |
| 94 | } | 91 | } |
| 95 | 92 | ||
| 96 | public boolean isPremium() { | ||
| 97 | return mIsPremium; | ||
| 98 | } | ||
| 99 | |||
| 100 | /** | 93 | /** |
| 101 | * Used by {@link SettingsAdapter}'s onCreateViewHolder() | 94 | * Used by {@link SettingsAdapter}'s onCreateViewHolder() |
| 102 | * method to determine which type of ViewHolder should be created. | 95 | * method to determine which type of ViewHolder should be created. |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.java index 1102d6af1..47e73bfe2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.java | |||
| @@ -14,14 +14,11 @@ import androidx.appcompat.app.AlertDialog; | |||
| 14 | import androidx.recyclerview.widget.RecyclerView; | 14 | import androidx.recyclerview.widget.RecyclerView; |
| 15 | 15 | ||
| 16 | import org.yuzu.yuzu_emu.R; | 16 | import org.yuzu.yuzu_emu.R; |
| 17 | import org.yuzu.yuzu_emu.dialogs.MotionAlertDialog; | ||
| 18 | import org.yuzu.yuzu_emu.features.settings.model.FloatSetting; | 17 | import org.yuzu.yuzu_emu.features.settings.model.FloatSetting; |
| 19 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting; | 18 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting; |
| 20 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting; | 19 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting; |
| 21 | import org.yuzu.yuzu_emu.features.settings.model.view.CheckBoxSetting; | 20 | import org.yuzu.yuzu_emu.features.settings.model.view.CheckBoxSetting; |
| 22 | import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting; | 21 | import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting; |
| 23 | import org.yuzu.yuzu_emu.features.settings.model.view.InputBindingSetting; | ||
| 24 | import org.yuzu.yuzu_emu.features.settings.model.view.PremiumSingleChoiceSetting; | ||
| 25 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem; | 22 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem; |
| 26 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting; | 23 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting; |
| 27 | import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting; | 24 | import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting; |
| @@ -30,13 +27,10 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting; | |||
| 30 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.CheckBoxSettingViewHolder; | 27 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.CheckBoxSettingViewHolder; |
| 31 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.DateTimeViewHolder; | 28 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.DateTimeViewHolder; |
| 32 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.HeaderViewHolder; | 29 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.HeaderViewHolder; |
| 33 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.InputBindingSettingViewHolder; | ||
| 34 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.PremiumViewHolder; | ||
| 35 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SettingViewHolder; | 30 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SettingViewHolder; |
| 36 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SingleChoiceViewHolder; | 31 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SingleChoiceViewHolder; |
| 37 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SliderViewHolder; | 32 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SliderViewHolder; |
| 38 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SubmenuViewHolder; | 33 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SubmenuViewHolder; |
| 39 | import org.yuzu.yuzu_emu.ui.main.MainActivity; | ||
| 40 | import org.yuzu.yuzu_emu.utils.Log; | 34 | import org.yuzu.yuzu_emu.utils.Log; |
| 41 | 35 | ||
| 42 | import java.util.ArrayList; | 36 | import java.util.ArrayList; |
| @@ -87,18 +81,10 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde | |||
| 87 | view = inflater.inflate(R.layout.list_item_setting, parent, false); | 81 | view = inflater.inflate(R.layout.list_item_setting, parent, false); |
| 88 | return new SubmenuViewHolder(view, this); | 82 | return new SubmenuViewHolder(view, this); |
| 89 | 83 | ||
| 90 | case SettingsItem.TYPE_INPUT_BINDING: | ||
| 91 | view = inflater.inflate(R.layout.list_item_setting, parent, false); | ||
| 92 | return new InputBindingSettingViewHolder(view, this, mContext); | ||
| 93 | |||
| 94 | case SettingsItem.TYPE_DATETIME_SETTING: | 84 | case SettingsItem.TYPE_DATETIME_SETTING: |
| 95 | view = inflater.inflate(R.layout.list_item_setting, parent, false); | 85 | view = inflater.inflate(R.layout.list_item_setting, parent, false); |
| 96 | return new DateTimeViewHolder(view, this); | 86 | return new DateTimeViewHolder(view, this); |
| 97 | 87 | ||
| 98 | case SettingsItem.TYPE_PREMIUM: | ||
| 99 | view = inflater.inflate(R.layout.premium_item_setting, parent, false); | ||
| 100 | return new PremiumViewHolder(view, this, mView); | ||
| 101 | |||
| 102 | default: | 88 | default: |
| 103 | Log.error("[SettingsAdapter] Invalid view type: " + viewType); | 89 | Log.error("[SettingsAdapter] Invalid view type: " + viewType); |
| 104 | return null; | 90 | return null; |
| @@ -144,19 +130,6 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde | |||
| 144 | mView.onSettingChanged(); | 130 | mView.onSettingChanged(); |
| 145 | } | 131 | } |
| 146 | 132 | ||
| 147 | public void onSingleChoiceClick(PremiumSingleChoiceSetting item) { | ||
| 148 | mClickedItem = item; | ||
| 149 | |||
| 150 | int value = getSelectionForSingleChoiceValue(item); | ||
| 151 | |||
| 152 | AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity()); | ||
| 153 | |||
| 154 | builder.setTitle(item.getNameId()); | ||
| 155 | builder.setSingleChoiceItems(item.getChoicesId(), value, this); | ||
| 156 | |||
| 157 | mDialog = builder.show(); | ||
| 158 | } | ||
| 159 | |||
| 160 | public void onSingleChoiceClick(SingleChoiceSetting item) { | 133 | public void onSingleChoiceClick(SingleChoiceSetting item) { |
| 161 | mClickedItem = item; | 134 | mClickedItem = item; |
| 162 | 135 | ||
| @@ -172,28 +145,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde | |||
| 172 | 145 | ||
| 173 | public void onSingleChoiceClick(SingleChoiceSetting item, int position) { | 146 | public void onSingleChoiceClick(SingleChoiceSetting item, int position) { |
| 174 | mClickedPosition = position; | 147 | mClickedPosition = position; |
| 175 | 148 | onSingleChoiceClick(item); | |
| 176 | if (!item.isPremium() || MainActivity.isPremiumActive()) { | ||
| 177 | // Setting is either not Premium, or the user has Premium | ||
| 178 | onSingleChoiceClick(item); | ||
| 179 | return; | ||
| 180 | } | ||
| 181 | |||
| 182 | // User needs Premium, invoke the billing flow | ||
| 183 | MainActivity.invokePremiumBilling(() -> onSingleChoiceClick(item)); | ||
| 184 | } | ||
| 185 | |||
| 186 | public void onSingleChoiceClick(PremiumSingleChoiceSetting item, int position) { | ||
| 187 | mClickedPosition = position; | ||
| 188 | |||
| 189 | if (!item.isPremium() || MainActivity.isPremiumActive()) { | ||
| 190 | // Setting is either not Premium, or the user has Premium | ||
| 191 | onSingleChoiceClick(item); | ||
| 192 | return; | ||
| 193 | } | ||
| 194 | |||
| 195 | // User needs Premium, invoke the billing flow | ||
| 196 | MainActivity.invokePremiumBilling(() -> onSingleChoiceClick(item)); | ||
| 197 | } | 149 | } |
| 198 | 150 | ||
| 199 | public void onStringSingleChoiceClick(StringSingleChoiceSetting item) { | 151 | public void onStringSingleChoiceClick(StringSingleChoiceSetting item) { |
| @@ -209,15 +161,7 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde | |||
| 209 | 161 | ||
| 210 | public void onStringSingleChoiceClick(StringSingleChoiceSetting item, int position) { | 162 | public void onStringSingleChoiceClick(StringSingleChoiceSetting item, int position) { |
| 211 | mClickedPosition = position; | 163 | mClickedPosition = position; |
| 212 | 164 | onStringSingleChoiceClick(item); | |
| 213 | if (!item.isPremium() || MainActivity.isPremiumActive()) { | ||
| 214 | // Setting is either not Premium, or the user has Premium | ||
| 215 | onStringSingleChoiceClick(item); | ||
| 216 | return; | ||
| 217 | } | ||
| 218 | |||
| 219 | // User needs Premium, invoke the billing flow | ||
| 220 | MainActivity.invokePremiumBilling(() -> onStringSingleChoiceClick(item)); | ||
| 221 | } | 165 | } |
| 222 | 166 | ||
| 223 | DialogInterface.OnClickListener defaultCancelListener = (dialog, which) -> closeDialog(); | 167 | DialogInterface.OnClickListener defaultCancelListener = (dialog, which) -> closeDialog(); |
| @@ -309,37 +253,6 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde | |||
| 309 | mView.loadSubMenu(item.getMenuKey()); | 253 | mView.loadSubMenu(item.getMenuKey()); |
| 310 | } | 254 | } |
| 311 | 255 | ||
| 312 | public void onInputBindingClick(final InputBindingSetting item, final int position) { | ||
| 313 | final MotionAlertDialog dialog = new MotionAlertDialog(mContext, item); | ||
| 314 | dialog.setTitle(R.string.input_binding); | ||
| 315 | |||
| 316 | int messageResId = R.string.input_binding_description; | ||
| 317 | if (item.IsAxisMappingSupported() && !item.IsTrigger()) { | ||
| 318 | // Use specialized message for axis left/right or up/down | ||
| 319 | if (item.IsHorizontalOrientation()) { | ||
| 320 | messageResId = R.string.input_binding_description_horizontal_axis; | ||
| 321 | } else { | ||
| 322 | messageResId = R.string.input_binding_description_vertical_axis; | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | dialog.setMessage(String.format(mContext.getString(messageResId), mContext.getString(item.getNameId()))); | ||
| 327 | dialog.setButton(AlertDialog.BUTTON_NEGATIVE, mContext.getString(android.R.string.cancel), this); | ||
| 328 | dialog.setButton(AlertDialog.BUTTON_NEUTRAL, mContext.getString(R.string.clear), (dialogInterface, i) -> | ||
| 329 | item.removeOldMapping()); | ||
| 330 | dialog.setOnDismissListener(dialog1 -> | ||
| 331 | { | ||
| 332 | StringSetting setting = new StringSetting(item.getKey(), item.getSection(), item.getValue()); | ||
| 333 | notifyItemChanged(position); | ||
| 334 | |||
| 335 | mView.putSetting(setting); | ||
| 336 | |||
| 337 | mView.onSettingChanged(); | ||
| 338 | }); | ||
| 339 | dialog.setCanceledOnTouchOutside(false); | ||
| 340 | dialog.show(); | ||
| 341 | } | ||
| 342 | |||
| 343 | @Override | 256 | @Override |
| 344 | public void onClick(DialogInterface dialog, int which) { | 257 | public void onClick(DialogInterface dialog, int which) { |
| 345 | if (mClickedItem instanceof SingleChoiceSetting) { | 258 | if (mClickedItem instanceof SingleChoiceSetting) { |
| @@ -357,10 +270,6 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde | |||
| 357 | } | 270 | } |
| 358 | 271 | ||
| 359 | closeDialog(); | 272 | closeDialog(); |
| 360 | } else if (mClickedItem instanceof PremiumSingleChoiceSetting) { | ||
| 361 | PremiumSingleChoiceSetting scSetting = (PremiumSingleChoiceSetting) mClickedItem; | ||
| 362 | scSetting.setSelectedValue(getValueForSingleChoiceSelection(scSetting, which)); | ||
| 363 | closeDialog(); | ||
| 364 | } else if (mClickedItem instanceof StringSingleChoiceSetting) { | 273 | } else if (mClickedItem instanceof StringSingleChoiceSetting) { |
| 365 | StringSingleChoiceSetting scSetting = (StringSingleChoiceSetting) mClickedItem; | 274 | StringSingleChoiceSetting scSetting = (StringSingleChoiceSetting) mClickedItem; |
| 366 | String value = scSetting.getValueAt(which); | 275 | String value = scSetting.getValueAt(which); |
| @@ -436,17 +345,6 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde | |||
| 436 | } | 345 | } |
| 437 | } | 346 | } |
| 438 | 347 | ||
| 439 | private int getValueForSingleChoiceSelection(PremiumSingleChoiceSetting item, int which) { | ||
| 440 | int valuesId = item.getValuesId(); | ||
| 441 | |||
| 442 | if (valuesId > 0) { | ||
| 443 | int[] valuesArray = mContext.getResources().getIntArray(valuesId); | ||
| 444 | return valuesArray[which]; | ||
| 445 | } else { | ||
| 446 | return which; | ||
| 447 | } | ||
| 448 | } | ||
| 449 | |||
| 450 | private int getSelectionForSingleChoiceValue(SingleChoiceSetting item) { | 348 | private int getSelectionForSingleChoiceValue(SingleChoiceSetting item) { |
| 451 | int value = item.getSelectedValue(); | 349 | int value = item.getSelectedValue(); |
| 452 | int valuesId = item.getValuesId(); | 350 | int valuesId = item.getValuesId(); |
| @@ -465,23 +363,4 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde | |||
| 465 | 363 | ||
| 466 | return -1; | 364 | return -1; |
| 467 | } | 365 | } |
| 468 | |||
| 469 | private int getSelectionForSingleChoiceValue(PremiumSingleChoiceSetting item) { | ||
| 470 | int value = item.getSelectedValue(); | ||
| 471 | int valuesId = item.getValuesId(); | ||
| 472 | |||
| 473 | if (valuesId > 0) { | ||
| 474 | int[] valuesArray = mContext.getResources().getIntArray(valuesId); | ||
| 475 | for (int index = 0; index < valuesArray.length; index++) { | ||
| 476 | int current = valuesArray[index]; | ||
| 477 | if (current == value) { | ||
| 478 | return index; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | } else { | ||
| 482 | return value; | ||
| 483 | } | ||
| 484 | |||
| 485 | return -1; | ||
| 486 | } | ||
| 487 | } | 366 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.java index 27f0adf29..c84467c16 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.java | |||
| @@ -1,10 +1,5 @@ | |||
| 1 | package org.yuzu.yuzu_emu.features.settings.ui; | 1 | package org.yuzu.yuzu_emu.features.settings.ui; |
| 2 | 2 | ||
| 3 | import android.app.Activity; | ||
| 4 | import android.content.Context; | ||
| 5 | import android.hardware.camera2.CameraAccessException; | ||
| 6 | import android.hardware.camera2.CameraCharacteristics; | ||
| 7 | import android.hardware.camera2.CameraManager; | ||
| 8 | import android.text.TextUtils; | 3 | import android.text.TextUtils; |
| 9 | 4 | ||
| 10 | import org.yuzu.yuzu_emu.R; | 5 | import org.yuzu.yuzu_emu.R; |
| @@ -15,20 +10,13 @@ import org.yuzu.yuzu_emu.features.settings.model.StringSetting; | |||
| 15 | import org.yuzu.yuzu_emu.features.settings.model.view.CheckBoxSetting; | 10 | import org.yuzu.yuzu_emu.features.settings.model.view.CheckBoxSetting; |
| 16 | import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting; | 11 | import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting; |
| 17 | import org.yuzu.yuzu_emu.features.settings.model.view.HeaderSetting; | 12 | import org.yuzu.yuzu_emu.features.settings.model.view.HeaderSetting; |
| 18 | import org.yuzu.yuzu_emu.features.settings.model.view.InputBindingSetting; | ||
| 19 | import org.yuzu.yuzu_emu.features.settings.model.view.PremiumHeader; | ||
| 20 | import org.yuzu.yuzu_emu.features.settings.model.view.PremiumSingleChoiceSetting; | ||
| 21 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem; | 13 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem; |
| 22 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting; | 14 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting; |
| 23 | import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting; | 15 | import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting; |
| 24 | import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting; | ||
| 25 | import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting; | 16 | import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting; |
| 26 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile; | 17 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile; |
| 27 | import org.yuzu.yuzu_emu.utils.Log; | ||
| 28 | 18 | ||
| 29 | import java.util.ArrayList; | 19 | import java.util.ArrayList; |
| 30 | import java.util.Arrays; | ||
| 31 | import java.util.Objects; | ||
| 32 | 20 | ||
| 33 | public final class SettingsFragmentPresenter { | 21 | public final class SettingsFragmentPresenter { |
| 34 | private SettingsFragmentView mView; | 22 | private SettingsFragmentView mView; |
| @@ -106,27 +94,18 @@ public final class SettingsFragmentPresenter { | |||
| 106 | case SettingsFile.FILE_NAME_CONFIG: | 94 | case SettingsFile.FILE_NAME_CONFIG: |
| 107 | addConfigSettings(sl); | 95 | addConfigSettings(sl); |
| 108 | break; | 96 | break; |
| 109 | case Settings.SECTION_PREMIUM: | 97 | case Settings.SECTION_GENERAL: |
| 110 | addPremiumSettings(sl); | ||
| 111 | break; | ||
| 112 | case Settings.SECTION_CORE: | ||
| 113 | addGeneralSettings(sl); | 98 | addGeneralSettings(sl); |
| 114 | break; | 99 | break; |
| 115 | case Settings.SECTION_SYSTEM: | 100 | case Settings.SECTION_SYSTEM: |
| 116 | addSystemSettings(sl); | 101 | addSystemSettings(sl); |
| 117 | break; | 102 | break; |
| 118 | case Settings.SECTION_CONTROLS: | ||
| 119 | addInputSettings(sl); | ||
| 120 | break; | ||
| 121 | case Settings.SECTION_RENDERER: | 103 | case Settings.SECTION_RENDERER: |
| 122 | addGraphicsSettings(sl); | 104 | addGraphicsSettings(sl); |
| 123 | break; | 105 | break; |
| 124 | case Settings.SECTION_AUDIO: | 106 | case Settings.SECTION_AUDIO: |
| 125 | addAudioSettings(sl); | 107 | addAudioSettings(sl); |
| 126 | break; | 108 | break; |
| 127 | case Settings.SECTION_DEBUG: | ||
| 128 | addDebugSettings(sl); | ||
| 129 | break; | ||
| 130 | default: | 109 | default: |
| 131 | mView.showToastMessage("Unimplemented menu", false); | 110 | mView.showToastMessage("Unimplemented menu", false); |
| 132 | return; | 111 | return; |
| @@ -139,184 +118,61 @@ public final class SettingsFragmentPresenter { | |||
| 139 | private void addConfigSettings(ArrayList<SettingsItem> sl) { | 118 | private void addConfigSettings(ArrayList<SettingsItem> sl) { |
| 140 | mView.getActivity().setTitle(R.string.preferences_settings); | 119 | mView.getActivity().setTitle(R.string.preferences_settings); |
| 141 | 120 | ||
| 142 | sl.add(new SubmenuSetting(null, null, R.string.preferences_premium, 0, Settings.SECTION_PREMIUM)); | 121 | sl.add(new SubmenuSetting(null, null, R.string.preferences_general, 0, Settings.SECTION_GENERAL)); |
| 143 | sl.add(new SubmenuSetting(null, null, R.string.preferences_general, 0, Settings.SECTION_CORE)); | ||
| 144 | sl.add(new SubmenuSetting(null, null, R.string.preferences_system, 0, Settings.SECTION_SYSTEM)); | 122 | sl.add(new SubmenuSetting(null, null, R.string.preferences_system, 0, Settings.SECTION_SYSTEM)); |
| 145 | sl.add(new SubmenuSetting(null, null, R.string.preferences_controls, 0, Settings.SECTION_CONTROLS)); | ||
| 146 | sl.add(new SubmenuSetting(null, null, R.string.preferences_graphics, 0, Settings.SECTION_RENDERER)); | 123 | sl.add(new SubmenuSetting(null, null, R.string.preferences_graphics, 0, Settings.SECTION_RENDERER)); |
| 147 | sl.add(new SubmenuSetting(null, null, R.string.preferences_audio, 0, Settings.SECTION_AUDIO)); | 124 | sl.add(new SubmenuSetting(null, null, R.string.preferences_audio, 0, Settings.SECTION_AUDIO)); |
| 148 | sl.add(new SubmenuSetting(null, null, R.string.preferences_debug, 0, Settings.SECTION_DEBUG)); | ||
| 149 | } | ||
| 150 | |||
| 151 | private void addPremiumSettings(ArrayList<SettingsItem> sl) { | ||
| 152 | mView.getActivity().setTitle(R.string.preferences_premium); | ||
| 153 | |||
| 154 | SettingSection premiumSection = mSettings.getSection(Settings.SECTION_PREMIUM); | ||
| 155 | Setting design = premiumSection.getSetting(SettingsFile.KEY_DESIGN); | ||
| 156 | |||
| 157 | sl.add(new PremiumHeader()); | ||
| 158 | |||
| 159 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { | ||
| 160 | sl.add(new PremiumSingleChoiceSetting(SettingsFile.KEY_DESIGN, Settings.SECTION_PREMIUM, R.string.design, 0, R.array.designNames, R.array.designValues, 0, design, mView)); | ||
| 161 | } else { | ||
| 162 | // Pre-Android 10 does not support System Default | ||
| 163 | sl.add(new PremiumSingleChoiceSetting(SettingsFile.KEY_DESIGN, Settings.SECTION_PREMIUM, R.string.design, 0, R.array.designNamesOld, R.array.designValuesOld, 0, design, mView)); | ||
| 164 | } | ||
| 165 | |||
| 166 | //Setting textureFilterName = premiumSection.getSetting(SettingsFile.KEY_TEXTURE_FILTER_NAME); | ||
| 167 | //sl.add(new StringSingleChoiceSetting(SettingsFile.KEY_TEXTURE_FILTER_NAME, Settings.SECTION_PREMIUM, R.string.texture_filter_name, R.string.texture_filter_description, textureFilterNames, textureFilterNames, "none", textureFilterName)); | ||
| 168 | } | 125 | } |
| 169 | 126 | ||
| 170 | private void addGeneralSettings(ArrayList<SettingsItem> sl) { | 127 | private void addGeneralSettings(ArrayList<SettingsItem> sl) { |
| 171 | mView.getActivity().setTitle(R.string.preferences_general); | 128 | mView.getActivity().setTitle(R.string.preferences_general); |
| 172 | 129 | ||
| 173 | SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER); | 130 | SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER); |
| 174 | Setting frameLimitEnable = rendererSection.getSetting(SettingsFile.KEY_FRAME_LIMIT_ENABLED); | 131 | Setting frameLimitEnable = rendererSection.getSetting(SettingsFile.KEY_RENDERER_USE_SPEED_LIMIT); |
| 175 | Setting frameLimitValue = rendererSection.getSetting(SettingsFile.KEY_FRAME_LIMIT); | 132 | Setting frameLimitValue = rendererSection.getSetting(SettingsFile.KEY_RENDERER_SPEED_LIMIT); |
| 133 | |||
| 134 | sl.add(new CheckBoxSetting(SettingsFile.KEY_RENDERER_USE_SPEED_LIMIT, Settings.SECTION_RENDERER, R.string.frame_limit_enable, R.string.frame_limit_enable_description, true, frameLimitEnable)); | ||
| 135 | sl.add(new SliderSetting(SettingsFile.KEY_RENDERER_SPEED_LIMIT, Settings.SECTION_RENDERER, R.string.frame_limit_slider, R.string.frame_limit_slider_description, 1, 200, "%", 100, frameLimitValue)); | ||
| 176 | 136 | ||
| 177 | sl.add(new CheckBoxSetting(SettingsFile.KEY_FRAME_LIMIT_ENABLED, Settings.SECTION_RENDERER, R.string.frame_limit_enable, R.string.frame_limit_enable_description, true, frameLimitEnable)); | 137 | SettingSection cpuSection = mSettings.getSection(Settings.SECTION_CPU); |
| 178 | sl.add(new SliderSetting(SettingsFile.KEY_FRAME_LIMIT, Settings.SECTION_RENDERER, R.string.frame_limit_slider, R.string.frame_limit_slider_description, 1, 200, "%", 100, frameLimitValue)); | 138 | Setting cpuAccuracy = cpuSection.getSetting(SettingsFile.KEY_CPU_ACCURACY); |
| 139 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_CPU_ACCURACY, Settings.SECTION_CPU, R.string.cpu_accuracy, 0, R.array.cpuAccuracyNames, R.array.cpuAccuracyValues, 0, cpuAccuracy)); | ||
| 179 | } | 140 | } |
| 180 | 141 | ||
| 181 | private void addSystemSettings(ArrayList<SettingsItem> sl) { | 142 | private void addSystemSettings(ArrayList<SettingsItem> sl) { |
| 182 | mView.getActivity().setTitle(R.string.preferences_system); | 143 | mView.getActivity().setTitle(R.string.preferences_system); |
| 183 | 144 | ||
| 184 | SettingSection systemSection = mSettings.getSection(Settings.SECTION_SYSTEM); | 145 | SettingSection systemSection = mSettings.getSection(Settings.SECTION_SYSTEM); |
| 185 | Setting region = systemSection.getSetting(SettingsFile.KEY_REGION_VALUE); | 146 | Setting dockedMode = systemSection.getSetting(SettingsFile.KEY_USE_DOCKED_MODE); |
| 186 | Setting language = systemSection.getSetting(SettingsFile.KEY_LANGUAGE); | 147 | Setting region = systemSection.getSetting(SettingsFile.KEY_REGION_INDEX); |
| 187 | Setting systemClock = systemSection.getSetting(SettingsFile.KEY_INIT_CLOCK); | 148 | Setting language = systemSection.getSetting(SettingsFile.KEY_LANGUAGE_INDEX); |
| 188 | Setting dateTime = systemSection.getSetting(SettingsFile.KEY_INIT_TIME); | ||
| 189 | |||
| 190 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_REGION_VALUE, Settings.SECTION_SYSTEM, R.string.emulated_region, 0, R.array.regionNames, R.array.regionValues, -1, region)); | ||
| 191 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_LANGUAGE, Settings.SECTION_SYSTEM, R.string.emulated_language, 0, R.array.languageNames, R.array.languageValues, 1, language)); | ||
| 192 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_INIT_CLOCK, Settings.SECTION_SYSTEM, R.string.init_clock, R.string.init_clock_description, R.array.systemClockNames, R.array.systemClockValues, 0, systemClock)); | ||
| 193 | sl.add(new DateTimeSetting(SettingsFile.KEY_INIT_TIME, Settings.SECTION_SYSTEM, R.string.init_time, R.string.init_time_description, "2000-01-01 00:00:01", dateTime)); | ||
| 194 | } | ||
| 195 | 149 | ||
| 196 | private void addInputSettings(ArrayList<SettingsItem> sl) { | 150 | sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_DOCKED_MODE, Settings.SECTION_SYSTEM, R.string.use_docked_mode, R.string.use_docked_mode_description, true, dockedMode)); |
| 197 | mView.getActivity().setTitle(R.string.preferences_controls); | 151 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_REGION_INDEX, Settings.SECTION_SYSTEM, R.string.emulated_region, 0, R.array.regionNames, R.array.regionValues, -1, region)); |
| 198 | 152 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_LANGUAGE_INDEX, Settings.SECTION_SYSTEM, R.string.emulated_language, 0, R.array.languageNames, R.array.languageValues, 1, language)); | |
| 199 | SettingSection controlsSection = mSettings.getSection(Settings.SECTION_CONTROLS); | ||
| 200 | Setting buttonA = controlsSection.getSetting(SettingsFile.KEY_BUTTON_A); | ||
| 201 | Setting buttonB = controlsSection.getSetting(SettingsFile.KEY_BUTTON_B); | ||
| 202 | Setting buttonX = controlsSection.getSetting(SettingsFile.KEY_BUTTON_X); | ||
| 203 | Setting buttonY = controlsSection.getSetting(SettingsFile.KEY_BUTTON_Y); | ||
| 204 | Setting buttonSelect = controlsSection.getSetting(SettingsFile.KEY_BUTTON_SELECT); | ||
| 205 | Setting buttonStart = controlsSection.getSetting(SettingsFile.KEY_BUTTON_START); | ||
| 206 | Setting circlepadAxisVert = controlsSection.getSetting(SettingsFile.KEY_CIRCLEPAD_AXIS_VERTICAL); | ||
| 207 | Setting circlepadAxisHoriz = controlsSection.getSetting(SettingsFile.KEY_CIRCLEPAD_AXIS_HORIZONTAL); | ||
| 208 | Setting cstickAxisVert = controlsSection.getSetting(SettingsFile.KEY_CSTICK_AXIS_VERTICAL); | ||
| 209 | Setting cstickAxisHoriz = controlsSection.getSetting(SettingsFile.KEY_CSTICK_AXIS_HORIZONTAL); | ||
| 210 | Setting dpadAxisVert = controlsSection.getSetting(SettingsFile.KEY_DPAD_AXIS_VERTICAL); | ||
| 211 | Setting dpadAxisHoriz = controlsSection.getSetting(SettingsFile.KEY_DPAD_AXIS_HORIZONTAL); | ||
| 212 | // Setting buttonUp = controlsSection.getSetting(SettingsFile.KEY_BUTTON_UP); | ||
| 213 | // Setting buttonDown = controlsSection.getSetting(SettingsFile.KEY_BUTTON_DOWN); | ||
| 214 | // Setting buttonLeft = controlsSection.getSetting(SettingsFile.KEY_BUTTON_LEFT); | ||
| 215 | // Setting buttonRight = controlsSection.getSetting(SettingsFile.KEY_BUTTON_RIGHT); | ||
| 216 | Setting buttonL = controlsSection.getSetting(SettingsFile.KEY_BUTTON_L); | ||
| 217 | Setting buttonR = controlsSection.getSetting(SettingsFile.KEY_BUTTON_R); | ||
| 218 | Setting buttonZL = controlsSection.getSetting(SettingsFile.KEY_BUTTON_ZL); | ||
| 219 | Setting buttonZR = controlsSection.getSetting(SettingsFile.KEY_BUTTON_ZR); | ||
| 220 | |||
| 221 | sl.add(new HeaderSetting(null, null, R.string.generic_buttons, 0)); | ||
| 222 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_A, Settings.SECTION_CONTROLS, R.string.button_a, buttonA)); | ||
| 223 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_B, Settings.SECTION_CONTROLS, R.string.button_b, buttonB)); | ||
| 224 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_X, Settings.SECTION_CONTROLS, R.string.button_x, buttonX)); | ||
| 225 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_Y, Settings.SECTION_CONTROLS, R.string.button_y, buttonY)); | ||
| 226 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_SELECT, Settings.SECTION_CONTROLS, R.string.button_select, buttonSelect)); | ||
| 227 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_START, Settings.SECTION_CONTROLS, R.string.button_start, buttonStart)); | ||
| 228 | |||
| 229 | sl.add(new HeaderSetting(null, null, R.string.controller_circlepad, 0)); | ||
| 230 | sl.add(new InputBindingSetting(SettingsFile.KEY_CIRCLEPAD_AXIS_VERTICAL, Settings.SECTION_CONTROLS, R.string.controller_axis_vertical, circlepadAxisVert)); | ||
| 231 | sl.add(new InputBindingSetting(SettingsFile.KEY_CIRCLEPAD_AXIS_HORIZONTAL, Settings.SECTION_CONTROLS, R.string.controller_axis_horizontal, circlepadAxisHoriz)); | ||
| 232 | |||
| 233 | sl.add(new HeaderSetting(null, null, R.string.controller_c, 0)); | ||
| 234 | sl.add(new InputBindingSetting(SettingsFile.KEY_CSTICK_AXIS_VERTICAL, Settings.SECTION_CONTROLS, R.string.controller_axis_vertical, cstickAxisVert)); | ||
| 235 | sl.add(new InputBindingSetting(SettingsFile.KEY_CSTICK_AXIS_HORIZONTAL, Settings.SECTION_CONTROLS, R.string.controller_axis_horizontal, cstickAxisHoriz)); | ||
| 236 | |||
| 237 | sl.add(new HeaderSetting(null, null, R.string.controller_dpad, 0)); | ||
| 238 | sl.add(new InputBindingSetting(SettingsFile.KEY_DPAD_AXIS_VERTICAL, Settings.SECTION_CONTROLS, R.string.controller_axis_vertical, dpadAxisVert)); | ||
| 239 | sl.add(new InputBindingSetting(SettingsFile.KEY_DPAD_AXIS_HORIZONTAL, Settings.SECTION_CONTROLS, R.string.controller_axis_horizontal, dpadAxisHoriz)); | ||
| 240 | |||
| 241 | // TODO(bunnei): Figure out what to do with these. Configuring is functional, but removing for MVP because they are confusing. | ||
| 242 | // sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_UP, Settings.SECTION_CONTROLS, R.string.generic_up, buttonUp)); | ||
| 243 | // sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_DOWN, Settings.SECTION_CONTROLS, R.string.generic_down, buttonDown)); | ||
| 244 | // sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_LEFT, Settings.SECTION_CONTROLS, R.string.generic_left, buttonLeft)); | ||
| 245 | // sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_RIGHT, Settings.SECTION_CONTROLS, R.string.generic_right, buttonRight)); | ||
| 246 | |||
| 247 | sl.add(new HeaderSetting(null, null, R.string.controller_triggers, 0)); | ||
| 248 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_L, Settings.SECTION_CONTROLS, R.string.button_l, buttonL)); | ||
| 249 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_R, Settings.SECTION_CONTROLS, R.string.button_r, buttonR)); | ||
| 250 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_ZL, Settings.SECTION_CONTROLS, R.string.button_zl, buttonZL)); | ||
| 251 | sl.add(new InputBindingSetting(SettingsFile.KEY_BUTTON_ZR, Settings.SECTION_CONTROLS, R.string.button_zr, buttonZR)); | ||
| 252 | } | 153 | } |
| 253 | 154 | ||
| 254 | private void addGraphicsSettings(ArrayList<SettingsItem> sl) { | 155 | private void addGraphicsSettings(ArrayList<SettingsItem> sl) { |
| 255 | mView.getActivity().setTitle(R.string.preferences_graphics); | 156 | mView.getActivity().setTitle(R.string.preferences_graphics); |
| 256 | 157 | ||
| 257 | SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER); | 158 | SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER); |
| 258 | Setting resolutionFactor = rendererSection.getSetting(SettingsFile.KEY_RESOLUTION_FACTOR); | 159 | Setting rendererBackend = rendererSection.getSetting(SettingsFile.KEY_RENDERER_BACKEND); |
| 259 | Setting filterMode = rendererSection.getSetting(SettingsFile.KEY_FILTER_MODE); | 160 | Setting rendererAccuracy = rendererSection.getSetting(SettingsFile.KEY_RENDERER_ACCURACY); |
| 260 | Setting shadersAccurateMul = rendererSection.getSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL); | 161 | Setting rendererReolution = rendererSection.getSetting(SettingsFile.KEY_RENDERER_RESOLUTION); |
| 261 | Setting render3dMode = rendererSection.getSetting(SettingsFile.KEY_RENDER_3D); | 162 | Setting rendererAsynchronousShaders = rendererSection.getSetting(SettingsFile.KEY_RENDERER_ASYNCHRONOUS_SHADERS); |
| 262 | Setting factor3d = rendererSection.getSetting(SettingsFile.KEY_FACTOR_3D); | 163 | |
| 263 | Setting useDiskShaderCache = rendererSection.getSetting(SettingsFile.KEY_USE_DISK_SHADER_CACHE); | 164 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_RENDERER_BACKEND, Settings.SECTION_RENDERER, R.string.renderer_api, 0, R.array.rendererApiNames, R.array.rendererApiValues, 0, rendererBackend)); |
| 264 | SettingSection layoutSection = mSettings.getSection(Settings.SECTION_LAYOUT); | 165 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_RENDERER_ACCURACY, Settings.SECTION_RENDERER, R.string.renderer_accuracy, 0, R.array.rendererAccuracyNames, R.array.rendererAccuracyValues, 1, rendererAccuracy)); |
| 265 | Setting cardboardScreenSize = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_SCREEN_SIZE); | 166 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_RENDERER_RESOLUTION, Settings.SECTION_RENDERER, R.string.renderer_resolution, 0, R.array.rendererResolutionNames, R.array.rendererResolutionValues, 2, rendererReolution)); |
| 266 | Setting cardboardXShift = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_X_SHIFT); | 167 | sl.add(new CheckBoxSetting(SettingsFile.KEY_RENDERER_ASYNCHRONOUS_SHADERS, Settings.SECTION_RENDERER, R.string.renderer_asynchronous_shaders, R.string.renderer_asynchronous_shaders_description, false, rendererAsynchronousShaders)); |
| 267 | Setting cardboardYShift = layoutSection.getSetting(SettingsFile.KEY_CARDBOARD_Y_SHIFT); | ||
| 268 | SettingSection utilitySection = mSettings.getSection(Settings.SECTION_UTILITY); | ||
| 269 | Setting dumpTextures = utilitySection.getSetting(SettingsFile.KEY_DUMP_TEXTURES); | ||
| 270 | Setting customTextures = utilitySection.getSetting(SettingsFile.KEY_CUSTOM_TEXTURES); | ||
| 271 | //Setting preloadTextures = utilitySection.getSetting(SettingsFile.KEY_PRELOAD_TEXTURES); | ||
| 272 | |||
| 273 | sl.add(new HeaderSetting(null, null, R.string.renderer, 0)); | ||
| 274 | sl.add(new SliderSetting(SettingsFile.KEY_RESOLUTION_FACTOR, Settings.SECTION_RENDERER, R.string.internal_resolution, R.string.internal_resolution_description, 1, 4, "x", 1, resolutionFactor)); | ||
| 275 | sl.add(new CheckBoxSetting(SettingsFile.KEY_FILTER_MODE, Settings.SECTION_RENDERER, R.string.linear_filtering, R.string.linear_filtering_description, true, filterMode)); | ||
| 276 | sl.add(new CheckBoxSetting(SettingsFile.KEY_SHADERS_ACCURATE_MUL, Settings.SECTION_RENDERER, R.string.shaders_accurate_mul, R.string.shaders_accurate_mul_description, false, shadersAccurateMul)); | ||
| 277 | sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_DISK_SHADER_CACHE, Settings.SECTION_RENDERER, R.string.use_disk_shader_cache, R.string.use_disk_shader_cache_description, true, useDiskShaderCache)); | ||
| 278 | |||
| 279 | sl.add(new HeaderSetting(null, null, R.string.stereoscopy, 0)); | ||
| 280 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_RENDER_3D, Settings.SECTION_RENDERER, R.string.render3d, 0, R.array.render3dModes, R.array.render3dValues, 0, render3dMode)); | ||
| 281 | sl.add(new SliderSetting(SettingsFile.KEY_FACTOR_3D, Settings.SECTION_RENDERER, R.string.factor3d, R.string.factor3d_description, 0, 100, "%", 0, factor3d)); | ||
| 282 | |||
| 283 | sl.add(new HeaderSetting(null, null, R.string.cardboard_vr, 0)); | ||
| 284 | sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_SCREEN_SIZE, Settings.SECTION_LAYOUT, R.string.cardboard_screen_size, R.string.cardboard_screen_size_description, 30, 100, "%", 85, cardboardScreenSize)); | ||
| 285 | sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_X_SHIFT, Settings.SECTION_LAYOUT, R.string.cardboard_x_shift, R.string.cardboard_x_shift_description, -100, 100, "%", 0, cardboardXShift)); | ||
| 286 | sl.add(new SliderSetting(SettingsFile.KEY_CARDBOARD_Y_SHIFT, Settings.SECTION_LAYOUT, R.string.cardboard_y_shift, R.string.cardboard_y_shift_description, -100, 100, "%", 0, cardboardYShift)); | ||
| 287 | |||
| 288 | sl.add(new HeaderSetting(null, null, R.string.utility, 0)); | ||
| 289 | sl.add(new CheckBoxSetting(SettingsFile.KEY_DUMP_TEXTURES, Settings.SECTION_UTILITY, R.string.dump_textures, R.string.dump_textures_description, false, dumpTextures)); | ||
| 290 | sl.add(new CheckBoxSetting(SettingsFile.KEY_CUSTOM_TEXTURES, Settings.SECTION_UTILITY, R.string.custom_textures, R.string.custom_textures_description, false, customTextures)); | ||
| 291 | //Disabled until custom texture implementation gets rewrite, current one overloads RAM and crashes yuzu. | ||
| 292 | //sl.add(new CheckBoxSetting(SettingsFile.KEY_PRELOAD_TEXTURES, Settings.SECTION_UTILITY, R.string.preload_textures, R.string.preload_textures_description, false, preloadTextures)); | ||
| 293 | } | 168 | } |
| 294 | 169 | ||
| 295 | private void addAudioSettings(ArrayList<SettingsItem> sl) { | 170 | private void addAudioSettings(ArrayList<SettingsItem> sl) { |
| 296 | mView.getActivity().setTitle(R.string.preferences_audio); | 171 | mView.getActivity().setTitle(R.string.preferences_audio); |
| 297 | 172 | ||
| 298 | SettingSection audioSection = mSettings.getSection(Settings.SECTION_AUDIO); | 173 | SettingSection audioSection = mSettings.getSection(Settings.SECTION_AUDIO); |
| 299 | Setting audioStretch = audioSection.getSetting(SettingsFile.KEY_ENABLE_AUDIO_STRETCHING); | 174 | Setting audioVolume = audioSection.getSetting(SettingsFile.KEY_AUDIO_VOLUME); |
| 300 | Setting micInputType = audioSection.getSetting(SettingsFile.KEY_MIC_INPUT_TYPE); | ||
| 301 | 175 | ||
| 302 | sl.add(new CheckBoxSetting(SettingsFile.KEY_ENABLE_AUDIO_STRETCHING, Settings.SECTION_AUDIO, R.string.audio_stretch, R.string.audio_stretch_description, true, audioStretch)); | 176 | sl.add(new SliderSetting(SettingsFile.KEY_AUDIO_VOLUME, Settings.SECTION_AUDIO, R.string.audio_volume, R.string.audio_volume_description, 0, 100, "%", 100, audioVolume)); |
| 303 | sl.add(new SingleChoiceSetting(SettingsFile.KEY_MIC_INPUT_TYPE, Settings.SECTION_AUDIO, R.string.audio_input_type, 0, R.array.audioInputTypeNames, R.array.audioInputTypeValues, 1, micInputType)); | ||
| 304 | } | ||
| 305 | |||
| 306 | private void addDebugSettings(ArrayList<SettingsItem> sl) { | ||
| 307 | mView.getActivity().setTitle(R.string.preferences_debug); | ||
| 308 | |||
| 309 | SettingSection coreSection = mSettings.getSection(Settings.SECTION_CORE); | ||
| 310 | SettingSection rendererSection = mSettings.getSection(Settings.SECTION_RENDERER); | ||
| 311 | Setting useCpuJit = coreSection.getSetting(SettingsFile.KEY_CPU_JIT); | ||
| 312 | Setting hardwareRenderer = rendererSection.getSetting(SettingsFile.KEY_HW_RENDERER); | ||
| 313 | Setting hardwareShader = rendererSection.getSetting(SettingsFile.KEY_HW_SHADER); | ||
| 314 | Setting vsyncEnable = rendererSection.getSetting(SettingsFile.KEY_USE_VSYNC); | ||
| 315 | |||
| 316 | sl.add(new HeaderSetting(null, null, R.string.debug_warning, 0)); | ||
| 317 | sl.add(new CheckBoxSetting(SettingsFile.KEY_CPU_JIT, Settings.SECTION_CORE, R.string.cpu_jit, R.string.cpu_jit_description, true, useCpuJit, true, mView)); | ||
| 318 | sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_RENDERER, Settings.SECTION_RENDERER, R.string.hw_renderer, R.string.hw_renderer_description, true, hardwareRenderer, true, mView)); | ||
| 319 | sl.add(new CheckBoxSetting(SettingsFile.KEY_HW_SHADER, Settings.SECTION_RENDERER, R.string.hw_shaders, R.string.hw_shaders_description, true, hardwareShader, true, mView)); | ||
| 320 | sl.add(new CheckBoxSetting(SettingsFile.KEY_USE_VSYNC, Settings.SECTION_RENDERER, R.string.vsync, R.string.vsync_description, true, vsyncEnable)); | ||
| 321 | } | 177 | } |
| 322 | } | 178 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputBindingSettingViewHolder.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputBindingSettingViewHolder.java deleted file mode 100644 index 6f8bef7d7..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/InputBindingSettingViewHolder.java +++ /dev/null | |||
| @@ -1,55 +0,0 @@ | |||
| 1 | package org.yuzu.yuzu_emu.features.settings.ui.viewholder; | ||
| 2 | |||
| 3 | import android.content.Context; | ||
| 4 | import android.content.SharedPreferences; | ||
| 5 | import android.preference.PreferenceManager; | ||
| 6 | import android.view.View; | ||
| 7 | import android.widget.TextView; | ||
| 8 | |||
| 9 | import org.yuzu.yuzu_emu.R; | ||
| 10 | import org.yuzu.yuzu_emu.features.settings.model.view.InputBindingSetting; | ||
| 11 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem; | ||
| 12 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter; | ||
| 13 | |||
| 14 | public final class InputBindingSettingViewHolder extends SettingViewHolder { | ||
| 15 | private InputBindingSetting mItem; | ||
| 16 | |||
| 17 | private TextView mTextSettingName; | ||
| 18 | private TextView mTextSettingDescription; | ||
| 19 | |||
| 20 | private Context mContext; | ||
| 21 | |||
| 22 | public InputBindingSettingViewHolder(View itemView, SettingsAdapter adapter, Context context) { | ||
| 23 | super(itemView, adapter); | ||
| 24 | |||
| 25 | mContext = context; | ||
| 26 | } | ||
| 27 | |||
| 28 | @Override | ||
| 29 | protected void findViews(View root) { | ||
| 30 | mTextSettingName = root.findViewById(R.id.text_setting_name); | ||
| 31 | mTextSettingDescription = root.findViewById(R.id.text_setting_description); | ||
| 32 | } | ||
| 33 | |||
| 34 | @Override | ||
| 35 | public void bind(SettingsItem item) { | ||
| 36 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext); | ||
| 37 | |||
| 38 | mItem = (InputBindingSetting) item; | ||
| 39 | |||
| 40 | mTextSettingName.setText(item.getNameId()); | ||
| 41 | |||
| 42 | String key = sharedPreferences.getString(mItem.getKey(), ""); | ||
| 43 | if (key != null && !key.isEmpty()) { | ||
| 44 | mTextSettingDescription.setText(key); | ||
| 45 | mTextSettingDescription.setVisibility(View.VISIBLE); | ||
| 46 | } else { | ||
| 47 | mTextSettingDescription.setVisibility(View.GONE); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | @Override | ||
| 52 | public void onClick(View clicked) { | ||
| 53 | getAdapter().onInputBindingClick(mItem, getAdapterPosition()); | ||
| 54 | } | ||
| 55 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/PremiumViewHolder.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/PremiumViewHolder.java deleted file mode 100644 index 1f862b281..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/PremiumViewHolder.java +++ /dev/null | |||
| @@ -1,57 +0,0 @@ | |||
| 1 | package org.yuzu.yuzu_emu.features.settings.ui.viewholder; | ||
| 2 | |||
| 3 | import android.view.View; | ||
| 4 | import android.widget.TextView; | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.R; | ||
| 7 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem; | ||
| 8 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter; | ||
| 9 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsFragmentView; | ||
| 10 | import org.yuzu.yuzu_emu.ui.main.MainActivity; | ||
| 11 | |||
| 12 | public final class PremiumViewHolder extends SettingViewHolder { | ||
| 13 | private TextView mHeaderName; | ||
| 14 | private TextView mTextDescription; | ||
| 15 | private SettingsFragmentView mView; | ||
| 16 | |||
| 17 | public PremiumViewHolder(View itemView, SettingsAdapter adapter, SettingsFragmentView view) { | ||
| 18 | super(itemView, adapter); | ||
| 19 | mView = view; | ||
| 20 | itemView.setOnClickListener(this); | ||
| 21 | } | ||
| 22 | |||
| 23 | @Override | ||
| 24 | protected void findViews(View root) { | ||
| 25 | mHeaderName = root.findViewById(R.id.text_setting_name); | ||
| 26 | mTextDescription = root.findViewById(R.id.text_setting_description); | ||
| 27 | } | ||
| 28 | |||
| 29 | @Override | ||
| 30 | public void bind(SettingsItem item) { | ||
| 31 | updateText(); | ||
| 32 | } | ||
| 33 | |||
| 34 | @Override | ||
| 35 | public void onClick(View clicked) { | ||
| 36 | if (MainActivity.isPremiumActive()) { | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | |||
| 40 | // Invoke billing flow if Premium is not already active, then refresh the UI to indicate | ||
| 41 | // the purchase has completed. | ||
| 42 | MainActivity.invokePremiumBilling(() -> updateText()); | ||
| 43 | } | ||
| 44 | |||
| 45 | /** | ||
| 46 | * Update the text shown to the user, based on whether Premium is active | ||
| 47 | */ | ||
| 48 | private void updateText() { | ||
| 49 | if (MainActivity.isPremiumActive()) { | ||
| 50 | mHeaderName.setText(R.string.premium_settings_welcome); | ||
| 51 | mTextDescription.setText(R.string.premium_settings_welcome_description); | ||
| 52 | } else { | ||
| 53 | mHeaderName.setText(R.string.premium_settings_upsell); | ||
| 54 | mTextDescription.setText(R.string.premium_settings_upsell_description); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.java index e3766f55e..539710395 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SingleChoiceViewHolder.java | |||
| @@ -5,7 +5,6 @@ import android.view.View; | |||
| 5 | import android.widget.TextView; | 5 | import android.widget.TextView; |
| 6 | 6 | ||
| 7 | import org.yuzu.yuzu_emu.R; | 7 | import org.yuzu.yuzu_emu.R; |
| 8 | import org.yuzu.yuzu_emu.features.settings.model.view.PremiumSingleChoiceSetting; | ||
| 9 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem; | 8 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem; |
| 10 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting; | 9 | import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting; |
| 11 | import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting; | 10 | import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting; |
| @@ -46,17 +45,6 @@ public final class SingleChoiceViewHolder extends SettingViewHolder { | |||
| 46 | mTextSettingDescription.setText(choices[i]); | 45 | mTextSettingDescription.setText(choices[i]); |
| 47 | } | 46 | } |
| 48 | } | 47 | } |
| 49 | } else if (item instanceof PremiumSingleChoiceSetting) { | ||
| 50 | PremiumSingleChoiceSetting setting = (PremiumSingleChoiceSetting) item; | ||
| 51 | int selected = setting.getSelectedValue(); | ||
| 52 | Resources resMgr = mTextSettingDescription.getContext().getResources(); | ||
| 53 | String[] choices = resMgr.getStringArray(setting.getChoicesId()); | ||
| 54 | int[] values = resMgr.getIntArray(setting.getValuesId()); | ||
| 55 | for (int i = 0; i < values.length; ++i) { | ||
| 56 | if (values[i] == selected) { | ||
| 57 | mTextSettingDescription.setText(choices[i]); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } else { | 48 | } else { |
| 61 | mTextSettingDescription.setVisibility(View.GONE); | 49 | mTextSettingDescription.setVisibility(View.GONE); |
| 62 | } | 50 | } |
| @@ -67,8 +55,6 @@ public final class SingleChoiceViewHolder extends SettingViewHolder { | |||
| 67 | int position = getAdapterPosition(); | 55 | int position = getAdapterPosition(); |
| 68 | if (mItem instanceof SingleChoiceSetting) { | 56 | if (mItem instanceof SingleChoiceSetting) { |
| 69 | getAdapter().onSingleChoiceClick((SingleChoiceSetting) mItem, position); | 57 | getAdapter().onSingleChoiceClick((SingleChoiceSetting) mItem, position); |
| 70 | } else if (mItem instanceof PremiumSingleChoiceSetting) { | ||
| 71 | getAdapter().onSingleChoiceClick((PremiumSingleChoiceSetting) mItem, position); | ||
| 72 | } else if (mItem instanceof StringSingleChoiceSetting) { | 58 | } else if (mItem instanceof StringSingleChoiceSetting) { |
| 73 | getAdapter().onStringSingleChoiceClick((StringSingleChoiceSetting) mItem, position); | 59 | getAdapter().onStringSingleChoiceClick((StringSingleChoiceSetting) mItem, position); |
| 74 | } | 60 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java index 9e58dedc2..6526f9139 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.java | |||
| @@ -33,95 +33,23 @@ import java.util.TreeSet; | |||
| 33 | public final class SettingsFile { | 33 | public final class SettingsFile { |
| 34 | public static final String FILE_NAME_CONFIG = "config"; | 34 | public static final String FILE_NAME_CONFIG = "config"; |
| 35 | 35 | ||
| 36 | public static final String KEY_CPU_JIT = "use_cpu_jit"; | ||
| 37 | |||
| 38 | public static final String KEY_DESIGN = "design"; | 36 | public static final String KEY_DESIGN = "design"; |
| 39 | 37 | ||
| 40 | public static final String KEY_PREMIUM = "premium"; | 38 | // CPU |
| 41 | 39 | public static final String KEY_CPU_ACCURACY = "cpu_accuracy"; | |
| 42 | public static final String KEY_HW_RENDERER = "use_hw_renderer"; | 40 | // System |
| 43 | public static final String KEY_HW_SHADER = "use_hw_shader"; | 41 | public static final String KEY_USE_DOCKED_MODE = "use_docked_mode"; |
| 44 | public static final String KEY_SHADERS_ACCURATE_MUL = "shaders_accurate_mul"; | 42 | public static final String KEY_REGION_INDEX = "region_index"; |
| 45 | public static final String KEY_USE_SHADER_JIT = "use_shader_jit"; | 43 | public static final String KEY_LANGUAGE_INDEX = "language_index"; |
| 46 | public static final String KEY_USE_DISK_SHADER_CACHE = "use_disk_shader_cache"; | 44 | public static final String KEY_RENDERER_BACKEND = "backend"; |
| 47 | public static final String KEY_USE_VSYNC = "use_vsync_new"; | 45 | // Renderer |
| 48 | public static final String KEY_RESOLUTION_FACTOR = "resolution_factor"; | 46 | public static final String KEY_RENDERER_RESOLUTION = "resolution_setup"; |
| 49 | public static final String KEY_FRAME_LIMIT_ENABLED = "use_frame_limit"; | 47 | public static final String KEY_RENDERER_ACCURACY = "gpu_accuracy"; |
| 50 | public static final String KEY_FRAME_LIMIT = "frame_limit"; | 48 | public static final String KEY_RENDERER_ASYNCHRONOUS_SHADERS = "use_asynchronous_shaders"; |
| 51 | public static final String KEY_BACKGROUND_RED = "bg_red"; | 49 | public static final String KEY_RENDERER_USE_SPEED_LIMIT = "use_speed_limit"; |
| 52 | public static final String KEY_BACKGROUND_BLUE = "bg_blue"; | 50 | public static final String KEY_RENDERER_SPEED_LIMIT = "speed_limit"; |
| 53 | public static final String KEY_BACKGROUND_GREEN = "bg_green"; | 51 | // Audio |
| 54 | public static final String KEY_RENDER_3D = "render_3d"; | 52 | public static final String KEY_AUDIO_VOLUME = "volume"; |
| 55 | public static final String KEY_FACTOR_3D = "factor_3d"; | ||
| 56 | public static final String KEY_PP_SHADER_NAME = "pp_shader_name"; | ||
| 57 | public static final String KEY_FILTER_MODE = "filter_mode"; | ||
| 58 | public static final String KEY_TEXTURE_FILTER_NAME = "texture_filter_name"; | ||
| 59 | public static final String KEY_USE_ASYNCHRONOUS_GPU_EMULATION = "use_asynchronous_gpu_emulation"; | ||
| 60 | |||
| 61 | public static final String KEY_LAYOUT_OPTION = "layout_option"; | ||
| 62 | public static final String KEY_SWAP_SCREEN = "swap_screen"; | ||
| 63 | public static final String KEY_CARDBOARD_SCREEN_SIZE = "cardboard_screen_size"; | ||
| 64 | public static final String KEY_CARDBOARD_X_SHIFT = "cardboard_x_shift"; | ||
| 65 | public static final String KEY_CARDBOARD_Y_SHIFT = "cardboard_y_shift"; | ||
| 66 | |||
| 67 | public static final String KEY_DUMP_TEXTURES = "dump_textures"; | ||
| 68 | public static final String KEY_CUSTOM_TEXTURES = "custom_textures"; | ||
| 69 | public static final String KEY_PRELOAD_TEXTURES = "preload_textures"; | ||
| 70 | |||
| 71 | public static final String KEY_AUDIO_OUTPUT_ENGINE = "output_engine"; | ||
| 72 | public static final String KEY_ENABLE_AUDIO_STRETCHING = "enable_audio_stretching"; | ||
| 73 | public static final String KEY_VOLUME = "volume"; | ||
| 74 | public static final String KEY_MIC_INPUT_TYPE = "mic_input_type"; | ||
| 75 | |||
| 76 | public static final String KEY_USE_VIRTUAL_SD = "use_virtual_sd"; | ||
| 77 | |||
| 78 | public static final String KEY_IS_NEW_3DS = "is_new_3ds"; | ||
| 79 | public static final String KEY_REGION_VALUE = "region_value"; | ||
| 80 | public static final String KEY_LANGUAGE = "language"; | ||
| 81 | |||
| 82 | public static final String KEY_INIT_CLOCK = "init_clock"; | ||
| 83 | public static final String KEY_INIT_TIME = "init_time"; | ||
| 84 | |||
| 85 | public static final String KEY_BUTTON_A = "button_a"; | ||
| 86 | public static final String KEY_BUTTON_B = "button_b"; | ||
| 87 | public static final String KEY_BUTTON_X = "button_x"; | ||
| 88 | public static final String KEY_BUTTON_Y = "button_y"; | ||
| 89 | public static final String KEY_BUTTON_SELECT = "button_select"; | ||
| 90 | public static final String KEY_BUTTON_START = "button_start"; | ||
| 91 | public static final String KEY_BUTTON_UP = "button_up"; | ||
| 92 | public static final String KEY_BUTTON_DOWN = "button_down"; | ||
| 93 | public static final String KEY_BUTTON_LEFT = "button_left"; | ||
| 94 | public static final String KEY_BUTTON_RIGHT = "button_right"; | ||
| 95 | public static final String KEY_BUTTON_L = "button_l"; | ||
| 96 | public static final String KEY_BUTTON_R = "button_r"; | ||
| 97 | public static final String KEY_BUTTON_ZL = "button_zl"; | ||
| 98 | public static final String KEY_BUTTON_ZR = "button_zr"; | ||
| 99 | public static final String KEY_CIRCLEPAD_AXIS_VERTICAL = "circlepad_axis_vertical"; | ||
| 100 | public static final String KEY_CIRCLEPAD_AXIS_HORIZONTAL = "circlepad_axis_horizontal"; | ||
| 101 | public static final String KEY_CSTICK_AXIS_VERTICAL = "cstick_axis_vertical"; | ||
| 102 | public static final String KEY_CSTICK_AXIS_HORIZONTAL = "cstick_axis_horizontal"; | ||
| 103 | public static final String KEY_DPAD_AXIS_VERTICAL = "dpad_axis_vertical"; | ||
| 104 | public static final String KEY_DPAD_AXIS_HORIZONTAL = "dpad_axis_horizontal"; | ||
| 105 | public static final String KEY_CIRCLEPAD_UP = "circlepad_up"; | ||
| 106 | public static final String KEY_CIRCLEPAD_DOWN = "circlepad_down"; | ||
| 107 | public static final String KEY_CIRCLEPAD_LEFT = "circlepad_left"; | ||
| 108 | public static final String KEY_CIRCLEPAD_RIGHT = "circlepad_right"; | ||
| 109 | public static final String KEY_CSTICK_UP = "cstick_up"; | ||
| 110 | public static final String KEY_CSTICK_DOWN = "cstick_down"; | ||
| 111 | public static final String KEY_CSTICK_LEFT = "cstick_left"; | ||
| 112 | public static final String KEY_CSTICK_RIGHT = "cstick_right"; | ||
| 113 | |||
| 114 | public static final String KEY_CAMERA_OUTER_RIGHT_NAME = "camera_outer_right_name"; | ||
| 115 | public static final String KEY_CAMERA_OUTER_RIGHT_CONFIG = "camera_outer_right_config"; | ||
| 116 | public static final String KEY_CAMERA_OUTER_RIGHT_FLIP = "camera_outer_right_flip"; | ||
| 117 | public static final String KEY_CAMERA_OUTER_LEFT_NAME = "camera_outer_left_name"; | ||
| 118 | public static final String KEY_CAMERA_OUTER_LEFT_CONFIG = "camera_outer_left_config"; | ||
| 119 | public static final String KEY_CAMERA_OUTER_LEFT_FLIP = "camera_outer_left_flip"; | ||
| 120 | public static final String KEY_CAMERA_INNER_NAME = "camera_inner_name"; | ||
| 121 | public static final String KEY_CAMERA_INNER_CONFIG = "camera_inner_config"; | ||
| 122 | public static final String KEY_CAMERA_INNER_FLIP = "camera_inner_flip"; | ||
| 123 | |||
| 124 | public static final String KEY_LOG_FILTER = "log_filter"; | ||
| 125 | 53 | ||
| 126 | private static BiMap<String, String> sectionsMap = new BiMap<>(); | 54 | private static BiMap<String, String> sectionsMap = new BiMap<>(); |
| 127 | 55 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.java index b2083f858..f7a242171 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.java | |||
| @@ -29,7 +29,6 @@ import org.yuzu.yuzu_emu.overlay.InputOverlay; | |||
| 29 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization; | 29 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization; |
| 30 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState; | 30 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState; |
| 31 | import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver; | 31 | import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver; |
| 32 | import org.yuzu.yuzu_emu.utils.EmulationMenuSettings; | ||
| 33 | import org.yuzu.yuzu_emu.utils.Log; | 32 | import org.yuzu.yuzu_emu.utils.Log; |
| 34 | 33 | ||
| 35 | public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback, Choreographer.FrameCallback { | 34 | public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback, Choreographer.FrameCallback { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java index 6558a05c9..d419750a3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.java | |||
| @@ -18,7 +18,6 @@ import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity; | |||
| 18 | import org.yuzu.yuzu_emu.model.GameProvider; | 18 | import org.yuzu.yuzu_emu.model.GameProvider; |
| 19 | import org.yuzu.yuzu_emu.ui.platform.PlatformGamesFragment; | 19 | import org.yuzu.yuzu_emu.ui.platform.PlatformGamesFragment; |
| 20 | import org.yuzu.yuzu_emu.utils.AddDirectoryHelper; | 20 | import org.yuzu.yuzu_emu.utils.AddDirectoryHelper; |
| 21 | import org.yuzu.yuzu_emu.utils.BillingManager; | ||
| 22 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization; | 21 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization; |
| 23 | import org.yuzu.yuzu_emu.utils.FileBrowserHelper; | 22 | import org.yuzu.yuzu_emu.utils.FileBrowserHelper; |
| 24 | import org.yuzu.yuzu_emu.utils.PermissionsHandler; | 23 | import org.yuzu.yuzu_emu.utils.PermissionsHandler; |
| @@ -40,11 +39,6 @@ public final class MainActivity extends AppCompatActivity implements MainView { | |||
| 40 | 39 | ||
| 41 | private MainPresenter mPresenter = new MainPresenter(this); | 40 | private MainPresenter mPresenter = new MainPresenter(this); |
| 42 | 41 | ||
| 43 | // Singleton to manage user billing state | ||
| 44 | private static BillingManager mBillingManager; | ||
| 45 | |||
| 46 | private static MenuItem mPremiumButton; | ||
| 47 | |||
| 48 | @Override | 42 | @Override |
| 49 | protected void onCreate(Bundle savedInstanceState) { | 43 | protected void onCreate(Bundle savedInstanceState) { |
| 50 | ThemeUtil.applyTheme(); | 44 | ThemeUtil.applyTheme(); |
| @@ -71,9 +65,6 @@ public final class MainActivity extends AppCompatActivity implements MainView { | |||
| 71 | } | 65 | } |
| 72 | PicassoUtils.init(); | 66 | PicassoUtils.init(); |
| 73 | 67 | ||
| 74 | // Setup billing manager, so we can globally query for Premium status | ||
| 75 | mBillingManager = new BillingManager(this); | ||
| 76 | |||
| 77 | // Dismiss previous notifications (should not happen unless a crash occurred) | 68 | // Dismiss previous notifications (should not happen unless a crash occurred) |
| 78 | EmulationActivity.tryDismissRunningNotification(this); | 69 | EmulationActivity.tryDismissRunningNotification(this); |
| 79 | } | 70 | } |
| @@ -107,22 +98,10 @@ public final class MainActivity extends AppCompatActivity implements MainView { | |||
| 107 | public boolean onCreateOptionsMenu(Menu menu) { | 98 | public boolean onCreateOptionsMenu(Menu menu) { |
| 108 | MenuInflater inflater = getMenuInflater(); | 99 | MenuInflater inflater = getMenuInflater(); |
| 109 | inflater.inflate(R.menu.menu_game_grid, menu); | 100 | inflater.inflate(R.menu.menu_game_grid, menu); |
| 110 | mPremiumButton = menu.findItem(R.id.button_premium); | ||
| 111 | |||
| 112 | if (mBillingManager.isPremiumCached()) { | ||
| 113 | // User had premium in a previous session, hide upsell option | ||
| 114 | setPremiumButtonVisible(false); | ||
| 115 | } | ||
| 116 | 101 | ||
| 117 | return true; | 102 | return true; |
| 118 | } | 103 | } |
| 119 | 104 | ||
| 120 | static public void setPremiumButtonVisible(boolean isVisible) { | ||
| 121 | if (mPremiumButton != null) { | ||
| 122 | mPremiumButton.setVisible(isVisible); | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | /** | 105 | /** |
| 127 | * MainView | 106 | * MainView |
| 128 | */ | 107 | */ |
| @@ -155,15 +134,8 @@ public final class MainActivity extends AppCompatActivity implements MainView { | |||
| 155 | FileBrowserHelper.openDirectoryPicker(this, | 134 | FileBrowserHelper.openDirectoryPicker(this, |
| 156 | MainPresenter.REQUEST_ADD_DIRECTORY, | 135 | MainPresenter.REQUEST_ADD_DIRECTORY, |
| 157 | R.string.select_game_folder, | 136 | R.string.select_game_folder, |
| 158 | Arrays.asList("xci", "nsp", "cci", "3ds", | 137 | Arrays.asList("nso", "nro", "nca", "xci", |
| 159 | "cxi", "app", "3dsx", "cia", | 138 | "nsp", "kip")); |
| 160 | "rar", "zip", "7z", "torrent", | ||
| 161 | "tar", "gz", "nro")); | ||
| 162 | break; | ||
| 163 | case MainPresenter.REQUEST_INSTALL_CIA: | ||
| 164 | FileBrowserHelper.openFilePicker(this, MainPresenter.REQUEST_INSTALL_CIA, | ||
| 165 | R.string.install_cia_title, | ||
| 166 | Collections.singletonList("cia"), true); | ||
| 167 | break; | 139 | break; |
| 168 | } | 140 | } |
| 169 | } else { | 141 | } else { |
| @@ -191,12 +163,6 @@ public final class MainActivity extends AppCompatActivity implements MainView { | |||
| 191 | mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result)); | 163 | mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result)); |
| 192 | } | 164 | } |
| 193 | break; | 165 | break; |
| 194 | case MainPresenter.REQUEST_INSTALL_CIA: | ||
| 195 | // If the user picked a file, as opposed to just backing out. | ||
| 196 | if (resultCode == MainActivity.RESULT_OK) { | ||
| 197 | mPresenter.refeshGameList(); | ||
| 198 | } | ||
| 199 | break; | ||
| 200 | } | 166 | } |
| 201 | } | 167 | } |
| 202 | 168 | ||
| @@ -248,20 +214,4 @@ public final class MainActivity extends AppCompatActivity implements MainView { | |||
| 248 | EmulationActivity.tryDismissRunningNotification(this); | 214 | EmulationActivity.tryDismissRunningNotification(this); |
| 249 | super.onDestroy(); | 215 | super.onDestroy(); |
| 250 | } | 216 | } |
| 251 | |||
| 252 | /** | ||
| 253 | * @return true if Premium subscription is currently active | ||
| 254 | */ | ||
| 255 | public static boolean isPremiumActive() { | ||
| 256 | return mBillingManager.isPremiumActive(); | ||
| 257 | } | ||
| 258 | |||
| 259 | /** | ||
| 260 | * Invokes the billing flow for Premium | ||
| 261 | * | ||
| 262 | * @param callback Optional callback, called once, on completion of billing | ||
| 263 | */ | ||
| 264 | public static void invokePremiumBilling(Runnable callback) { | ||
| 265 | mBillingManager.invokePremiumBilling(callback); | ||
| 266 | } | ||
| 267 | } | 217 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java index 2608df2c2..4cf643552 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainPresenter.java | |||
| @@ -5,15 +5,12 @@ import android.os.SystemClock; | |||
| 5 | import org.yuzu.yuzu_emu.BuildConfig; | 5 | import org.yuzu.yuzu_emu.BuildConfig; |
| 6 | import org.yuzu.yuzu_emu.YuzuApplication; | 6 | import org.yuzu.yuzu_emu.YuzuApplication; |
| 7 | import org.yuzu.yuzu_emu.R; | 7 | import org.yuzu.yuzu_emu.R; |
| 8 | import org.yuzu.yuzu_emu.features.settings.model.Settings; | ||
| 9 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile; | 8 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile; |
| 10 | import org.yuzu.yuzu_emu.model.GameDatabase; | 9 | import org.yuzu.yuzu_emu.model.GameDatabase; |
| 11 | import org.yuzu.yuzu_emu.utils.AddDirectoryHelper; | 10 | import org.yuzu.yuzu_emu.utils.AddDirectoryHelper; |
| 12 | 11 | ||
| 13 | public final class MainPresenter { | 12 | public final class MainPresenter { |
| 14 | public static final int REQUEST_ADD_DIRECTORY = 1; | 13 | public static final int REQUEST_ADD_DIRECTORY = 1; |
| 15 | public static final int REQUEST_INSTALL_CIA = 2; | ||
| 16 | |||
| 17 | private final MainView mView; | 14 | private final MainView mView; |
| 18 | private String mDirToAdd; | 15 | private String mDirToAdd; |
| 19 | private long mLastClickTime = 0; | 16 | private long mLastClickTime = 0; |
| @@ -49,14 +46,6 @@ public final class MainPresenter { | |||
| 49 | case R.id.button_add_directory: | 46 | case R.id.button_add_directory: |
| 50 | launchFileListActivity(REQUEST_ADD_DIRECTORY); | 47 | launchFileListActivity(REQUEST_ADD_DIRECTORY); |
| 51 | return true; | 48 | return true; |
| 52 | |||
| 53 | case R.id.button_install_cia: | ||
| 54 | launchFileListActivity(REQUEST_INSTALL_CIA); | ||
| 55 | return true; | ||
| 56 | |||
| 57 | case R.id.button_premium: | ||
| 58 | mView.launchSettingsActivity(Settings.SECTION_PREMIUM); | ||
| 59 | return true; | ||
| 60 | } | 49 | } |
| 61 | 50 | ||
| 62 | return false; | 51 | return false; |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BillingManager.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BillingManager.java deleted file mode 100644 index 3d6dd1481..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BillingManager.java +++ /dev/null | |||
| @@ -1,215 +0,0 @@ | |||
| 1 | package org.yuzu.yuzu_emu.utils; | ||
| 2 | |||
| 3 | import android.app.Activity; | ||
| 4 | import android.content.SharedPreferences; | ||
| 5 | import android.preference.PreferenceManager; | ||
| 6 | import android.widget.Toast; | ||
| 7 | |||
| 8 | import com.android.billingclient.api.AcknowledgePurchaseParams; | ||
| 9 | import com.android.billingclient.api.AcknowledgePurchaseResponseListener; | ||
| 10 | import com.android.billingclient.api.BillingClient; | ||
| 11 | import com.android.billingclient.api.BillingClientStateListener; | ||
| 12 | import com.android.billingclient.api.BillingFlowParams; | ||
| 13 | import com.android.billingclient.api.BillingResult; | ||
| 14 | import com.android.billingclient.api.Purchase; | ||
| 15 | import com.android.billingclient.api.Purchase.PurchasesResult; | ||
| 16 | import com.android.billingclient.api.PurchasesUpdatedListener; | ||
| 17 | import com.android.billingclient.api.SkuDetails; | ||
| 18 | import com.android.billingclient.api.SkuDetailsParams; | ||
| 19 | |||
| 20 | import org.yuzu.yuzu_emu.YuzuApplication; | ||
| 21 | import org.yuzu.yuzu_emu.R; | ||
| 22 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile; | ||
| 23 | import org.yuzu.yuzu_emu.ui.main.MainActivity; | ||
| 24 | |||
| 25 | import java.util.ArrayList; | ||
| 26 | import java.util.List; | ||
| 27 | |||
| 28 | public class BillingManager implements PurchasesUpdatedListener { | ||
| 29 | private final String BILLING_SKU_PREMIUM = "yuzu.yuzu_emu.product_id.premium"; | ||
| 30 | |||
| 31 | private final Activity mActivity; | ||
| 32 | private BillingClient mBillingClient; | ||
| 33 | private SkuDetails mSkuPremium; | ||
| 34 | private boolean mIsPremiumActive = false; | ||
| 35 | private boolean mIsServiceConnected = false; | ||
| 36 | private Runnable mUpdateBillingCallback; | ||
| 37 | |||
| 38 | private static SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.getAppContext()); | ||
| 39 | |||
| 40 | public BillingManager(Activity activity) { | ||
| 41 | mActivity = activity; | ||
| 42 | mBillingClient = BillingClient.newBuilder(mActivity).enablePendingPurchases().setListener(this).build(); | ||
| 43 | querySkuDetails(); | ||
| 44 | } | ||
| 45 | |||
| 46 | static public boolean isPremiumCached() { | ||
| 47 | return mPreferences.getBoolean(SettingsFile.KEY_PREMIUM, false); | ||
| 48 | } | ||
| 49 | |||
| 50 | /** | ||
| 51 | * @return true if Premium subscription is currently active | ||
| 52 | */ | ||
| 53 | public boolean isPremiumActive() { | ||
| 54 | return mIsPremiumActive; | ||
| 55 | } | ||
| 56 | |||
| 57 | /** | ||
| 58 | * Invokes the billing flow for Premium | ||
| 59 | * | ||
| 60 | * @param callback Optional callback, called once, on completion of billing | ||
| 61 | */ | ||
| 62 | public void invokePremiumBilling(Runnable callback) { | ||
| 63 | if (mSkuPremium == null) { | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | |||
| 67 | // Optional callback to refresh the UI for the caller when billing completes | ||
| 68 | mUpdateBillingCallback = callback; | ||
| 69 | |||
| 70 | // Invoke the billing flow | ||
| 71 | BillingFlowParams flowParams = BillingFlowParams.newBuilder() | ||
| 72 | .setSkuDetails(mSkuPremium) | ||
| 73 | .build(); | ||
| 74 | mBillingClient.launchBillingFlow(mActivity, flowParams); | ||
| 75 | } | ||
| 76 | |||
| 77 | private void updatePremiumState(boolean isPremiumActive) { | ||
| 78 | mIsPremiumActive = isPremiumActive; | ||
| 79 | |||
| 80 | // Cache state for synchronous UI | ||
| 81 | SharedPreferences.Editor editor = mPreferences.edit(); | ||
| 82 | editor.putBoolean(SettingsFile.KEY_PREMIUM, isPremiumActive); | ||
| 83 | editor.apply(); | ||
| 84 | |||
| 85 | // No need to show button in action bar if Premium is active | ||
| 86 | MainActivity.setPremiumButtonVisible(!isPremiumActive); | ||
| 87 | } | ||
| 88 | |||
| 89 | @Override | ||
| 90 | public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchaseList) { | ||
| 91 | if (purchaseList == null || purchaseList.isEmpty()) { | ||
| 92 | // Premium is not active, or billing is unavailable | ||
| 93 | updatePremiumState(false); | ||
| 94 | return; | ||
| 95 | } | ||
| 96 | |||
| 97 | Purchase premiumPurchase = null; | ||
| 98 | for (Purchase purchase : purchaseList) { | ||
| 99 | if (purchase.getSku().equals(BILLING_SKU_PREMIUM)) { | ||
| 100 | premiumPurchase = purchase; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | if (premiumPurchase != null && premiumPurchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { | ||
| 105 | // Premium has been purchased | ||
| 106 | updatePremiumState(true); | ||
| 107 | |||
| 108 | // Acknowledge the purchase if it hasn't already been acknowledged. | ||
| 109 | if (!premiumPurchase.isAcknowledged()) { | ||
| 110 | AcknowledgePurchaseParams acknowledgePurchaseParams = | ||
| 111 | AcknowledgePurchaseParams.newBuilder() | ||
| 112 | .setPurchaseToken(premiumPurchase.getPurchaseToken()) | ||
| 113 | .build(); | ||
| 114 | |||
| 115 | AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = billingResult1 -> { | ||
| 116 | Toast.makeText(mActivity, R.string.premium_settings_welcome, Toast.LENGTH_SHORT).show(); | ||
| 117 | }; | ||
| 118 | mBillingClient.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener); | ||
| 119 | } | ||
| 120 | |||
| 121 | if (mUpdateBillingCallback != null) { | ||
| 122 | try { | ||
| 123 | mUpdateBillingCallback.run(); | ||
| 124 | } catch (Exception e) { | ||
| 125 | e.printStackTrace(); | ||
| 126 | } | ||
| 127 | mUpdateBillingCallback = null; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | private void onQuerySkuDetailsFinished(List<SkuDetails> skuDetailsList) { | ||
| 133 | if (skuDetailsList == null) { | ||
| 134 | // This can happen when no user is signed in | ||
| 135 | return; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (skuDetailsList.isEmpty()) { | ||
| 139 | return; | ||
| 140 | } | ||
| 141 | |||
| 142 | mSkuPremium = skuDetailsList.get(0); | ||
| 143 | |||
| 144 | queryPurchases(); | ||
| 145 | } | ||
| 146 | |||
| 147 | private void querySkuDetails() { | ||
| 148 | Runnable queryToExecute = new Runnable() { | ||
| 149 | @Override | ||
| 150 | public void run() { | ||
| 151 | SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); | ||
| 152 | List<String> skuList = new ArrayList<>(); | ||
| 153 | |||
| 154 | skuList.add(BILLING_SKU_PREMIUM); | ||
| 155 | params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP); | ||
| 156 | |||
| 157 | mBillingClient.querySkuDetailsAsync(params.build(), | ||
| 158 | (billingResult, skuDetailsList) -> onQuerySkuDetailsFinished(skuDetailsList)); | ||
| 159 | } | ||
| 160 | }; | ||
| 161 | |||
| 162 | executeServiceRequest(queryToExecute); | ||
| 163 | } | ||
| 164 | |||
| 165 | private void onQueryPurchasesFinished(PurchasesResult result) { | ||
| 166 | // Have we been disposed of in the meantime? If so, or bad result code, then quit | ||
| 167 | if (mBillingClient == null || result.getResponseCode() != BillingClient.BillingResponseCode.OK) { | ||
| 168 | updatePremiumState(false); | ||
| 169 | return; | ||
| 170 | } | ||
| 171 | // Update the UI and purchases inventory with new list of purchases | ||
| 172 | onPurchasesUpdated(result.getBillingResult(), result.getPurchasesList()); | ||
| 173 | } | ||
| 174 | |||
| 175 | private void queryPurchases() { | ||
| 176 | Runnable queryToExecute = new Runnable() { | ||
| 177 | @Override | ||
| 178 | public void run() { | ||
| 179 | final PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP); | ||
| 180 | onQueryPurchasesFinished(purchasesResult); | ||
| 181 | } | ||
| 182 | }; | ||
| 183 | |||
| 184 | executeServiceRequest(queryToExecute); | ||
| 185 | } | ||
| 186 | |||
| 187 | private void startServiceConnection(final Runnable executeOnFinish) { | ||
| 188 | mBillingClient.startConnection(new BillingClientStateListener() { | ||
| 189 | @Override | ||
| 190 | public void onBillingSetupFinished(BillingResult billingResult) { | ||
| 191 | if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { | ||
| 192 | mIsServiceConnected = true; | ||
| 193 | } | ||
| 194 | |||
| 195 | if (executeOnFinish != null) { | ||
| 196 | executeOnFinish.run(); | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | @Override | ||
| 201 | public void onBillingServiceDisconnected() { | ||
| 202 | mIsServiceConnected = false; | ||
| 203 | } | ||
| 204 | }); | ||
| 205 | } | ||
| 206 | |||
| 207 | private void executeServiceRequest(Runnable runnable) { | ||
| 208 | if (mIsServiceConnected) { | ||
| 209 | runnable.run(); | ||
| 210 | } else { | ||
| 211 | // If billing service was disconnected, we try to reconnect 1 time. | ||
| 212 | startServiceConnection(runnable); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | } | ||
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index 373c0e8bd..e5c9d57f2 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt | |||
| @@ -1,4 +1,7 @@ | |||
| 1 | add_library(yuzu-android SHARED | 1 | add_library(yuzu-android SHARED |
| 2 | config.cpp | ||
| 3 | config.h | ||
| 4 | default_ini.h | ||
| 2 | emu_window/emu_window.cpp | 5 | emu_window/emu_window.cpp |
| 3 | emu_window/emu_window.h | 6 | emu_window/emu_window.h |
| 4 | id_cache.cpp | 7 | id_cache.cpp |
diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp new file mode 100644 index 000000000..326dab5fc --- /dev/null +++ b/src/android/app/src/main/jni/config.cpp | |||
| @@ -0,0 +1,284 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <memory> | ||
| 5 | #include <optional> | ||
| 6 | #include <sstream> | ||
| 7 | |||
| 8 | #include <INIReader.h> | ||
| 9 | #include "common/fs/file.h" | ||
| 10 | #include "common/fs/fs.h" | ||
| 11 | #include "common/fs/path_util.h" | ||
| 12 | #include "common/logging/log.h" | ||
| 13 | #include "common/settings.h" | ||
| 14 | #include "core/hle/service/acc/profile_manager.h" | ||
| 15 | #include "input_common/main.h" | ||
| 16 | #include "jni/config.h" | ||
| 17 | #include "jni/default_ini.h" | ||
| 18 | |||
| 19 | namespace FS = Common::FS; | ||
| 20 | |||
| 21 | const std::filesystem::path default_config_path = | ||
| 22 | FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "config.ini"; | ||
| 23 | |||
| 24 | Config::Config(std::optional<std::filesystem::path> config_path) | ||
| 25 | : config_loc{config_path.value_or(default_config_path)}, | ||
| 26 | config{std::make_unique<INIReader>(FS::PathToUTF8String(config_loc))} { | ||
| 27 | Reload(); | ||
| 28 | } | ||
| 29 | |||
| 30 | Config::~Config() = default; | ||
| 31 | |||
| 32 | bool Config::LoadINI(const std::string& default_contents, bool retry) { | ||
| 33 | const auto config_loc_str = FS::PathToUTF8String(config_loc); | ||
| 34 | if (config->ParseError() < 0) { | ||
| 35 | if (retry) { | ||
| 36 | LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", | ||
| 37 | config_loc_str); | ||
| 38 | |||
| 39 | void(FS::CreateParentDir(config_loc)); | ||
| 40 | void(FS::WriteStringToFile(config_loc, FS::FileType::TextFile, default_contents)); | ||
| 41 | |||
| 42 | config = std::make_unique<INIReader>(config_loc_str); | ||
| 43 | |||
| 44 | return LoadINI(default_contents, false); | ||
| 45 | } | ||
| 46 | LOG_ERROR(Config, "Failed."); | ||
| 47 | return false; | ||
| 48 | } | ||
| 49 | LOG_INFO(Config, "Successfully loaded {}", config_loc_str); | ||
| 50 | return true; | ||
| 51 | } | ||
| 52 | |||
| 53 | template <> | ||
| 54 | void Config::ReadSetting(const std::string& group, Settings::Setting<std::string>& setting) { | ||
| 55 | std::string setting_value = config->Get(group, setting.GetLabel(), setting.GetDefault()); | ||
| 56 | if (setting_value.empty()) { | ||
| 57 | setting_value = setting.GetDefault(); | ||
| 58 | } | ||
| 59 | setting = std::move(setting_value); | ||
| 60 | } | ||
| 61 | |||
| 62 | template <> | ||
| 63 | void Config::ReadSetting(const std::string& group, Settings::Setting<bool>& setting) { | ||
| 64 | setting = config->GetBoolean(group, setting.GetLabel(), setting.GetDefault()); | ||
| 65 | } | ||
| 66 | |||
| 67 | template <typename Type, bool ranged> | ||
| 68 | void Config::ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting) { | ||
| 69 | setting = static_cast<Type>(config->GetInteger(group, setting.GetLabel(), | ||
| 70 | static_cast<long>(setting.GetDefault()))); | ||
| 71 | } | ||
| 72 | |||
| 73 | void Config::ReadValues() { | ||
| 74 | ReadSetting("ControlsGeneral", Settings::values.mouse_enabled); | ||
| 75 | ReadSetting("ControlsGeneral", Settings::values.touch_device); | ||
| 76 | ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled); | ||
| 77 | ReadSetting("ControlsGeneral", Settings::values.debug_pad_enabled); | ||
| 78 | ReadSetting("ControlsGeneral", Settings::values.vibration_enabled); | ||
| 79 | ReadSetting("ControlsGeneral", Settings::values.enable_accurate_vibrations); | ||
| 80 | ReadSetting("ControlsGeneral", Settings::values.motion_enabled); | ||
| 81 | Settings::values.touchscreen.enabled = | ||
| 82 | config->GetBoolean("ControlsGeneral", "touch_enabled", true); | ||
| 83 | Settings::values.touchscreen.rotation_angle = | ||
| 84 | config->GetInteger("ControlsGeneral", "touch_angle", 0); | ||
| 85 | Settings::values.touchscreen.diameter_x = | ||
| 86 | config->GetInteger("ControlsGeneral", "touch_diameter_x", 15); | ||
| 87 | Settings::values.touchscreen.diameter_y = | ||
| 88 | config->GetInteger("ControlsGeneral", "touch_diameter_y", 15); | ||
| 89 | |||
| 90 | int num_touch_from_button_maps = | ||
| 91 | config->GetInteger("ControlsGeneral", "touch_from_button_map", 0); | ||
| 92 | if (num_touch_from_button_maps > 0) { | ||
| 93 | for (int i = 0; i < num_touch_from_button_maps; ++i) { | ||
| 94 | Settings::TouchFromButtonMap map; | ||
| 95 | map.name = config->Get("ControlsGeneral", | ||
| 96 | std::string("touch_from_button_maps_") + std::to_string(i) + | ||
| 97 | std::string("_name"), | ||
| 98 | "default"); | ||
| 99 | const int num_touch_maps = config->GetInteger( | ||
| 100 | "ControlsGeneral", | ||
| 101 | std::string("touch_from_button_maps_") + std::to_string(i) + std::string("_count"), | ||
| 102 | 0); | ||
| 103 | map.buttons.reserve(num_touch_maps); | ||
| 104 | |||
| 105 | for (int j = 0; j < num_touch_maps; ++j) { | ||
| 106 | std::string touch_mapping = | ||
| 107 | config->Get("ControlsGeneral", | ||
| 108 | std::string("touch_from_button_maps_") + std::to_string(i) + | ||
| 109 | std::string("_bind_") + std::to_string(j), | ||
| 110 | ""); | ||
| 111 | map.buttons.emplace_back(std::move(touch_mapping)); | ||
| 112 | } | ||
| 113 | |||
| 114 | Settings::values.touch_from_button_maps.emplace_back(std::move(map)); | ||
| 115 | } | ||
| 116 | } else { | ||
| 117 | Settings::values.touch_from_button_maps.emplace_back( | ||
| 118 | Settings::TouchFromButtonMap{"default", {}}); | ||
| 119 | num_touch_from_button_maps = 1; | ||
| 120 | } | ||
| 121 | Settings::values.touch_from_button_map_index = std::clamp( | ||
| 122 | Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); | ||
| 123 | |||
| 124 | ReadSetting("ControlsGeneral", Settings::values.udp_input_servers); | ||
| 125 | |||
| 126 | // Data Storage | ||
| 127 | ReadSetting("Data Storage", Settings::values.use_virtual_sd); | ||
| 128 | FS::SetYuzuPath(FS::YuzuPath::NANDDir, | ||
| 129 | config->Get("Data Storage", "nand_directory", | ||
| 130 | FS::GetYuzuPathString(FS::YuzuPath::NANDDir))); | ||
| 131 | FS::SetYuzuPath(FS::YuzuPath::SDMCDir, | ||
| 132 | config->Get("Data Storage", "sdmc_directory", | ||
| 133 | FS::GetYuzuPathString(FS::YuzuPath::SDMCDir))); | ||
| 134 | FS::SetYuzuPath(FS::YuzuPath::LoadDir, | ||
| 135 | config->Get("Data Storage", "load_directory", | ||
| 136 | FS::GetYuzuPathString(FS::YuzuPath::LoadDir))); | ||
| 137 | FS::SetYuzuPath(FS::YuzuPath::DumpDir, | ||
| 138 | config->Get("Data Storage", "dump_directory", | ||
| 139 | FS::GetYuzuPathString(FS::YuzuPath::DumpDir))); | ||
| 140 | ReadSetting("Data Storage", Settings::values.gamecard_inserted); | ||
| 141 | ReadSetting("Data Storage", Settings::values.gamecard_current_game); | ||
| 142 | ReadSetting("Data Storage", Settings::values.gamecard_path); | ||
| 143 | |||
| 144 | // System | ||
| 145 | ReadSetting("System", Settings::values.use_docked_mode); | ||
| 146 | |||
| 147 | ReadSetting("System", Settings::values.current_user); | ||
| 148 | Settings::values.current_user = std::clamp<int>(Settings::values.current_user.GetValue(), 0, | ||
| 149 | Service::Account::MAX_USERS - 1); | ||
| 150 | |||
| 151 | const auto rng_seed_enabled = config->GetBoolean("System", "rng_seed_enabled", false); | ||
| 152 | if (rng_seed_enabled) { | ||
| 153 | Settings::values.rng_seed.SetValue(config->GetInteger("System", "rng_seed", 0)); | ||
| 154 | } else { | ||
| 155 | Settings::values.rng_seed.SetValue(std::nullopt); | ||
| 156 | } | ||
| 157 | |||
| 158 | const auto custom_rtc_enabled = config->GetBoolean("System", "custom_rtc_enabled", false); | ||
| 159 | if (custom_rtc_enabled) { | ||
| 160 | Settings::values.custom_rtc = config->GetInteger("System", "custom_rtc", 0); | ||
| 161 | } else { | ||
| 162 | Settings::values.custom_rtc = std::nullopt; | ||
| 163 | } | ||
| 164 | |||
| 165 | ReadSetting("System", Settings::values.language_index); | ||
| 166 | ReadSetting("System", Settings::values.region_index); | ||
| 167 | ReadSetting("System", Settings::values.time_zone_index); | ||
| 168 | ReadSetting("System", Settings::values.sound_index); | ||
| 169 | |||
| 170 | // Core | ||
| 171 | ReadSetting("Core", Settings::values.use_multi_core); | ||
| 172 | ReadSetting("Core", Settings::values.use_unsafe_extended_memory_layout); | ||
| 173 | |||
| 174 | // Cpu | ||
| 175 | ReadSetting("Cpu", Settings::values.cpu_accuracy); | ||
| 176 | ReadSetting("Cpu", Settings::values.cpu_debug_mode); | ||
| 177 | ReadSetting("Cpu", Settings::values.cpuopt_page_tables); | ||
| 178 | ReadSetting("Cpu", Settings::values.cpuopt_block_linking); | ||
| 179 | ReadSetting("Cpu", Settings::values.cpuopt_return_stack_buffer); | ||
| 180 | ReadSetting("Cpu", Settings::values.cpuopt_fast_dispatcher); | ||
| 181 | ReadSetting("Cpu", Settings::values.cpuopt_context_elimination); | ||
| 182 | ReadSetting("Cpu", Settings::values.cpuopt_const_prop); | ||
| 183 | ReadSetting("Cpu", Settings::values.cpuopt_misc_ir); | ||
| 184 | ReadSetting("Cpu", Settings::values.cpuopt_reduce_misalign_checks); | ||
| 185 | ReadSetting("Cpu", Settings::values.cpuopt_fastmem); | ||
| 186 | ReadSetting("Cpu", Settings::values.cpuopt_fastmem_exclusives); | ||
| 187 | ReadSetting("Cpu", Settings::values.cpuopt_recompile_exclusives); | ||
| 188 | ReadSetting("Cpu", Settings::values.cpuopt_ignore_memory_aborts); | ||
| 189 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_unfuse_fma); | ||
| 190 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_reduce_fp_error); | ||
| 191 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_standard_fpcr); | ||
| 192 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_inaccurate_nan); | ||
| 193 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_fastmem_check); | ||
| 194 | ReadSetting("Cpu", Settings::values.cpuopt_unsafe_ignore_global_monitor); | ||
| 195 | |||
| 196 | // Renderer | ||
| 197 | ReadSetting("Renderer", Settings::values.renderer_backend); | ||
| 198 | ReadSetting("Renderer", Settings::values.renderer_force_max_clock); | ||
| 199 | ReadSetting("Renderer", Settings::values.renderer_debug); | ||
| 200 | ReadSetting("Renderer", Settings::values.renderer_shader_feedback); | ||
| 201 | ReadSetting("Renderer", Settings::values.enable_nsight_aftermath); | ||
| 202 | ReadSetting("Renderer", Settings::values.disable_shader_loop_safety_checks); | ||
| 203 | ReadSetting("Renderer", Settings::values.vulkan_device); | ||
| 204 | |||
| 205 | ReadSetting("Renderer", Settings::values.resolution_setup); | ||
| 206 | ReadSetting("Renderer", Settings::values.scaling_filter); | ||
| 207 | ReadSetting("Renderer", Settings::values.fsr_sharpening_slider); | ||
| 208 | ReadSetting("Renderer", Settings::values.anti_aliasing); | ||
| 209 | ReadSetting("Renderer", Settings::values.fullscreen_mode); | ||
| 210 | ReadSetting("Renderer", Settings::values.aspect_ratio); | ||
| 211 | ReadSetting("Renderer", Settings::values.max_anisotropy); | ||
| 212 | ReadSetting("Renderer", Settings::values.use_speed_limit); | ||
| 213 | ReadSetting("Renderer", Settings::values.speed_limit); | ||
| 214 | ReadSetting("Renderer", Settings::values.use_disk_shader_cache); | ||
| 215 | ReadSetting("Renderer", Settings::values.gpu_accuracy); | ||
| 216 | ReadSetting("Renderer", Settings::values.use_asynchronous_gpu_emulation); | ||
| 217 | ReadSetting("Renderer", Settings::values.vsync_mode); | ||
| 218 | ReadSetting("Renderer", Settings::values.shader_backend); | ||
| 219 | ReadSetting("Renderer", Settings::values.use_asynchronous_shaders); | ||
| 220 | ReadSetting("Renderer", Settings::values.nvdec_emulation); | ||
| 221 | ReadSetting("Renderer", Settings::values.accelerate_astc); | ||
| 222 | ReadSetting("Renderer", Settings::values.use_fast_gpu_time); | ||
| 223 | ReadSetting("Renderer", Settings::values.use_vulkan_driver_pipeline_cache); | ||
| 224 | |||
| 225 | ReadSetting("Renderer", Settings::values.bg_red); | ||
| 226 | ReadSetting("Renderer", Settings::values.bg_green); | ||
| 227 | ReadSetting("Renderer", Settings::values.bg_blue); | ||
| 228 | |||
| 229 | // Audio | ||
| 230 | ReadSetting("Audio", Settings::values.sink_id); | ||
| 231 | ReadSetting("Audio", Settings::values.audio_output_device_id); | ||
| 232 | ReadSetting("Audio", Settings::values.volume); | ||
| 233 | |||
| 234 | // Miscellaneous | ||
| 235 | // log_filter has a different default here than from common | ||
| 236 | Settings::values.log_filter = "*:Info"; | ||
| 237 | ReadSetting("Miscellaneous", Settings::values.use_dev_keys); | ||
| 238 | |||
| 239 | // Debugging | ||
| 240 | Settings::values.record_frame_times = | ||
| 241 | config->GetBoolean("Debugging", "record_frame_times", false); | ||
| 242 | ReadSetting("Debugging", Settings::values.dump_exefs); | ||
| 243 | ReadSetting("Debugging", Settings::values.dump_nso); | ||
| 244 | ReadSetting("Debugging", Settings::values.enable_fs_access_log); | ||
| 245 | ReadSetting("Debugging", Settings::values.reporting_services); | ||
| 246 | ReadSetting("Debugging", Settings::values.quest_flag); | ||
| 247 | ReadSetting("Debugging", Settings::values.use_debug_asserts); | ||
| 248 | ReadSetting("Debugging", Settings::values.use_auto_stub); | ||
| 249 | ReadSetting("Debugging", Settings::values.disable_macro_jit); | ||
| 250 | ReadSetting("Debugging", Settings::values.disable_macro_hle); | ||
| 251 | ReadSetting("Debugging", Settings::values.use_gdbstub); | ||
| 252 | ReadSetting("Debugging", Settings::values.gdbstub_port); | ||
| 253 | |||
| 254 | const auto title_list = config->Get("AddOns", "title_ids", ""); | ||
| 255 | std::stringstream ss(title_list); | ||
| 256 | std::string line; | ||
| 257 | while (std::getline(ss, line, '|')) { | ||
| 258 | const auto title_id = std::stoul(line, nullptr, 16); | ||
| 259 | const auto disabled_list = config->Get("AddOns", "disabled_" + line, ""); | ||
| 260 | |||
| 261 | std::stringstream inner_ss(disabled_list); | ||
| 262 | std::string inner_line; | ||
| 263 | std::vector<std::string> out; | ||
| 264 | while (std::getline(inner_ss, inner_line, '|')) { | ||
| 265 | out.push_back(inner_line); | ||
| 266 | } | ||
| 267 | |||
| 268 | Settings::values.disabled_addons.insert_or_assign(title_id, out); | ||
| 269 | } | ||
| 270 | |||
| 271 | // Web Service | ||
| 272 | ReadSetting("WebService", Settings::values.enable_telemetry); | ||
| 273 | ReadSetting("WebService", Settings::values.web_api_url); | ||
| 274 | ReadSetting("WebService", Settings::values.yuzu_username); | ||
| 275 | ReadSetting("WebService", Settings::values.yuzu_token); | ||
| 276 | |||
| 277 | // Network | ||
| 278 | ReadSetting("Network", Settings::values.network_interface); | ||
| 279 | } | ||
| 280 | |||
| 281 | void Config::Reload() { | ||
| 282 | LoadINI(DefaultINI::android_config_file); | ||
| 283 | ReadValues(); | ||
| 284 | } | ||
diff --git a/src/android/app/src/main/jni/config.h b/src/android/app/src/main/jni/config.h new file mode 100644 index 000000000..0d7d6e94d --- /dev/null +++ b/src/android/app/src/main/jni/config.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <filesystem> | ||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | #include <string> | ||
| 10 | |||
| 11 | #include "common/settings.h" | ||
| 12 | |||
| 13 | class INIReader; | ||
| 14 | |||
| 15 | class Config { | ||
| 16 | std::filesystem::path config_loc; | ||
| 17 | std::unique_ptr<INIReader> config; | ||
| 18 | |||
| 19 | bool LoadINI(const std::string& default_contents = "", bool retry = true); | ||
| 20 | void ReadValues(); | ||
| 21 | |||
| 22 | public: | ||
| 23 | explicit Config(std::optional<std::filesystem::path> config_path = std::nullopt); | ||
| 24 | ~Config(); | ||
| 25 | |||
| 26 | void Reload(); | ||
| 27 | |||
| 28 | private: | ||
| 29 | /** | ||
| 30 | * Applies a value read from the sdl2_config to a Setting. | ||
| 31 | * | ||
| 32 | * @param group The name of the INI group | ||
| 33 | * @param setting The yuzu setting to modify | ||
| 34 | */ | ||
| 35 | template <typename Type, bool ranged> | ||
| 36 | void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting); | ||
| 37 | }; | ||
diff --git a/src/android/app/src/main/jni/default_ini.h b/src/android/app/src/main/jni/default_ini.h new file mode 100644 index 000000000..60db951c8 --- /dev/null +++ b/src/android/app/src/main/jni/default_ini.h | |||
| @@ -0,0 +1,499 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | namespace DefaultINI { | ||
| 7 | |||
| 8 | const char* android_config_file = R"( | ||
| 9 | |||
| 10 | [ControlsP0] | ||
| 11 | # The input devices and parameters for each Switch native input | ||
| 12 | # The config section determines the player number where the config will be applied on. For example "ControlsP0", "ControlsP1", ... | ||
| 13 | # It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." | ||
| 14 | # Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values | ||
| 15 | |||
| 16 | # Indicates if this player should be connected at boot | ||
| 17 | connected= | ||
| 18 | |||
| 19 | # for button input, the following devices are available: | ||
| 20 | # - "keyboard" (default) for keyboard input. Required parameters: | ||
| 21 | # - "code": the code of the key to bind | ||
| 22 | # - "sdl" for joystick input using SDL. Required parameters: | ||
| 23 | # - "guid": SDL identification GUID of the joystick | ||
| 24 | # - "port": the index of the joystick to bind | ||
| 25 | # - "button"(optional): the index of the button to bind | ||
| 26 | # - "hat"(optional): the index of the hat to bind as direction buttons | ||
| 27 | # - "axis"(optional): the index of the axis to bind | ||
| 28 | # - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" | ||
| 29 | # - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is | ||
| 30 | # triggered if the axis value crosses | ||
| 31 | # - "direction"(only used for axis): "+" means the button is triggered when the axis value | ||
| 32 | # is greater than the threshold; "-" means the button is triggered when the axis value | ||
| 33 | # is smaller than the threshold | ||
| 34 | button_a= | ||
| 35 | button_b= | ||
| 36 | button_x= | ||
| 37 | button_y= | ||
| 38 | button_lstick= | ||
| 39 | button_rstick= | ||
| 40 | button_l= | ||
| 41 | button_r= | ||
| 42 | button_zl= | ||
| 43 | button_zr= | ||
| 44 | button_plus= | ||
| 45 | button_minus= | ||
| 46 | button_dleft= | ||
| 47 | button_dup= | ||
| 48 | button_dright= | ||
| 49 | button_ddown= | ||
| 50 | button_lstick_left= | ||
| 51 | button_lstick_up= | ||
| 52 | button_lstick_right= | ||
| 53 | button_lstick_down= | ||
| 54 | button_sl= | ||
| 55 | button_sr= | ||
| 56 | button_home= | ||
| 57 | button_screenshot= | ||
| 58 | |||
| 59 | # for analog input, the following devices are available: | ||
| 60 | # - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: | ||
| 61 | # - "up", "down", "left", "right": sub-devices for each direction. | ||
| 62 | # Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" | ||
| 63 | # - "modifier": sub-devices as a modifier. | ||
| 64 | # - "modifier_scale": a float number representing the applied modifier scale to the analog input. | ||
| 65 | # Must be in range of 0.0-1.0. Defaults to 0.5 | ||
| 66 | # - "sdl" for joystick input using SDL. Required parameters: | ||
| 67 | # - "guid": SDL identification GUID of the joystick | ||
| 68 | # - "port": the index of the joystick to bind | ||
| 69 | # - "axis_x": the index of the axis to bind as x-axis (default to 0) | ||
| 70 | # - "axis_y": the index of the axis to bind as y-axis (default to 1) | ||
| 71 | lstick= | ||
| 72 | rstick= | ||
| 73 | |||
| 74 | # for motion input, the following devices are available: | ||
| 75 | # - "keyboard" (default) for emulating random motion input from buttons. Required parameters: | ||
| 76 | # - "code": the code of the key to bind | ||
| 77 | # - "sdl" for motion input using SDL. Required parameters: | ||
| 78 | # - "guid": SDL identification GUID of the joystick | ||
| 79 | # - "port": the index of the joystick to bind | ||
| 80 | # - "motion": the index of the motion sensor to bind | ||
| 81 | # - "cemuhookudp" for motion input using Cemu Hook protocol. Required parameters: | ||
| 82 | # - "guid": the IP address of the cemu hook server encoded to a hex string. for example 192.168.0.1 = "c0a80001" | ||
| 83 | # - "port": the port of the cemu hook server | ||
| 84 | # - "pad": the index of the joystick | ||
| 85 | # - "motion": the index of the motion sensor of the joystick to bind | ||
| 86 | motionleft= | ||
| 87 | motionright= | ||
| 88 | |||
| 89 | [ControlsGeneral] | ||
| 90 | # To use the debug_pad, prepend `debug_pad_` before each button setting above. | ||
| 91 | # i.e. debug_pad_button_a= | ||
| 92 | |||
| 93 | # Enable debug pad inputs to the guest | ||
| 94 | # 0 (default): Disabled, 1: Enabled | ||
| 95 | debug_pad_enabled = | ||
| 96 | |||
| 97 | # Whether to enable or disable vibration | ||
| 98 | # 0: Disabled, 1 (default): Enabled | ||
| 99 | vibration_enabled= | ||
| 100 | |||
| 101 | # Whether to enable or disable accurate vibrations | ||
| 102 | # 0 (default): Disabled, 1: Enabled | ||
| 103 | enable_accurate_vibrations= | ||
| 104 | |||
| 105 | # Enables controller motion inputs | ||
| 106 | # 0: Disabled, 1 (default): Enabled | ||
| 107 | motion_enabled = | ||
| 108 | |||
| 109 | # Defines the udp device's touch screen coordinate system for cemuhookudp devices | ||
| 110 | # - "min_x", "min_y", "max_x", "max_y" | ||
| 111 | touch_device= | ||
| 112 | |||
| 113 | # for mapping buttons to touch inputs. | ||
| 114 | #touch_from_button_map=1 | ||
| 115 | #touch_from_button_maps_0_name=default | ||
| 116 | #touch_from_button_maps_0_count=2 | ||
| 117 | #touch_from_button_maps_0_bind_0=foo | ||
| 118 | #touch_from_button_maps_0_bind_1=bar | ||
| 119 | # etc. | ||
| 120 | |||
| 121 | # List of Cemuhook UDP servers, delimited by ','. | ||
| 122 | # Default: 127.0.0.1:26760 | ||
| 123 | # Example: 127.0.0.1:26760,123.4.5.67:26761 | ||
| 124 | udp_input_servers = | ||
| 125 | |||
| 126 | # Enable controlling an axis via a mouse input. | ||
| 127 | # 0 (default): Off, 1: On | ||
| 128 | mouse_panning = | ||
| 129 | |||
| 130 | # Set mouse sensitivity. | ||
| 131 | # Default: 1.0 | ||
| 132 | mouse_panning_sensitivity = | ||
| 133 | |||
| 134 | # Emulate an analog control stick from keyboard inputs. | ||
| 135 | # 0 (default): Disabled, 1: Enabled | ||
| 136 | emulate_analog_keyboard = | ||
| 137 | |||
| 138 | # Enable mouse inputs to the guest | ||
| 139 | # 0 (default): Disabled, 1: Enabled | ||
| 140 | mouse_enabled = | ||
| 141 | |||
| 142 | # Enable keyboard inputs to the guest | ||
| 143 | # 0 (default): Disabled, 1: Enabled | ||
| 144 | keyboard_enabled = | ||
| 145 | |||
| 146 | [Core] | ||
| 147 | # Whether to use multi-core for CPU emulation | ||
| 148 | # 0: Disabled, 1 (default): Enabled | ||
| 149 | use_multi_core = | ||
| 150 | |||
| 151 | # Enable unsafe extended guest system memory layout (8GB DRAM) | ||
| 152 | # 0 (default): Disabled, 1: Enabled | ||
| 153 | use_unsafe_extended_memory_layout = | ||
| 154 | |||
| 155 | [Cpu] | ||
| 156 | # Adjusts various optimizations. | ||
| 157 | # Auto-select mode enables choice unsafe optimizations. | ||
| 158 | # Accurate enables only safe optimizations. | ||
| 159 | # Unsafe allows any unsafe optimizations. | ||
| 160 | # 0 (default): Auto-select, 1: Accurate, 2: Enable unsafe optimizations | ||
| 161 | cpu_accuracy = | ||
| 162 | |||
| 163 | # Allow disabling safe optimizations. | ||
| 164 | # 0 (default): Disabled, 1: Enabled | ||
| 165 | cpu_debug_mode = | ||
| 166 | |||
| 167 | # Enable inline page tables optimization (faster guest memory access) | ||
| 168 | # 0: Disabled, 1 (default): Enabled | ||
| 169 | cpuopt_page_tables = | ||
| 170 | |||
| 171 | # Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) | ||
| 172 | # 0: Disabled, 1 (default): Enabled | ||
| 173 | cpuopt_block_linking = | ||
| 174 | |||
| 175 | # Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) | ||
| 176 | # 0: Disabled, 1 (default): Enabled | ||
| 177 | cpuopt_return_stack_buffer = | ||
| 178 | |||
| 179 | # Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) | ||
| 180 | # 0: Disabled, 1 (default): Enabled | ||
| 181 | cpuopt_fast_dispatcher = | ||
| 182 | |||
| 183 | # Enable context elimination CPU Optimization (reduce host memory use for guest context) | ||
| 184 | # 0: Disabled, 1 (default): Enabled | ||
| 185 | cpuopt_context_elimination = | ||
| 186 | |||
| 187 | # Enable constant propagation CPU optimization (basic IR optimization) | ||
| 188 | # 0: Disabled, 1 (default): Enabled | ||
| 189 | cpuopt_const_prop = | ||
| 190 | |||
| 191 | # Enable miscellaneous CPU optimizations (basic IR optimization) | ||
| 192 | # 0: Disabled, 1 (default): Enabled | ||
| 193 | cpuopt_misc_ir = | ||
| 194 | |||
| 195 | # Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) | ||
| 196 | # 0: Disabled, 1 (default): Enabled | ||
| 197 | cpuopt_reduce_misalign_checks = | ||
| 198 | |||
| 199 | # Enable Host MMU Emulation (faster guest memory access) | ||
| 200 | # 0: Disabled, 1 (default): Enabled | ||
| 201 | cpuopt_fastmem = | ||
| 202 | |||
| 203 | # Enable Host MMU Emulation for exclusive memory instructions (faster guest memory access) | ||
| 204 | # 0: Disabled, 1 (default): Enabled | ||
| 205 | cpuopt_fastmem_exclusives = | ||
| 206 | |||
| 207 | # Enable fallback on failure of fastmem of exclusive memory instructions (faster guest memory access) | ||
| 208 | # 0: Disabled, 1 (default): Enabled | ||
| 209 | cpuopt_recompile_exclusives = | ||
| 210 | |||
| 211 | # Enable optimization to ignore invalid memory accesses (faster guest memory access) | ||
| 212 | # 0: Disabled, 1 (default): Enabled | ||
| 213 | cpuopt_ignore_memory_aborts = | ||
| 214 | |||
| 215 | # Enable unfuse FMA (improve performance on CPUs without FMA) | ||
| 216 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 217 | # 0: Disabled, 1 (default): Enabled | ||
| 218 | cpuopt_unsafe_unfuse_fma = | ||
| 219 | |||
| 220 | # Enable faster FRSQRTE and FRECPE | ||
| 221 | # Only enabled if cpu_accuracy is set to Unsafe. | ||
| 222 | # 0: Disabled, 1 (default): Enabled | ||
| 223 | cpuopt_unsafe_reduce_fp_error = | ||
| 224 | |||
| 225 | # Enable faster ASIMD instructions (32 bits only) | ||
| 226 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 227 | # 0: Disabled, 1 (default): Enabled | ||
| 228 | cpuopt_unsafe_ignore_standard_fpcr = | ||
| 229 | |||
| 230 | # Enable inaccurate NaN handling | ||
| 231 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 232 | # 0: Disabled, 1 (default): Enabled | ||
| 233 | cpuopt_unsafe_inaccurate_nan = | ||
| 234 | |||
| 235 | # Disable address space checks (64 bits only) | ||
| 236 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 237 | # 0: Disabled, 1 (default): Enabled | ||
| 238 | cpuopt_unsafe_fastmem_check = | ||
| 239 | |||
| 240 | # Enable faster exclusive instructions | ||
| 241 | # Only enabled if cpu_accuracy is set to Unsafe. Automatically chosen with cpu_accuracy = Auto-select. | ||
| 242 | # 0: Disabled, 1 (default): Enabled | ||
| 243 | cpuopt_unsafe_ignore_global_monitor = | ||
| 244 | |||
| 245 | [Renderer] | ||
| 246 | # Which backend API to use. | ||
| 247 | # 0: OpenGL (unsupported), 1 (default): Vulkan, 2: Null | ||
| 248 | backend = | ||
| 249 | |||
| 250 | # Enable graphics API debugging mode. | ||
| 251 | # 0 (default): Disabled, 1: Enabled | ||
| 252 | debug = | ||
| 253 | |||
| 254 | # Enable shader feedback. | ||
| 255 | # 0 (default): Disabled, 1: Enabled | ||
| 256 | renderer_shader_feedback = | ||
| 257 | |||
| 258 | # Enable Nsight Aftermath crash dumps | ||
| 259 | # 0 (default): Disabled, 1: Enabled | ||
| 260 | nsight_aftermath = | ||
| 261 | |||
| 262 | # Disable shader loop safety checks, executing the shader without loop logic changes | ||
| 263 | # 0 (default): Disabled, 1: Enabled | ||
| 264 | disable_shader_loop_safety_checks = | ||
| 265 | |||
| 266 | # Which Vulkan physical device to use (defaults to 0) | ||
| 267 | vulkan_device = | ||
| 268 | |||
| 269 | # 0: 0.5x (360p/540p) [EXPERIMENTAL] | ||
| 270 | # 1: 0.75x (540p/810p) [EXPERIMENTAL] | ||
| 271 | # 2 (default): 1x (720p/1080p) | ||
| 272 | # 3: 2x (1440p/2160p) | ||
| 273 | # 4: 3x (2160p/3240p) | ||
| 274 | # 5: 4x (2880p/4320p) | ||
| 275 | # 6: 5x (3600p/5400p) | ||
| 276 | # 7: 6x (4320p/6480p) | ||
| 277 | resolution_setup = | ||
| 278 | |||
| 279 | # Pixel filter to use when up- or down-sampling rendered frames. | ||
| 280 | # 0: Nearest Neighbor | ||
| 281 | # 1 (default): Bilinear | ||
| 282 | # 2: Bicubic | ||
| 283 | # 3: Gaussian | ||
| 284 | # 4: ScaleForce | ||
| 285 | # 5: AMD FidelityFX™️ Super Resolution [Vulkan Only] | ||
| 286 | scaling_filter = | ||
| 287 | |||
| 288 | # Anti-Aliasing (AA) | ||
| 289 | # 0 (default): None, 1: FXAA | ||
| 290 | anti_aliasing = | ||
| 291 | |||
| 292 | # Whether to use fullscreen or borderless window mode | ||
| 293 | # 0 (Windows default): Borderless window, 1 (All other default): Exclusive fullscreen | ||
| 294 | fullscreen_mode = | ||
| 295 | |||
| 296 | # Aspect ratio | ||
| 297 | # 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Stretch to Window | ||
| 298 | aspect_ratio = | ||
| 299 | |||
| 300 | # Anisotropic filtering | ||
| 301 | # 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x | ||
| 302 | max_anisotropy = | ||
| 303 | |||
| 304 | # Whether to enable VSync or not. | ||
| 305 | # OpenGL: Values other than 0 enable VSync | ||
| 306 | # Vulkan: FIFO is selected if the requested mode is not supported by the driver. | ||
| 307 | # FIFO (VSync) does not drop frames or exhibit tearing but is limited by the screen refresh rate. | ||
| 308 | # FIFO Relaxed is similar to FIFO but allows tearing as it recovers from a slow down. | ||
| 309 | # Mailbox can have lower latency than FIFO and does not tear but may drop frames. | ||
| 310 | # Immediate (no synchronization) just presents whatever is available and can exhibit tearing. | ||
| 311 | # 0: Immediate (Off), 1: Mailbox, 2 (Default): FIFO (On), 3: FIFO Relaxed | ||
| 312 | use_vsync = | ||
| 313 | |||
| 314 | # Selects the OpenGL shader backend. NV_gpu_program5 is required for GLASM. If NV_gpu_program5 is | ||
| 315 | # not available and GLASM is selected, GLSL will be used. | ||
| 316 | # 0: GLSL, 1 (default): GLASM, 2: SPIR-V | ||
| 317 | shader_backend = | ||
| 318 | |||
| 319 | # Whether to allow asynchronous shader building. | ||
| 320 | # 0 (default): Off, 1: On | ||
| 321 | use_asynchronous_shaders = | ||
| 322 | |||
| 323 | # NVDEC emulation. | ||
| 324 | # 0: Disabled, 1: CPU Decoding, 2 (default): GPU Decoding | ||
| 325 | nvdec_emulation = | ||
| 326 | |||
| 327 | # Accelerate ASTC texture decoding. | ||
| 328 | # 0: Off, 1 (default): On | ||
| 329 | accelerate_astc = | ||
| 330 | |||
| 331 | # Turns on the speed limiter, which will limit the emulation speed to the desired speed limit value | ||
| 332 | # 0: Off, 1: On (default) | ||
| 333 | use_speed_limit = | ||
| 334 | |||
| 335 | # Limits the speed of the game to run no faster than this value as a percentage of target speed | ||
| 336 | # 1 - 9999: Speed limit as a percentage of target game speed. 100 (default) | ||
| 337 | speed_limit = | ||
| 338 | |||
| 339 | # Whether to use disk based shader cache | ||
| 340 | # 0: Off, 1 (default): On | ||
| 341 | use_disk_shader_cache = | ||
| 342 | |||
| 343 | # Which gpu accuracy level to use | ||
| 344 | # 0: Normal, 1 (default): High, 2: Extreme (Very slow) | ||
| 345 | gpu_accuracy = | ||
| 346 | |||
| 347 | # Whether to use asynchronous GPU emulation | ||
| 348 | # 0 : Off (slow), 1 (default): On (fast) | ||
| 349 | use_asynchronous_gpu_emulation = | ||
| 350 | |||
| 351 | # Inform the guest that GPU operations completed more quickly than they did. | ||
| 352 | # 0: Off, 1 (default): On | ||
| 353 | use_fast_gpu_time = | ||
| 354 | |||
| 355 | # Force unmodified buffers to be flushed, which can cost performance. | ||
| 356 | # 0: Off (default), 1: On | ||
| 357 | use_pessimistic_flushes = | ||
| 358 | |||
| 359 | # Whether to use garbage collection or not for GPU caches. | ||
| 360 | # 0 (default): Off, 1: On | ||
| 361 | use_caches_gc = | ||
| 362 | |||
| 363 | # The clear color for the renderer. What shows up on the sides of the bottom screen. | ||
| 364 | # Must be in range of 0-255. Defaults to 0 for all. | ||
| 365 | bg_red = | ||
| 366 | bg_blue = | ||
| 367 | bg_green = | ||
| 368 | |||
| 369 | [Audio] | ||
| 370 | # Which audio output engine to use. | ||
| 371 | # auto (default): Auto-select | ||
| 372 | # cubeb: Cubeb audio engine (if available) | ||
| 373 | # sdl2: SDL2 audio engine (if available) | ||
| 374 | # null: No audio output | ||
| 375 | output_engine = | ||
| 376 | |||
| 377 | # Which audio device to use. | ||
| 378 | # auto (default): Auto-select | ||
| 379 | output_device = | ||
| 380 | |||
| 381 | # Output volume. | ||
| 382 | # 100 (default): 100%, 0; mute | ||
| 383 | volume = | ||
| 384 | |||
| 385 | [Data Storage] | ||
| 386 | # Whether to create a virtual SD card. | ||
| 387 | # 1 (default): Yes, 0: No | ||
| 388 | use_virtual_sd = | ||
| 389 | |||
| 390 | # Whether or not to enable gamecard emulation | ||
| 391 | # 1: Yes, 0 (default): No | ||
| 392 | gamecard_inserted = | ||
| 393 | |||
| 394 | # Whether or not the gamecard should be emulated as the current game | ||
| 395 | # If 'gamecard_inserted' is 0 this setting is irrelevant | ||
| 396 | # 1: Yes, 0 (default): No | ||
| 397 | gamecard_current_game = | ||
| 398 | |||
| 399 | # Path to an XCI file to use as the gamecard | ||
| 400 | # If 'gamecard_inserted' is 0 this setting is irrelevant | ||
| 401 | # If 'gamecard_current_game' is 1 this setting is irrelevant | ||
| 402 | gamecard_path = | ||
| 403 | |||
| 404 | [System] | ||
| 405 | # Whether the system is docked | ||
| 406 | # 1 (default): Yes, 0: No | ||
| 407 | use_docked_mode = | ||
| 408 | |||
| 409 | # Sets the seed for the RNG generator built into the switch | ||
| 410 | # rng_seed will be ignored and randomly generated if rng_seed_enabled is false | ||
| 411 | rng_seed_enabled = | ||
| 412 | rng_seed = | ||
| 413 | |||
| 414 | # Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service | ||
| 415 | # This will auto-increment, with the time set being the time the game is started | ||
| 416 | # This override will only occur if custom_rtc_enabled is true, otherwise the current time is used | ||
| 417 | custom_rtc_enabled = | ||
| 418 | custom_rtc = | ||
| 419 | |||
| 420 | # Sets the systems language index | ||
| 421 | # 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, | ||
| 422 | # 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, | ||
| 423 | # 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese, 17: Brazilian Portuguese | ||
| 424 | language_index = | ||
| 425 | |||
| 426 | # The system region that yuzu will use during emulation | ||
| 427 | # -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan | ||
| 428 | region_index = | ||
| 429 | |||
| 430 | # The system time zone that yuzu will use during emulation | ||
| 431 | # 0: Auto-select (default), 1: Default (system archive value), Others: Index for specified time zone | ||
| 432 | time_zone_index = | ||
| 433 | |||
| 434 | # Sets the sound output mode. | ||
| 435 | # 0: Mono, 1 (default): Stereo, 2: Surround | ||
| 436 | sound_index = | ||
| 437 | |||
| 438 | [Miscellaneous] | ||
| 439 | # A filter which removes logs below a certain logging level. | ||
| 440 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical | ||
| 441 | log_filter = *:Trace | ||
| 442 | |||
| 443 | # Use developer keys | ||
| 444 | # 0 (default): Disabled, 1: Enabled | ||
| 445 | use_dev_keys = | ||
| 446 | |||
| 447 | [Debugging] | ||
| 448 | # Record frame time data, can be found in the log directory. Boolean value | ||
| 449 | record_frame_times = | ||
| 450 | # Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them | ||
| 451 | dump_exefs=false | ||
| 452 | # Determines whether or not yuzu will dump all NSOs it attempts to load while loading them | ||
| 453 | dump_nso=false | ||
| 454 | # Determines whether or not yuzu will save the filesystem access log. | ||
| 455 | enable_fs_access_log=false | ||
| 456 | # Enables verbose reporting services | ||
| 457 | reporting_services = | ||
| 458 | # Determines whether or not yuzu will report to the game that the emulated console is in Kiosk Mode | ||
| 459 | # false: Retail/Normal Mode (default), true: Kiosk Mode | ||
| 460 | quest_flag = | ||
| 461 | # Determines whether debug asserts should be enabled, which will throw an exception on asserts. | ||
| 462 | # false: Disabled (default), true: Enabled | ||
| 463 | use_debug_asserts = | ||
| 464 | # Determines whether unimplemented HLE service calls should be automatically stubbed. | ||
| 465 | # false: Disabled (default), true: Enabled | ||
| 466 | use_auto_stub = | ||
| 467 | # Enables/Disables the macro JIT compiler | ||
| 468 | disable_macro_jit=false | ||
| 469 | # Determines whether to enable the GDB stub and wait for the debugger to attach before running. | ||
| 470 | # false: Disabled (default), true: Enabled | ||
| 471 | use_gdbstub=false | ||
| 472 | # The port to use for the GDB server, if it is enabled. | ||
| 473 | gdbstub_port=6543 | ||
| 474 | |||
| 475 | [WebService] | ||
| 476 | # Whether or not to enable telemetry | ||
| 477 | # 0: No, 1 (default): Yes | ||
| 478 | enable_telemetry = | ||
| 479 | # URL for Web API | ||
| 480 | web_api_url = https://api.yuzu-emu.org | ||
| 481 | # Username and token for yuzu Web Service | ||
| 482 | # See https://profile.yuzu-emu.org/ for more info | ||
| 483 | yuzu_username = | ||
| 484 | yuzu_token = | ||
| 485 | |||
| 486 | [Network] | ||
| 487 | # Name of the network interface device to use with yuzu LAN play. | ||
| 488 | # e.g. On *nix: 'enp7s0', 'wlp6s0u1u3u3', 'lo' | ||
| 489 | # e.g. On Windows: 'Ethernet', 'Wi-Fi' | ||
| 490 | network_interface = | ||
| 491 | |||
| 492 | [AddOns] | ||
| 493 | # Used to disable add-ons | ||
| 494 | # List of title IDs of games that will have add-ons disabled (separated by '|'): | ||
| 495 | title_ids = | ||
| 496 | # For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|') | ||
| 497 | # e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey | ||
| 498 | )"; | ||
| 499 | } // namespace DefaultINI | ||
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index f548931f1..5d93da237 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include "core/file_sys/vfs_real.h" | 19 | #include "core/file_sys/vfs_real.h" |
| 20 | #include "core/hle/service/filesystem/filesystem.h" | 20 | #include "core/hle/service/filesystem/filesystem.h" |
| 21 | #include "core/perf_stats.h" | 21 | #include "core/perf_stats.h" |
| 22 | #include "jni/config.h" | ||
| 22 | #include "jni/emu_window/emu_window.h" | 23 | #include "jni/emu_window/emu_window.h" |
| 23 | #include "jni/id_cache.h" | 24 | #include "jni/id_cache.h" |
| 24 | #include "video_core/rasterizer_interface.h" | 25 | #include "video_core/rasterizer_interface.h" |
| @@ -67,6 +68,9 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) { | |||
| 67 | return Core::SystemResultStatus::ErrorLoader; | 68 | return Core::SystemResultStatus::ErrorLoader; |
| 68 | } | 69 | } |
| 69 | 70 | ||
| 71 | // Loads the configuration. | ||
| 72 | Config{}; | ||
| 73 | |||
| 70 | system_.Initialize(); | 74 | system_.Initialize(); |
| 71 | system_.ApplySettings(); | 75 | system_.ApplySettings(); |
| 72 | 76 | ||
| @@ -245,7 +249,9 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGitRevision([[maybe_unused]] JN | |||
| 245 | } | 249 | } |
| 246 | 250 | ||
| 247 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_CreateConfigFile | 251 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_CreateConfigFile |
| 248 | [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {} | 252 | [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) { |
| 253 | Config{}; | ||
| 254 | } | ||
| 249 | 255 | ||
| 250 | jint Java_org_yuzu_yuzu_1emu_NativeLibrary_DefaultCPUCore([[maybe_unused]] JNIEnv* env, | 256 | jint Java_org_yuzu_yuzu_1emu_NativeLibrary_DefaultCPUCore([[maybe_unused]] JNIEnv* env, |
| 251 | [[maybe_unused]] jclass clazz) { | 257 | [[maybe_unused]] jclass clazz) { |
| @@ -257,7 +263,9 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_St | |||
| 257 | [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} | 263 | [[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {} |
| 258 | 264 | ||
| 259 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadSettings([[maybe_unused]] JNIEnv* env, | 265 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadSettings([[maybe_unused]] JNIEnv* env, |
| 260 | [[maybe_unused]] jclass clazz) {} | 266 | [[maybe_unused]] jclass clazz) { |
| 267 | Config{}; | ||
| 268 | } | ||
| 261 | 269 | ||
| 262 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetUserSetting([[maybe_unused]] JNIEnv* env, | 270 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetUserSetting([[maybe_unused]] JNIEnv* env, |
| 263 | [[maybe_unused]] jclass clazz, | 271 | [[maybe_unused]] jclass clazz, |
diff --git a/src/android/app/src/main/res/menu/menu_game_grid.xml b/src/android/app/src/main/res/menu/menu_game_grid.xml index 9cdcc7f08..cd515afbf 100644 --- a/src/android/app/src/main/res/menu/menu_game_grid.xml +++ b/src/android/app/src/main/res/menu/menu_game_grid.xml | |||
| @@ -3,11 +3,6 @@ | |||
| 3 | xmlns:app="http://schemas.android.com/apk/res-auto"> | 3 | xmlns:app="http://schemas.android.com/apk/res-auto"> |
| 4 | 4 | ||
| 5 | <item | 5 | <item |
| 6 | android:id="@+id/button_premium" | ||
| 7 | android:icon="@drawable/ic_premium" | ||
| 8 | android:title="@string/premium_text" | ||
| 9 | app:showAsAction="ifRoom" /> | ||
| 10 | <item | ||
| 11 | android:id="@+id/button_file_menu" | 6 | android:id="@+id/button_file_menu" |
| 12 | android:icon="@drawable/ic_folder" | 7 | android:icon="@drawable/ic_folder" |
| 13 | android:title="@string/select_game_folder" | 8 | android:title="@string/select_game_folder" |
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index c948e6a8b..bf9922be8 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml | |||
| @@ -61,16 +61,22 @@ | |||
| 61 | <string-array name="languageNames"> | 61 | <string-array name="languageNames"> |
| 62 | <item>Japanese (日本語)</item> | 62 | <item>Japanese (日本語)</item> |
| 63 | <item>English</item> | 63 | <item>English</item> |
| 64 | <item>French (français)</item> | 64 | <item>French (Français)</item> |
| 65 | <item>German (Deutsch)</item> | 65 | <item>German (Deutsch)</item> |
| 66 | <item>Italian (italiano)</item> | 66 | <item>Italian (Italiano)</item> |
| 67 | <item>Spanish (español)</item> | 67 | <item>Spanish (Español)</item> |
| 68 | <item>Simplified Chinese (简体中文)</item> | 68 | <item>Chinese (简体中文)</item> |
| 69 | <item>Korean (한국어)</item> | 69 | <item>Korean (한국어)</item> |
| 70 | <item>Dutch (Nederlands)</item> | 70 | <item>Dutch (Nederlands)</item> |
| 71 | <item>Portuguese (português)</item> | 71 | <item>Portuguese (Português)</item> |
| 72 | <item>Russian (Русский)</item> | 72 | <item>Russian (Русский)</item> |
| 73 | <item>Traditional Chinese (正體中文)</item> | 73 | <item>Taiwanese (台湾)</item> |
| 74 | <item>British English</item> | ||
| 75 | <item>Canadian French (Français canadien)</item> | ||
| 76 | <item>Latin American Spanish (Español latinoamericano)</item> | ||
| 77 | <item>Simplified Chinese (简体中文)</item> | ||
| 78 | <item>Traditional Chinese (正體中文))</item> | ||
| 79 | <item>Brazilian Portuguese (Portugues do Brasil)</item> | ||
| 74 | </string-array> | 80 | </string-array> |
| 75 | 81 | ||
| 76 | <integer-array name="languageValues"> | 82 | <integer-array name="languageValues"> |
| @@ -86,89 +92,65 @@ | |||
| 86 | <item>9</item> | 92 | <item>9</item> |
| 87 | <item>10</item> | 93 | <item>10</item> |
| 88 | <item>11</item> | 94 | <item>11</item> |
| 95 | <item>12</item> | ||
| 96 | <item>13</item> | ||
| 97 | <item>14</item> | ||
| 98 | <item>15</item> | ||
| 99 | <item>16</item> | ||
| 100 | <item>17</item> | ||
| 89 | </integer-array> | 101 | </integer-array> |
| 90 | 102 | ||
| 91 | <string-array name="n3dsButtons"> | 103 | <string-array name="rendererApiNames"> |
| 92 | <item>a</item> | 104 | <item>Vulkan</item> |
| 93 | <item>b</item> | 105 | <item>None</item> |
| 94 | <item>x</item> | ||
| 95 | <item>y</item> | ||
| 96 | <item>L</item> | ||
| 97 | <item>R</item> | ||
| 98 | <item>ZL</item> | ||
| 99 | <item>ZR</item> | ||
| 100 | <item>Start</item> | ||
| 101 | <item>Select</item> | ||
| 102 | <item>D-Pad</item> | ||
| 103 | <item>Circle Pad</item> | ||
| 104 | <item>C Stick</item> | ||
| 105 | </string-array> | ||
| 106 | |||
| 107 | <string-array name="cameraImageSourceNames"> | ||
| 108 | <item>Blank</item> | ||
| 109 | <item>Still Image</item> | ||
| 110 | <item>Device Camera</item> | ||
| 111 | </string-array> | ||
| 112 | |||
| 113 | <string-array name="cameraImageSourceValues"> | ||
| 114 | <item>blank</item> | ||
| 115 | <item>image</item> | ||
| 116 | <item>ndk</item> | ||
| 117 | </string-array> | ||
| 118 | |||
| 119 | <string-array name="cameraDeviceNames"> | ||
| 120 | <item>Default</item> | ||
| 121 | <item>Any Front Camera</item> | ||
| 122 | <item>Any Back Camera</item> | ||
| 123 | </string-array> | 106 | </string-array> |
| 124 | 107 | ||
| 125 | <string-array name="cameraDeviceValues"> | 108 | <integer-array name="rendererApiValues"> |
| 126 | <item /> | 109 | <item>1</item> |
| 127 | <item>_front</item> | 110 | <item>2</item> |
| 128 | <item>_back</item> | 111 | </integer-array> |
| 129 | </string-array> | ||
| 130 | 112 | ||
| 131 | <string-array name="cameraFlipNames"> | 113 | <string-array name="rendererAccuracyNames"> |
| 132 | <item>None</item> | 114 | <item>Normal</item> |
| 133 | <item>Horizontal</item> | 115 | <item>High</item> |
| 134 | <item>Vertical</item> | 116 | <item>Extreme (Slow)</item> |
| 135 | <item>Reverse</item> | ||
| 136 | </string-array> | 117 | </string-array> |
| 137 | 118 | ||
| 138 | <integer-array name="cameraFlipValues"> | 119 | <integer-array name="rendererAccuracyValues"> |
| 139 | <item>0</item> | 120 | <item>0</item> |
| 140 | <item>1</item> | 121 | <item>1</item> |
| 141 | <item>2</item> | 122 | <item>2</item> |
| 142 | <item>3</item> | ||
| 143 | </integer-array> | 123 | </integer-array> |
| 144 | 124 | ||
| 145 | <string-array name="audioInputTypeNames"> | 125 | <string-array name="rendererResolutionNames"> |
| 146 | <item>None</item> | 126 | <item>0.5X (360p/540p)</item> |
| 147 | <item>Real Device</item> | 127 | <item>0.75X (540p/810p)</item> |
| 148 | <item>Static Noise</item> | 128 | <item>1X (720p/1080p)</item> |
| 129 | <item>2X (1440p/2160p) (Slow)</item> | ||
| 130 | <item>3X (2160p/3240p) (Slow)</item> | ||
| 131 | <item>4X (2880p/4320p) (Slow)</item> | ||
| 149 | </string-array> | 132 | </string-array> |
| 150 | 133 | ||
| 151 | <integer-array name="audioInputTypeValues"> | 134 | <integer-array name="rendererResolutionValues"> |
| 152 | <item>0</item> | 135 | <item>0</item> |
| 153 | <item>1</item> | 136 | <item>1</item> |
| 154 | <item>2</item> | 137 | <item>2</item> |
| 138 | <item>3</item> | ||
| 139 | <item>4</item> | ||
| 140 | <item>5</item> | ||
| 155 | </integer-array> | 141 | </integer-array> |
| 156 | 142 | ||
| 157 | <string-array name="render3dModes"> | 143 | <string-array name="cpuAccuracyNames"> |
| 158 | <item>Off</item> | 144 | <item>Auto</item> |
| 159 | <item>Side by Side</item> | 145 | <item>Accurate</item> |
| 160 | <item>Anaglyph</item> | 146 | <item>Unsafe</item> |
| 161 | <item>Interlaced</item> | 147 | <item>Paranoid (Slow)</item> |
| 162 | <item>Reverse Interlaced</item> | ||
| 163 | <item>Cardboard VR</item> | ||
| 164 | </string-array> | 148 | </string-array> |
| 165 | 149 | ||
| 166 | <integer-array name="render3dValues"> | 150 | <integer-array name="cpuAccuracyValues"> |
| 167 | <item>0</item> | 151 | <item>0</item> |
| 168 | <item>1</item> | 152 | <item>1</item> |
| 169 | <item>2</item> | 153 | <item>2</item> |
| 170 | <item>3</item> | 154 | <item>3</item> |
| 171 | <item>4</item> | ||
| 172 | <item>5</item> | ||
| 173 | </integer-array> | 155 | </integer-array> |
| 174 | </resources> | 156 | </resources> |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 58d80398f..239fde48d 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -9,105 +9,31 @@ | |||
| 9 | <string name="app_notification_channel_description">yuzu Switch emulator notifications</string> | 9 | <string name="app_notification_channel_description">yuzu Switch emulator notifications</string> |
| 10 | <string name="app_notification_running">yuzu is running</string> | 10 | <string name="app_notification_running">yuzu is running</string> |
| 11 | 11 | ||
| 12 | <!-- Input related strings --> | 12 | <!-- General settings strings --> |
| 13 | <string name="controller_circlepad">Circle Pad</string> | 13 | <string name="frame_limit_enable">Enable limit speed</string> |
| 14 | <string name="controller_c">C-Stick</string> | 14 | <string name="frame_limit_enable_description">When enabled, emulation speed will be limited to a specified percentage of normal speed.</string> |
| 15 | <string name="controller_triggers">Triggers</string> | 15 | <string name="frame_limit_slider">Limit speed percent</string> |
| 16 | <string name="controller_dpad">D-Pad</string> | 16 | <string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit.</string> |
| 17 | <string name="controller_axis_vertical">Up/Down Axis</string> | 17 | <string name="cpu_accuracy">CPU accuracy</string> |
| 18 | <string name="controller_axis_horizontal">Left/Right Axis</string> | ||
| 19 | <string name="input_binding">Input Binding</string> | ||
| 20 | <string name="input_binding_description">Press or move an input to bind it to %1$s.</string> | ||
| 21 | <string name="input_binding_description_vertical_axis">Move your joystick up or down.</string> | ||
| 22 | <string name="input_binding_description_horizontal_axis">Move your joystick left or right.</string> | ||
| 23 | <string name="button_a" translatable="false">A</string> | ||
| 24 | <string name="button_b" translatable="false">B</string> | ||
| 25 | <string name="button_select" translatable="false">SELECT</string> | ||
| 26 | <string name="button_start" translatable="false">START</string> | ||
| 27 | <string name="button_x" translatable="false">X</string> | ||
| 28 | <string name="button_y" translatable="false">Y</string> | ||
| 29 | <string name="button_l" translatable="false">L</string> | ||
| 30 | <string name="button_r" translatable="false">R</string> | ||
| 31 | <string name="button_zl" translatable="false">ZL</string> | ||
| 32 | <string name="button_zr" translatable="false">ZR</string> | ||
| 33 | <string name="input_message_analog_only">This control must be bound to a gamepad analog stick or D-pad axis!</string> | ||
| 34 | <string name="input_message_button_only">This control must be bound to a gamepad button!</string> | ||
| 35 | |||
| 36 | <!-- Generic buttons (Shared with lots of stuff) --> | ||
| 37 | <string name="generic_buttons">Buttons</string> | ||
| 38 | |||
| 39 | <!-- Premium settings strings --> | ||
| 40 | <string name="design">Change Theme (Light, Dark)</string> | ||
| 41 | <string name="design_updated">Theme will update when exiting Settings</string> | ||
| 42 | |||
| 43 | <!-- Core settings strings --> | ||
| 44 | <string name="cpu_jit">Enable CPU JIT</string> | ||
| 45 | <string name="cpu_jit_description">Uses the Just-in-Time (JIT) compiler for CPU emulation. When enabled, game performance will be significantly improved.</string> | ||
| 46 | <string name="init_clock">System clock type</string> | ||
| 47 | <string name="init_clock_description">Set the emulated Console clock to either reflect that of your device or start at a simulated date and time.</string> | ||
| 48 | 18 | ||
| 49 | <!-- System settings strings --> | 19 | <!-- System settings strings --> |
| 20 | <string name="use_docked_mode">Docked mode</string> | ||
| 21 | <string name="use_docked_mode_description">Emulates in docked mode, which increases the resolution at the expense of performance.</string> | ||
| 50 | <string name="init_time">System clock starting time override</string> | 22 | <string name="init_time">System clock starting time override</string> |
| 51 | <string name="init_time_description">If the \"System clock type\" setting is set to \"Simulated clock\", this changes the fixed date and time to start at.</string> | 23 | <string name="init_time_description">If the \"System clock type\" setting is set to \"Simulated clock\", this changes the fixed date and time to start at.</string> |
| 52 | <string name="emulated_region">Emulated region</string> | 24 | <string name="emulated_region">Emulated region</string> |
| 53 | <string name="emulated_language">Emulated language</string> | 25 | <string name="emulated_language">Emulated language</string> |
| 54 | 26 | ||
| 55 | <!-- Graphics settings strings --> | 27 | <!-- Graphics settings strings --> |
| 56 | <string name="renderer">Renderer</string> | 28 | <string name="renderer_api">API</string> |
| 57 | <string name="vsync">Enable V-Sync</string> | 29 | <string name="renderer_accuracy">Accuracy level</string> |
| 58 | <string name="vsync_description">Synchronizes the game frame rate to the refresh rate of your device.</string> | 30 | <string name="renderer_resolution">Resolution</string> |
| 59 | <string name="linear_filtering">Enable linear filtering</string> | 31 | <string name="renderer_asynchronous_shaders">Use asynchronous shaders</string> |
| 60 | <string name="linear_filtering_description">Enables linear filtering, which causes game visuals to appear smoother.</string> | 32 | <string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously, which will reduce stutter but may introduce glitches.</string> |
| 61 | <string name="texture_filter_name">Texture Filter</string> | ||
| 62 | <string name="texture_filter_description">Enhances the visuals of games by applying a filter to textures. The supported filters are Anime4K Ultrafast, Bicubic, ScaleForce, and xBRZ freescale.</string> | ||
| 63 | <string name="hw_renderer">Enable hardware renderer</string> | ||
| 64 | <string name="hw_renderer_description">Uses hardware to emulate 3DS graphics. When enabled, game performance will be significantly improved.</string> | ||
| 65 | <string name="hw_shaders">Enable hardware shader</string> | ||
| 66 | <string name="hw_shaders_description">Uses hardware to emulate 3DS shaders. When enabled, game performance will be significantly improved.</string> | ||
| 67 | <string name="shaders_accurate_mul">Enable accurate shader multiplication</string> | ||
| 68 | <string name="shaders_accurate_mul_description">Uses more accurate multiplication in hardware shaders, which may fix some graphical bugs. When enabled, performance will be reduced.</string> | ||
| 69 | <string name="asynchronous_gpu">Enable asynchronous GPU emulation</string> | ||
| 70 | <string name="asynchronous_gpu_description">Uses a separate thread to emulate the GPU asynchronously. When enabled, performance will be improved.</string> | ||
| 71 | <string name="frame_limit_enable">Enable limit speed</string> | ||
| 72 | <string name="frame_limit_enable_description">When enabled, emulation speed will be limited to a specified percentage of normal speed.</string> | ||
| 73 | <string name="frame_limit_slider">Limit speed percent</string> | ||
| 74 | <string name="frame_limit_slider_description">Specifies the percentage to limit emulation speed. With the default of 100% emulation will be limited to normal speed. Values higher or lower will increase or decrease the speed limit.</string> | ||
| 75 | <string name="internal_resolution">Internal resolution</string> | ||
| 76 | <string name="internal_resolution_description">Specifies the resolution used to render at. A high resolution will improve visual quality a lot but is also quite heavy on performance and might cause glitches in certain games.</string> | ||
| 77 | <string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string> | ||
| 78 | <string name="debug_warning">Warning: Modifying these settings will slow emulation</string> | ||
| 79 | <string name="stereoscopy">Stereoscopy</string> | ||
| 80 | <string name="render3d">Stereoscopic 3D Mode</string> | ||
| 81 | <string name="factor3d">Depth</string> | ||
| 82 | <string name="factor3d_description">Specifies the value of the 3D slider. This should be set to higher than 0% when Stereoscopic 3D is enabled.</string> | ||
| 83 | <string name="cardboard_vr">Cardboard VR</string> | ||
| 84 | <string name="cardboard_screen_size">Cardboard Screen size</string> | ||
| 85 | <string name="cardboard_screen_size_description">Scales the screen to a percentage of its original size.</string> | ||
| 86 | <string name="cardboard_x_shift">Horizontal shift</string> | ||
| 87 | <string name="cardboard_x_shift_description">Specifies the percentage of empty space to shift the screens horizontally. Positive values move the two eyes closer to the middle, while negative values move them away.</string> | ||
| 88 | <string name="cardboard_y_shift">Vertical shift</string> | ||
| 89 | <string name="cardboard_y_shift_description">Specifies the percentage of empty space to shift the screens vertically. Positive values move the two eyes towards the bottom, while negative values move them towards the top.</string> | ||
| 90 | <string name="use_shader_jit">Use shader JIT</string> | ||
| 91 | <string name="use_disk_shader_cache">Use disk shader cache</string> | ||
| 92 | <string name="use_disk_shader_cache_description">Reduce stuttering by storing and loading generated shaders to disk. It cannot be used without Enabling Hardware Shader.</string> | ||
| 93 | <string name="utility">Utility</string> | ||
| 94 | <string name="dump_textures">Dump textures</string> | ||
| 95 | <string name="dump_textures_description">Dumps textures to dump/textures/[GAME ID]</string> | ||
| 96 | <string name="custom_textures">Use custom textures</string> | ||
| 97 | <string name="custom_textures_description">Uses custom textures found in load/textures/[GAME ID]</string> | ||
| 98 | <string name="preload_textures">Preload custom textures</string> | ||
| 99 | <string name="preload_textures_description">Loads all custom textures into memory. This feature can use a lot of memory.</string> | ||
| 100 | <!-- Premium strings --> | ||
| 101 | <string name="premium_text">Premium</string> | ||
| 102 | <string name="premium_settings_upsell">Upgrade to Premium and support yuzu!</string> | ||
| 103 | <string name="premium_settings_upsell_description">With Premium, you will support the developers to continue improving yuzu, and gain access to these exclusive features!</string> | ||
| 104 | <string name="premium_settings_welcome">Welcome to Premium.</string> | ||
| 105 | <string name="premium_settings_welcome_description">Thank you for your support!</string> | ||
| 106 | 33 | ||
| 107 | <!-- Audio settings strings --> | 34 | <!-- Audio settings strings --> |
| 108 | <string name="audio_stretch">Enable audio stretching</string> | 35 | <string name="audio_volume">Volume</string> |
| 109 | <string name="audio_stretch_description">Stretches audio to reduce stuttering. When enabled, increases audio latency and slightly reduces performance.</string> | 36 | <string name="audio_volume_description">Specifies the volume of audio output.</string> |
| 110 | <string name="audio_input_type">Audio Input Device</string> | ||
| 111 | 37 | ||
| 112 | <!-- Miscellaneous --> | 38 | <!-- Miscellaneous --> |
| 113 | <string name="clear">Clear</string> | 39 | <string name="clear">Clear</string> |
| @@ -126,14 +52,10 @@ | |||
| 126 | 52 | ||
| 127 | <!-- Preferences Screen --> | 53 | <!-- Preferences Screen --> |
| 128 | <string name="preferences_settings">Settings</string> | 54 | <string name="preferences_settings">Settings</string> |
| 129 | <string name="preferences_premium">Premium</string> | ||
| 130 | <string name="preferences_general">General</string> | 55 | <string name="preferences_general">General</string> |
| 131 | <string name="preferences_system">System</string> | 56 | <string name="preferences_system">System</string> |
| 132 | <string name="preferences_camera">Camera</string> | ||
| 133 | <string name="preferences_controls">Gamepad</string> | ||
| 134 | <string name="preferences_graphics">Graphics</string> | 57 | <string name="preferences_graphics">Graphics</string> |
| 135 | <string name="preferences_audio">Audio</string> | 58 | <string name="preferences_audio">Audio</string> |
| 136 | <string name="preferences_debug">Debug</string> | ||
| 137 | 59 | ||
| 138 | <!-- ROM loading errors --> | 60 | <!-- ROM loading errors --> |
| 139 | <string name="loader_error_encrypted">Your ROM is encrypted</string> | 61 | <string name="loader_error_encrypted">Your ROM is encrypted</string> |
| @@ -158,7 +80,7 @@ | |||
| 158 | 80 | ||
| 159 | <string name="do_not_show_this_again">Do not show this again</string> | 81 | <string name="do_not_show_this_again">Do not show this again</string> |
| 160 | 82 | ||
| 161 | <!-- Software Keyboard --> | 83 | <!-- Software keyboard --> |
| 162 | <string name="software_keyboard">Software Keyboard</string> | 84 | <string name="software_keyboard">Software Keyboard</string> |
| 163 | <string name="i_forgot">I Forgot</string> | 85 | <string name="i_forgot">I Forgot</string> |
| 164 | <string name="fixed_length_required">Text length is not correct (should be %d characters)</string> | 86 | <string name="fixed_length_required">Text length is not correct (should be %d characters)</string> |
| @@ -166,7 +88,7 @@ | |||
| 166 | <string name="blank_input_not_allowed">Blank input is not allowed</string> | 88 | <string name="blank_input_not_allowed">Blank input is not allowed</string> |
| 167 | <string name="empty_input_not_allowed">Empty input is not allowed</string> | 89 | <string name="empty_input_not_allowed">Empty input is not allowed</string> |
| 168 | 90 | ||
| 169 | <!-- Core Errors --> | 91 | <!-- Errors and warnings --> |
| 170 | <string name="abort_button">Abort</string> | 92 | <string name="abort_button">Abort</string> |
| 171 | <string name="continue_button">Continue</string> | 93 | <string name="continue_button">Continue</string> |
| 172 | <string name="system_archive_not_found">System Archive Not Found</string> | 94 | <string name="system_archive_not_found">System Archive Not Found</string> |
| @@ -175,4 +97,5 @@ | |||
| 175 | <string name="save_load_error">Save/Load Error</string> | 97 | <string name="save_load_error">Save/Load Error</string> |
| 176 | <string name="fatal_error">Fatal Error</string> | 98 | <string name="fatal_error">Fatal Error</string> |
| 177 | <string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string> | 99 | <string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string> |
| 100 | <string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string> | ||
| 178 | </resources> | 101 | </resources> |