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