nx: devicesettings: refactor and add joycon settings

- Refactor common fragment bits into new file
- Toggle analog trigger emu
- Full Nintendo controller button remapping
- Don't show OLED prefs on non-OLED
- Optimize gets and data loads

Change-Id: I331977aea35f7097cad0a8c2a644207a9dac6c03
This commit is contained in:
tmakin authored and Nolen Johnson committed 2025-02-14 12:52:37 -05:00
1 parent 6fe016e60e
commit 4f6079836b
11 files changed
+528 -529

No files matched your search

+1 -1
View File
@@ -38,12 +38,12 @@ android_app {
static_libs: [
"androidx.preference_preference",
"androidx.appcompat_appcompat",
"androidx.legacy_legacy-preference-v14",
"androidx.leanback_leanback-preference",
"androidx.leanback_leanback",
"org.lineageos.settings.resources",
"org.lineageos.platform.internal",
"vendor.nvidia.hardware.graphics.display-V1.0-java",
"android.hardware.nintendo.joycond-V1-java",
],
}
+2
View File
@@ -21,6 +21,7 @@
android:icon="@mipmap/ic_launcher"
android:banner="@mipmap/ic_banner"
android:persistent="true"
android:enableOnBackInvokedCallback="true"
android:exported="true">
<service android:name=".DockService"
@@ -56,6 +57,7 @@
<action android:name="com.android.settings.action.IA_SETTINGS" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.hardware.nintendo.joycond.IJoycond/default" />
</intent-filter>
<meta-data
android:name="com.android.settings.category"
+34
View File
@@ -37,4 +37,38 @@
<item>0x75</item> <!-- DCS_SM_COLOR_MODE_NIGHT3 -->
</string-array>
<string-array name="keys_map">
<item>B</item>
<item>A</item>
<item>X</item>
<item>Y</item>
<item>Screenshot</item>
<item>L1</item>
<item>R1</item>
<item>L2</item>
<item>R2</item>
<item>Minus</item>
<item>Plus</item>
<item>Home</item>
<item>Left Thumb</item>
<item>Right Thumb</item>
</string-array>
<string-array name="keys">
<item>304</item>
<item>305</item>
<item>307</item>
<item>308</item>
<item>309</item>
<item>310</item>
<item>311</item>
<item>312</item>
<item>313</item>
<item>314</item>
<item>315</item>
<item>316</item>
<item>317</item>
<item>318</item>
</string-array>
</resources>
+4 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 The LineageOS Project
Copyright (C) 2020-2025 The LineageOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -28,6 +28,9 @@
<string name="mode_confirmation_summary">Are you sure you want to keep these display settings?\n\nWill revert in %1$d seconds</string>
<string name="panel_color_setting_title">Select OLED Panel Color Mode</string>
<string name="panel_color_setting_summary">Current mode: %s</string>
<string name="joycon_category_title">Nintendo Controller Customization</string>
<string name="analog_title">Analog Trigger Emulation</string>
<string name="analog_summary">Enable/disable L2/R2 analog trigger emulation on Nintendo Controllers</string>
<string name="disable_internal_on_external_connected_title">Turn off when an external display is connected</string>
<string name="disable_internal_on_external_connected_summary_on">The internal panel will be turned off when an external display is connected</string>
<string name="disable_internal_on_external_connected_summary_off">Both the internal panel and external display will show the same image</string>
+10 -7
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020-2023 The LineageOS Project
Copyright (C) 2020-2025 The LineageOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -27,13 +27,16 @@
android:key="perf_mode"
android:title="@string/perf_setting_title"
android:summary="@string/perf_setting_summary" />
</PreferenceCategory>
<ListPreference
android:key="panel_color_mode"
android:title="@string/panel_color_setting_title"
android:entries="@array/panel_mode_map"
app:useSimpleSummaryProvider="false"
android:entryValues="@array/panel_modes" />
<PreferenceCategory
android:key="joycon_category"
android:title="@string/joycon_category_title">
<SwitchPreference
android:key="joycon_analog"
android:title="@string/analog_title"
android:summary="@string/analog_summary" />
</PreferenceCategory>
</PreferenceScreen>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The LineageOS Project
Copyright (C) 2023-2025 The LineageOS Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
@@ -30,13 +30,16 @@
android:key="perf_mode"
android:title="@string/perf_setting_title"
android:summary="@string/perf_setting_summary" />
<ListPreference
android:key="panel_color_mode"
android:title="@string/panel_color_setting_title"
android:entries="@array/panel_mode_map"
app:useSimpleSummaryProvider="false"
android:entryValues="@array/panel_modes" />
</PreferenceCategory>
<PreferenceCategory
android:key="joycon_category"
android:title="@string/joycon_category_title">
<SwitchPreference
android:key="joycon_analog"
android:title="@string/analog_title"
android:summary="@string/analog_summary" />
</PreferenceCategory>
</PreferenceScreen>
@@ -35,9 +35,11 @@ public class DisplaySettingsActivity extends CollapsingToolbarBaseActivity {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
getFragmentManager().beginTransaction().replace(
com.android.settingslib.collapsingtoolbar.R.id.content_frame,
new DisplaySettingsFragment()).commit();
getSupportFragmentManager()
.beginTransaction()
.add(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
new DisplaySettingsFragment())
.commitNow();
}
}
@@ -19,41 +19,30 @@ package org.lineageos.settings.device;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.content.Intent;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Log;
import android.view.MenuItem;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragment;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplay;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplayMode;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplayType;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcModeType;
import vendor.nvidia.hardware.graphics.display.V1_0.INvDisplay;
public class DisplaySettingsFragment extends PreferenceFragment
public class DisplaySettingsFragment extends PreferenceFragmentCompat
implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = DisplaySettingsFragment.class.getSimpleName();
private final String sku = SystemProperties.get("ro.product.name", "");
public boolean mInModeChange = false;
private INvDisplay mDisplayService;
private DisplaySettingsPrefsCommon commonPrefs;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
@@ -68,18 +57,22 @@ public class DisplaySettingsFragment extends PreferenceFragment
addPreferencesFromResource(R.xml.display_panel);
PreferenceScreen preferenceScreen = this.getPreferenceScreen();
createPerfSettings();
commonPrefs = new DisplaySettingsPrefsCommon(this, mDisplayService, sku);
commonPrefs.createPerfSettings();
if (!sku.equals("vali")) {
createDisplaySettings(preferenceScreen);
commonPrefs.createDisplaySettings(preferenceScreen);
}
commonPrefs.createJoyConSettings(preferenceScreen);
}
@Override
public void onResume() {
super.onResume();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
getActivity());
getActivity());
prefs.registerOnSharedPreferenceChangeListener(this);
}
@@ -87,14 +80,14 @@ public class DisplaySettingsFragment extends PreferenceFragment
public void onPause() {
super.onPause();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(
getActivity());
getActivity());
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getActivity().onBackPressed();
getActivity().getOnBackPressedDispatcher().onBackPressed();
return true;
}
return false;
@@ -102,7 +95,7 @@ public class DisplaySettingsFragment extends PreferenceFragment
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPrefs, String key) {
if(!sku.equals("vali")) {
if (!sku.equals("vali")) {
HashMap<String, Integer> uidMap = DisplayUtils.makeUidMap(mDisplayService);
if (key.startsWith("mode_")) {
String hash = key.substring(5);
@@ -119,15 +112,15 @@ public class DisplaySettingsFragment extends PreferenceFragment
if (key.equals("disable_internal_on_external_connected")) {
DisplayUtils.setInternalDisplayState(
!(((DisplaySettingsActivity)getActivity()).mExternalDisplayConnected
&& sharedPrefs.getBoolean(key, false)));
!(((DisplaySettingsActivity) getActivity()).mExternalDisplayConnected
&& sharedPrefs.getBoolean(key, false)));
return;
}
}
}
private void performModeChange(SharedPreferences sharedPrefs, String key,
int modeIndex, int display) {
int modeIndex, int display) {
try {
mDisplayService.modeDefaultSetIndex(display, modeIndex);
} catch (RemoteException e) {
@@ -135,8 +128,7 @@ public class DisplaySettingsFragment extends PreferenceFragment
return;
}
DialogInterface.OnClickListener confirmationDialogClickListener =
new DialogInterface.OnClickListener() {
DialogInterface.OnClickListener confirmationDialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
@@ -164,11 +156,10 @@ public class DisplaySettingsFragment extends PreferenceFragment
try {
currentMode = mDisplayService.getMode(display,
HwcSvcModeType.HWC_SVC_MODE_TYPE_CURRENT);
HwcSvcModeType.HWC_SVC_MODE_TYPE_CURRENT);
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display mode");
((DisplaySettingsActivity) getActivity()).mReceiver.mBlocked
= false;
((DisplaySettingsActivity) getActivity()).mReceiver.mBlocked = false;
getActivity().recreate();
return;
}
@@ -185,9 +176,9 @@ public class DisplaySettingsFragment extends PreferenceFragment
AlertDialog.Builder builder = new AlertDialog.Builder(getView().getContext());
builder.setTitle(R.string.mode_confirmation_title)
.setPositiveButton(android.R.string.ok, confirmationDialogClickListener)
.setNegativeButton(android.R.string.cancel, confirmationDialogClickListener)
.setMessage(getString(R.string.mode_confirmation_summary, waitTime));
.setPositiveButton(android.R.string.ok, confirmationDialogClickListener)
.setNegativeButton(android.R.string.cancel, confirmationDialogClickListener)
.setMessage(getString(R.string.mode_confirmation_summary, waitTime));
AlertDialog confirmationDialog = builder.create();
confirmationDialog.show();
@@ -197,7 +188,7 @@ public class DisplaySettingsFragment extends PreferenceFragment
public void onTick(long millisUntilFinished) {
if (isAdded())
confirmationDialog.setMessage(
getString(R.string.mode_confirmation_summary,
getString(R.string.mode_confirmation_summary,
millisUntilFinished / 1000));
}
@@ -205,233 +196,8 @@ public class DisplaySettingsFragment extends PreferenceFragment
public void onFinish() {
if (isAdded())
confirmationDialog.getButton(DialogInterface.BUTTON_NEGATIVE)
.performClick();
.performClick();
}
}.start();
}
private void createPerfSettings() {
SwitchPreference perfPreference = findPreference("perf_mode");
perfPreference.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (((Boolean) newValue) != PreferenceManager
.getDefaultSharedPreferences(getActivity())
.getBoolean("perf_mode", false)) {
final boolean isEnabled = (Boolean) newValue;
if (isEnabled) {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.perf_warning_title)
.setMessage(R.string.perf_warning_summary)
.setNegativeButton(getString(android.R.string.cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int whichButton) {
}
})
.setPositiveButton(getString(android.R.string.ok),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int whichButton) {
SharedPreferences sharedPrefs =
PreferenceManager
.getDefaultSharedPreferences(getActivity());
SharedPreferences.Editor editor =
sharedPrefs.edit();
editor.putBoolean("perf_mode", true);
editor.commit();
perfPreference.setChecked(true);
}
})
.setOnDismissListener(
new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
Intent intent=new Intent(DisplayUtils
.POWER_UPDATE_INTENT);
getActivity().sendBroadcast(intent);
}
}).create().show();
return false;
}
}
Intent intent=new Intent(DisplayUtils.POWER_UPDATE_INTENT);
getActivity().sendBroadcast(intent);
return true;
}
});
}
private void createPanelModeSettings() {
ListPreference panelColorPref = findPreference("panel_color_mode");
String current = DisplayUtils.getPanelColorMode();
int index;
Resources res = getResources();
String[] modes = res.getStringArray(R.array.panel_modes);
String[] modeMap = res.getStringArray(R.array.panel_mode_map);
for(index = 0; index < modes.length; index++) {
if(current.equals(modes[index]))
break;
}
if(index == modes.length) {
Log.e(TAG, "Unsupported OLED panel mode! ID: " + current);
} else {
Log.w(TAG, "OLED Panel Mode Index: " + String.valueOf(index));
panelColorPref.setValue(current);
panelColorPref.setSummary(modeMap[index]);
panelColorPref.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
int newIndex;
DisplayUtils.setPanelColorMode((String) newValue);
for (newIndex = 0; newIndex < modes.length; newIndex++) {
if (((String) newValue).equals(modes[newIndex])) {
panelColorPref.setSummary(modeMap[newIndex]);
break;
}
}
return true;
}
});
}
}
private void createDisplaySettings(PreferenceScreen preferenceScreen) {
for (int i = HwcSvcDisplay.HWC_SVC_DISPLAY_PANEL;
i <= HwcSvcDisplay.HWC_SVC_DISPLAY_HDMI2; i++) {
PreferenceCategory category = new PreferenceCategory(
preferenceScreen.getContext());
if (!initializeDisplayCategory(category, i))
continue;
preferenceScreen.addPreference(category);
populateDisplayCategory(category, i);
}
}
private boolean initializeDisplayCategory(PreferenceCategory category,
int display) {
try {
int type = mDisplayService.displayGetType(display);
ArrayList<HwcSvcDisplayMode> availableModes = mDisplayService
.modeGetList(display);
if (availableModes.size() == 0)
return false; // Display is not connected
category.setTitle(DisplayUtils.makeDisplayLabel(mDisplayService
.edidGetInfo(display), display));
category.setSummary(HwcSvcDisplayType.toString(type));
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display info");
return false;
}
return true;
}
private void populateDisplayCategory(PreferenceCategory category, int display) {
String displayUid;
HwcSvcDisplayMode currentMode;
ArrayList<HwcSvcDisplayMode> availableModes;
try {
displayUid = String.valueOf(DisplayUtils.makeDisplayLabel(mDisplayService
.edidGetInfo(display), display).hashCode());
currentMode = mDisplayService.getMode(display,
HwcSvcModeType.HWC_SVC_MODE_TYPE_CURRENT);
availableModes = mDisplayService.modeGetList(display);
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display info");
return;
}
// Sort by resolution and refresh rate
Collections.sort(availableModes, (Comparator<HwcSvcDisplayMode>) (a, b) -> {
HwcSvcDisplayMode modeA = (HwcSvcDisplayMode) a;
HwcSvcDisplayMode modeB = (HwcSvcDisplayMode) b;
if (modeA.xres == modeB.xres) {
if (modeA.yres == modeB.yres) {
if (modeA.refresh == modeB.refresh) {
if (modeA.flags > modeB.flags)
return -1;
else if (modeA.flags < modeB.flags)
return 1;
else
return 0;
}
else if (modeA.refresh > modeB.refresh)
return -1;
else
return 1;
} else if (modeA.yres > modeB.yres) {
return -1;
} else {
return 1;
}
} else if (modeA.xres > modeB.xres) {
return -1;
} else {
return 1;
}
});
ListPreference modesPreference = new ListPreference(category.getContext());
ArrayList<String> displayedModes = new ArrayList<>();
ArrayList<String> modeIndices = new ArrayList<>();
availableModes.forEach((mode) -> displayedModes.add(DisplayUtils
.makeModeInfoString(mode) + " " + DisplayUtils.makeColorInfoString(mode)));
availableModes.forEach((mode) -> modeIndices.add(String.valueOf(mode.index)));
modesPreference.setEntries(displayedModes.toArray(
new CharSequence[displayedModes.size()]));
modesPreference.setEntryValues(modeIndices.toArray(
new CharSequence[modeIndices.size()]));
modesPreference.setTitle(R.string.mode_selection_title);
modesPreference.setSummary(DisplayUtils.makeModeInfoString(currentMode) + "\n"
+ DisplayUtils.makeColorInfoString(currentMode));
modesPreference.setKey("mode_" + displayUid);
modesPreference.setValue(String.valueOf(currentMode.index));
category.addPreference(modesPreference);
// Show checkbox to disable internal panel when an external display is connected
if (display == HwcSvcDisplay.HWC_SVC_DISPLAY_PANEL) {
SwitchPreference disableInternalOnExternalConnectedPreference =
new SwitchPreference(category.getContext());
disableInternalOnExternalConnectedPreference
.setTitle(R.string.disable_internal_on_external_connected_title);
disableInternalOnExternalConnectedPreference
.setSummaryOn(R.string.disable_internal_on_external_connected_summary_on);
disableInternalOnExternalConnectedPreference
.setSummaryOff(R.string.disable_internal_on_external_connected_summary_off);
disableInternalOnExternalConnectedPreference
.setKey("disable_internal_on_external_connected");
category.addPreference(disableInternalOnExternalConnectedPreference);
if (sku.equals("fric")) {
createPanelModeSettings();
}
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2023-2024 The LineageOS Project
* Copyright (C) 2023-2025 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,37 +16,28 @@
package org.lineageos.settings.device;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.Log;
import android.view.MenuItem;
import androidx.leanback.preference.LeanbackPreferenceFragmentCompat;
import androidx.leanback.preference.LeanbackSettingsFragmentCompat;
import androidx.preference.DialogPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SeekBarPreference;
import androidx.preference.SwitchPreference;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplay;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplayMode;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplayType;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcModeType;
import vendor.nvidia.hardware.graphics.display.V1_0.INvDisplay;
@@ -99,6 +90,7 @@ public class DisplaySettingsFragmentLeanback extends LeanbackSettingsFragmentCom
private final String sku = SystemProperties.get("ro.product.name", "");
private INvDisplay mDisplayService;
private DisplaySettingsPrefsCommon commonPrefs;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
@@ -121,11 +113,13 @@ public class DisplaySettingsFragmentLeanback extends LeanbackSettingsFragmentCom
PreferenceScreen preferenceScreen = this.getPreferenceScreen();
createPerfSettings();
commonPrefs = new DisplaySettingsPrefsCommon((PreferenceFragmentCompat) this, mDisplayService, sku);
commonPrefs.createPerfSettings();
createBrightSettings();
if (!sku.equals("vali")) {
createDisplaySettings(preferenceScreen);
commonPrefs.createDisplaySettings(preferenceScreen);
}
}
@@ -146,7 +140,7 @@ public class DisplaySettingsFragmentLeanback extends LeanbackSettingsFragmentCom
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getActivity().onBackPressed();
getActivity().getOnBackPressedDispatcher().onBackPressed();
return true;
}
return false;
@@ -171,8 +165,7 @@ public class DisplaySettingsFragmentLeanback extends LeanbackSettingsFragmentCom
if (key.equals("disable_internal_on_external_connected")) {
DisplayUtils.setInternalDisplayState(
!(((DisplaySettingsLeanbackActivity) getActivity())
.mExternalDisplayConnected
!(((DisplaySettingsLeanbackActivity) getActivity()).mExternalDisplayConnected
&& sharedPrefs.getBoolean(key, false)));
return;
}
@@ -188,8 +181,7 @@ public class DisplaySettingsFragmentLeanback extends LeanbackSettingsFragmentCom
return;
}
DialogInterface.OnClickListener confirmationDialogClickListener =
new DialogInterface.OnClickListener() {
DialogInterface.OnClickListener confirmationDialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
@@ -220,8 +212,7 @@ public class DisplaySettingsFragmentLeanback extends LeanbackSettingsFragmentCom
HwcSvcModeType.HWC_SVC_MODE_TYPE_CURRENT);
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display mode");
((DisplaySettingsLeanbackActivity) getActivity()).mReceiver.mBlocked
= false;
((DisplaySettingsLeanbackActivity) getActivity()).mReceiver.mBlocked = false;
getActivity().recreate();
return;
}
@@ -265,65 +256,6 @@ public class DisplaySettingsFragmentLeanback extends LeanbackSettingsFragmentCom
}.start();
}
private void createPerfSettings() {
SwitchPreference perfPreference = findPreference("perf_mode");
perfPreference.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (((Boolean) newValue) != PreferenceManager
.getDefaultSharedPreferences(getActivity())
.getBoolean("perf_mode", false)) {
final boolean isEnabled = (Boolean) newValue;
if (isEnabled) {
new AlertDialog.Builder(getActivity())
.setTitle(R.string.perf_warning_title)
.setMessage(R.string.perf_warning_summary)
.setNegativeButton(getString(android.R.string.cancel),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int whichButton) {
}
})
.setPositiveButton(getString(android.R.string.ok),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int whichButton) {
SharedPreferences sharedPrefs =
PreferenceManager
.getDefaultSharedPreferences(
getActivity());
SharedPreferences.Editor editor =
sharedPrefs.edit();
editor.putBoolean("perf_mode", true);
editor.commit();
perfPreference.setChecked(true);
}
})
.setOnDismissListener(
new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
Intent intent = new Intent(
DisplayUtils.POWER_UPDATE_INTENT);
getActivity().sendBroadcast(intent);
}
})
.create().show();
return false;
}
}
Intent intent = new Intent(DisplayUtils.POWER_UPDATE_INTENT);
getActivity().sendBroadcast(intent);
return true;
}
});
}
private void createBrightSettings() {
SeekBarPreference brightPref = findPreference("bright_pref");
int current = DisplayUtils.getPanelBrightness(getActivity().getContentResolver());
@@ -337,180 +269,10 @@ public class DisplaySettingsFragmentLeanback extends LeanbackSettingsFragmentCom
public boolean onPreferenceChange(Preference preference,
Object newValue) {
DisplayUtils.setPanelBrightness(getActivity().getContentResolver(), (Integer)newValue);
DisplayUtils.setPanelBrightness(getActivity().getContentResolver(), (Integer) newValue);
return true;
}
});
}
private void createPanelModeSettings() {
ListPreference panelColorPref = findPreference("panel_color_mode");
String current = DisplayUtils.getPanelColorMode();
int index;
Resources res = getResources();
String[] modes = res.getStringArray(R.array.panel_modes);
String[] modeMap = res.getStringArray(R.array.panel_mode_map);
for (index = 0; index < modes.length; index++) {
if (current.equals(modes[index]))
break;
}
if (index == modes.length) {
Log.e(TAG, "Unsupported OLED panel mode! ID: " + current);
} else {
Log.w(TAG, "OLED Panel Mode Index: " + String.valueOf(index));
panelColorPref.setValue(current);
panelColorPref.setSummary(modeMap[index]);
panelColorPref.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
int newIndex;
DisplayUtils.setPanelColorMode((String) newValue);
for (newIndex = 0; newIndex < modes.length; newIndex++) {
if (((String) newValue).equals(modes[newIndex])) {
panelColorPref.setSummary(modeMap[newIndex]);
break;
}
}
return true;
}
});
}
}
private void createDisplaySettings(PreferenceScreen preferenceScreen) {
for (int i = HwcSvcDisplay.HWC_SVC_DISPLAY_PANEL; i <= HwcSvcDisplay.HWC_SVC_DISPLAY_HDMI2; i++) {
PreferenceCategory category = new PreferenceCategory(
preferenceScreen.getContext());
if (!initializeDisplayCategory(category, i)) {
continue;
}
preferenceScreen.addPreference(category);
populateDisplayCategory(category, i);
}
}
private boolean initializeDisplayCategory(PreferenceCategory category,
int display) {
try {
int type = mDisplayService.displayGetType(display);
ArrayList<HwcSvcDisplayMode> availableModes = mDisplayService
.modeGetList(display);
if (availableModes.size() == 0)
return false; // Display is not connected
category.setTitle(DisplayUtils.makeDisplayLabel(mDisplayService
.edidGetInfo(display), display));
category.setSummary(HwcSvcDisplayType.toString(type));
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display info");
return false;
}
return true;
}
private void populateDisplayCategory(PreferenceCategory category, int display) {
String displayUid;
HwcSvcDisplayMode currentMode;
ArrayList<HwcSvcDisplayMode> availableModes;
try {
displayUid = String.valueOf(DisplayUtils.makeDisplayLabel(mDisplayService
.edidGetInfo(display), display).hashCode());
currentMode = mDisplayService.getMode(display,
HwcSvcModeType.HWC_SVC_MODE_TYPE_CURRENT);
availableModes = mDisplayService.modeGetList(display);
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display info");
return;
}
// Sort by resolution and refresh rate
Collections.sort(availableModes, (Comparator<HwcSvcDisplayMode>) (a, b) -> {
HwcSvcDisplayMode modeA = (HwcSvcDisplayMode) a;
HwcSvcDisplayMode modeB = (HwcSvcDisplayMode) b;
if (modeA.xres == modeB.xres) {
if (modeA.yres == modeB.yres) {
if (modeA.refresh == modeB.refresh) {
if (modeA.flags > modeB.flags) {
return -1;
} else if (modeA.flags < modeB.flags) {
return 1;
} else {
return 0;
}
} else if (modeA.refresh > modeB.refresh) {
return -1;
} else {
return 1;
}
} else if (modeA.yres > modeB.yres) {
return -1;
} else {
return 1;
}
} else if (modeA.xres > modeB.xres) {
return -1;
} else {
return 1;
}
});
ListPreference modesPreference = new ListPreference(category.getContext());
ArrayList<String> displayedModes = new ArrayList<>();
ArrayList<String> modeIndices = new ArrayList<>();
availableModes.forEach((mode) -> displayedModes.add(DisplayUtils
.makeModeInfoString(mode) + " " + DisplayUtils.makeColorInfoString(mode)));
availableModes.forEach((mode) -> modeIndices.add(String.valueOf(mode.index)));
modesPreference.setEntries(displayedModes.toArray(
new CharSequence[displayedModes.size()]));
modesPreference.setEntryValues(modeIndices.toArray(
new CharSequence[modeIndices.size()]));
modesPreference.setTitle(R.string.mode_selection_title);
modesPreference.setSummary(DisplayUtils.makeModeInfoString(currentMode) + "\n"
+ DisplayUtils.makeColorInfoString(currentMode));
modesPreference.setKey("mode_" + displayUid);
modesPreference.setValue(String.valueOf(currentMode.index));
category.addPreference(modesPreference);
// Show checkbox to disable internal panel when an external display is connected
if (display == HwcSvcDisplay.HWC_SVC_DISPLAY_PANEL) {
SwitchPreference disableInternalOnExternalConnectedPreference =
new SwitchPreference(category.getContext());
disableInternalOnExternalConnectedPreference
.setTitle(R.string.disable_internal_on_external_connected_title);
disableInternalOnExternalConnectedPreference
.setSummaryOn(R.string.disable_internal_on_external_connected_summary_on);
disableInternalOnExternalConnectedPreference
.setSummaryOff(
R.string.disable_internal_on_external_connected_summary_off);
disableInternalOnExternalConnectedPreference
.setKey("disable_internal_on_external_connected");
category.addPreference(disableInternalOnExternalConnectedPreference);
if (sku.equals("fric")) {
createPanelModeSettings();
}
}
}
}
}
@@ -0,0 +1,425 @@
package org.lineageos.settings.device;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.hardware.nintendo.joycond.IJoycond;
import android.hardware.nintendo.joycond.KeyMap;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.util.Log;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplay;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplayMode;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcDisplayType;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcModeType;
import vendor.nvidia.hardware.graphics.display.V1_0.INvDisplay;
public class DisplaySettingsPrefsCommon {
private static final String TAG = DisplaySettingsPrefsCommon.class.getSimpleName();
public static final String JOYCOND_ANALOG_PROP = "persist.vendor.joycond.analog";
public static final String JOYCOND_COMBINED_PROP = "persist.vendor.joycond.combined";
private PreferenceFragmentCompat fragment;
private Activity activity;
private Resources res;
private INvDisplay mDisplayService;
private String sku;
private IJoycond mJoycond;
public DisplaySettingsPrefsCommon(PreferenceFragmentCompat fragment,
INvDisplay mDisplayService, String sku) {
this.fragment = fragment;
this.res = fragment.getResources();
this.activity = fragment.getActivity();
this.sku = sku;
this.mDisplayService = mDisplayService;
IBinder binder = ServiceManager.getService(IJoycond.DESCRIPTOR + "/default");
if (binder != null) {
mJoycond = IJoycond.Stub.asInterface(binder);
} else {
Log.e(TAG, "Failed to get Joycond service");
}
}
public void createJoyConSettings(PreferenceScreen preferenceScreen) {
int index;
boolean analog = true;
final List<KeyMap> mapping;
if (mJoycond == null) {
Log.w(TAG, "Joycond instance is null, skipping JoyCon settings creation...");
return;
}
// Analog trigger preference
SwitchPreference analogPref = fragment.findPreference("joycon_analog");
if (analogPref == null) {
Log.e(TAG, "No preference with key joycon_analog found! Skipping JoyCon settings creation...");
return;
}
PreferenceGroup group = analogPref.getParent();
try {
analog = mJoycond.getAnalog();
} catch (RemoteException e) {
Log.w(TAG, "Could not get analog preference! Inferring from prop...");
analog = SystemProperties.getBoolean(JOYCOND_ANALOG_PROP, true);
}
Log.i(TAG, "Joycond current analog value: " + String.valueOf(analog));
analogPref.setChecked(analog);
analogPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
try {
mJoycond.setAnalog((boolean) newValue);
} catch (RemoteException e) {
Log.w(TAG, "Could not set analog preference! Setting prop and deferring...");
SystemProperties.set(JOYCOND_ANALOG_PROP, (boolean) newValue ? "1" : "0");
}
return true;
}
});
// Controller mapping
try {
mapping = mJoycond.getLayout();
} catch (RemoteException e) {
Log.e(TAG, "Failed to get mapping!");
return;
}
// retrieve keys and mapped key names
final String[] keys = res.getStringArray(R.array.keys);
final String[] keysMap = res.getStringArray(R.array.keys_map);
// set up pref per key
for (index = 0; index < keys.length; index++) {
ListPreference pref = new ListPreference(group.getContext());
// key the preference from the index, indices will remain in sync
pref.setKey("joycon_map_" + String.valueOf(index));
pref.setTitle(keysMap[index]);
// get key name from index
int toIndex;
for (toIndex = 0; toIndex < keys.length; toIndex++) {
if (Integer.parseInt(keys[toIndex]) == mapping.get(index).to)
break;
}
pref.setSummary("Current value: " + keysMap[toIndex]);
pref.setValue(keys[toIndex]);
// options should be the key namaes
pref.setEntries(keysMap);
pref.setEntryValues(keys);
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final List<KeyMap> mapping;
// get again to handle changes
try {
mapping = mJoycond.getLayout();
} catch (RemoteException e) {
Log.e(TAG, "Failed to get mapping!");
return false;
}
// copy mapping
List<KeyMap> newMap = new ArrayList<KeyMap>(mapping);
// retrieve mapping index of this preference
int indexKey = Integer.parseInt(preference.getKey().substring(11));
// construct keymap and set
KeyMap change = new KeyMap();
change.from = Integer.parseInt(keys[indexKey]);
Log.w(TAG, "from: " + keys[indexKey] + " to: " + (String) newValue);
change.to = Integer.parseInt((String) newValue);
newMap.set(indexKey, change);
// get key name from index
int toIndex;
for (toIndex = 0; toIndex < keys.length; toIndex++) {
if (keys[toIndex].equals((String) newValue))
break;
}
pref.setSummary("Current value: " + keysMap[toIndex]);
for (KeyMap km : newMap) {
Log.w(TAG, "KeyMap Entry: from=" + km.from + ", to=" + km.to);
}
try {
mJoycond.setLayout(newMap);
} catch (RemoteException e) {
Log.e(TAG, "Failed to set layout!");
return false;
}
return true;
}
});
group.addPreference(pref);
}
}
public void createPerfSettings() {
SwitchPreference perfPreference = fragment.findPreference("perf_mode");
perfPreference.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (((Boolean) newValue) != PreferenceManager
.getDefaultSharedPreferences(activity)
.getBoolean("perf_mode", false)) {
final boolean isEnabled = (Boolean) newValue;
if (isEnabled) {
new AlertDialog.Builder(activity)
.setTitle(R.string.perf_warning_title)
.setMessage(R.string.perf_warning_summary)
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int whichButton) {
}
})
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int whichButton) {
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(activity);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putBoolean("perf_mode", true);
editor.commit();
perfPreference.setChecked(true);
}
})
.setOnDismissListener(
new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
Intent intent = new Intent(DisplayUtils.POWER_UPDATE_INTENT);
activity.sendBroadcast(intent);
}
})
.create().show();
return false;
}
}
Intent intent = new Intent(DisplayUtils.POWER_UPDATE_INTENT);
activity.sendBroadcast(intent);
return true;
}
});
}
private void createPanelModeSettings(PreferenceCategory category) {
ListPreference panelColorPref = new ListPreference(category.getContext());
String current = DisplayUtils.getPanelColorMode();
int index;
String[] modes = res.getStringArray(R.array.panel_modes);
String[] modeMap = res.getStringArray(R.array.panel_mode_map);
for (index = 0; index < modes.length; index++) {
if (current.equals(modes[index]))
break;
}
if (index == modes.length) {
Log.e(TAG, "Unsupported OLED panel mode! ID: " + current);
} else {
Log.w(TAG, "OLED Panel Mode Index: " + String.valueOf(index));
panelColorPref.setKey("panel_color_mode");
panelColorPref.setTitle(R.string.panel_color_setting_title);
panelColorPref.setEntries(R.array.panel_mode_map);
panelColorPref.setEntryValues(R.array.panel_modes);
panelColorPref.setValue(current);
panelColorPref.setSummary(modeMap[index]);
panelColorPref.setOnPreferenceChangeListener(
new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
int newIndex;
DisplayUtils.setPanelColorMode((String) newValue);
for (newIndex = 0; newIndex < modes.length; newIndex++) {
if (((String) newValue).equals(modes[newIndex])) {
panelColorPref.setSummary(modeMap[newIndex]);
break;
}
}
return true;
}
});
}
}
public void createDisplaySettings(PreferenceScreen preferenceScreen) {
if (mDisplayService == null) {
Log.e(TAG, "Display service is null! Skipping display settings creation.");
return;
}
for (int i = HwcSvcDisplay.HWC_SVC_DISPLAY_PANEL; i <= HwcSvcDisplay.HWC_SVC_DISPLAY_HDMI2; i++) {
PreferenceCategory category = new PreferenceCategory(
preferenceScreen.getContext());
if (!initializeDisplayCategory(category, i))
continue;
preferenceScreen.addPreference(category);
populateDisplayCategory(category, i);
}
}
private boolean initializeDisplayCategory(PreferenceCategory category,
int display) {
try {
int type = mDisplayService.displayGetType(display);
ArrayList<HwcSvcDisplayMode> availableModes = mDisplayService
.modeGetList(display);
if (availableModes.size() == 0)
return false; // Display is not connected
category.setTitle(DisplayUtils.makeDisplayLabel(mDisplayService
.edidGetInfo(display), display));
category.setSummary(HwcSvcDisplayType.toString(type));
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display info");
return false;
}
return true;
}
private void populateDisplayCategory(PreferenceCategory category, int display) {
String displayUid;
HwcSvcDisplayMode currentMode;
ArrayList<HwcSvcDisplayMode> availableModes;
try {
displayUid = String.valueOf(DisplayUtils.makeDisplayLabel(mDisplayService
.edidGetInfo(display), display).hashCode());
currentMode = mDisplayService.getMode(display,
HwcSvcModeType.HWC_SVC_MODE_TYPE_CURRENT);
availableModes = mDisplayService.modeGetList(display);
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display info");
return;
}
// Sort by resolution and refresh rate
Collections.sort(availableModes, (Comparator<HwcSvcDisplayMode>) (a, b) -> {
HwcSvcDisplayMode modeA = (HwcSvcDisplayMode) a;
HwcSvcDisplayMode modeB = (HwcSvcDisplayMode) b;
if (modeA.xres == modeB.xres) {
if (modeA.yres == modeB.yres) {
if (modeA.refresh == modeB.refresh) {
if (modeA.flags > modeB.flags)
return -1;
else if (modeA.flags < modeB.flags)
return 1;
else
return 0;
} else if (modeA.refresh > modeB.refresh)
return -1;
else
return 1;
} else if (modeA.yres > modeB.yres) {
return -1;
} else {
return 1;
}
} else if (modeA.xres > modeB.xres) {
return -1;
} else {
return 1;
}
});
ListPreference modesPreference = new ListPreference(category.getContext());
ArrayList<String> displayedModes = new ArrayList<>();
ArrayList<String> modeIndices = new ArrayList<>();
availableModes.forEach((mode) -> displayedModes.add(DisplayUtils
.makeModeInfoString(mode) + " " + DisplayUtils.makeColorInfoString(mode)));
availableModes.forEach((mode) -> modeIndices.add(String.valueOf(mode.index)));
modesPreference.setEntries(displayedModes.toArray(
new CharSequence[displayedModes.size()]));
modesPreference.setEntryValues(modeIndices.toArray(
new CharSequence[modeIndices.size()]));
modesPreference.setTitle(R.string.mode_selection_title);
modesPreference.setSummary(DisplayUtils.makeModeInfoString(currentMode) + "\n"
+ DisplayUtils.makeColorInfoString(currentMode));
modesPreference.setKey("mode_" + displayUid);
modesPreference.setValue(String.valueOf(currentMode.index));
category.addPreference(modesPreference);
// Show checkbox to disable internal panel when an external display is connected
if (display == HwcSvcDisplay.HWC_SVC_DISPLAY_PANEL) {
SwitchPreference disableInternalOnExternalConnectedPreference = new SwitchPreference(category.getContext());
disableInternalOnExternalConnectedPreference
.setTitle(R.string.disable_internal_on_external_connected_title);
disableInternalOnExternalConnectedPreference
.setSummaryOn(R.string.disable_internal_on_external_connected_summary_on);
disableInternalOnExternalConnectedPreference
.setSummaryOff(R.string.disable_internal_on_external_connected_summary_off);
disableInternalOnExternalConnectedPreference
.setKey("disable_internal_on_external_connected");
category.addPreference(disableInternalOnExternalConnectedPreference);
if (sku.equals("fric")) {
createPanelModeSettings(category);
}
}
}
}
@@ -24,7 +24,6 @@ import android.content.SharedPreferences;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManagerPolicyConstants;