nx: Import devicesettings from tegra-common 9c7025b

This is a baseline to modify

Change-Id: Ifaf5309ec0e2a15626571b667d567bc514082cad
This commit is contained in:
Aaron Kling authored and Nolen Johnson committed 2024-01-25 15:54:02 -05:00
1 parent 1148c4d66d
commit d088f2f0c3
21 files changed
+910

No files matched your search

+38
View File
@@ -0,0 +1,38 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_CERTIFICATE := platform
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PACKAGE_NAME := DeviceSettings
LOCAL_MODULE_TAGS := optional
LOCAL_USE_AAPT2 := true
LOCAL_STATIC_ANDROID_LIBRARIES := \
androidx.core_core \
androidx.preference_preference \
LOCAL_STATIC_JAVA_LIBRARIES := \
org.lineageos.platform.internal \
vendor.nvidia.hardware.graphics.display-V1.0-java
LOCAL_RESOURCE_DIR := \
$(LOCAL_PATH)/res \
$(TOP)/packages/resources/devicesettings/res
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_REQUIRED_MODULES := \
privapp-permissions-lineage-displaysettings.xml
include $(BUILD_PACKAGE)
include $(CLEAR_VARS)
LOCAL_MODULE := privapp-permissions-lineage-displaysettings.xml
LOCAL_MODULE_CLASS := ETC
LOCAL_SRC_FILES := permissions/privapp-permissions-lineage-displaysettings.xml
LOCAL_MODULE_RELATIVE_PATH := permissions
include $(BUILD_PREBUILT)
+63
View File
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.lineageos.settings.device"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-sdk
android:minSdkVersion="28"
android:targetSdkVersion="28" />
<application
android:icon="@mipmap/ic_launcher_settings"
android:label="@string/device_settings_app_name"
android:theme="@style/Theme.Main"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
android:persistent="true">
<service android:name=".DisplayService"
android:enabled="true"/>
<receiver android:name=".BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<provider
android:name=".DeviceSettingsSearchIndexablesProvider"
android:authorities="org.lineageos.settings.device"
android:multiprocess="false"
android:grantUriPermissions="true"
android:permission="android.permission.READ_SEARCH_INDEXABLES"
android:exported="true">
<intent-filter>
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
</intent-filter>
</provider>
<activity
android:name=".DisplaySettingsActivity"
android:label="@string/display_panel_title"
android:icon="@drawable/ic_settings_additional_buttons"
android:theme="@style/Theme.Main">
<intent-filter>
<action android:name="com.android.settings.action.IA_SETTINGS" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.system" />
<meta-data
android:name="com.android.settings.summary"
android:resource="@string/display_panel_summary" />
</activity>
</application>
</manifest>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<permissions>
<privapp-permissions package="org.lineageos.settings.device">
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
</privapp-permissions>
</permissions>
+3
View File
@@ -0,0 +1,3 @@
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2017 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M17,1L7,1C5.9,1,5,1.9,5,3v2h2v4H5v12c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V3C19,1.9,18.1,1,17,1z
M11,21H7v-2h4V21z M17,21 h-4v-2h4V21z" />
</vector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<integer name="mode_confirmation_wait_time">15</integer>
</resources>
+26
View File
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<string name="display_panel_title">Display Configuration</string>
<string name="display_panel_summary">Adjust external display and dock settings</string>
<string name="mode_selection_title">Select Mode</string>
<string name="mode_confirmation_title">Confirmation</string>
<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="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>
</resources>
+58
View File
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014-2016 The CyanogenMod Project
(C) 2020 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<style name="Theme.Main" parent="@android:style/Theme.DeviceDefault.Settings">
<item name="dialogPreferenceStyle">@style/Theme.Main.DialogPreferenceStyle</item>
<item name="preferenceCategoryStyle">@style/Theme.Main.PreferenceCategoryStyle</item>
<item name="preferenceFragmentStyle">@style/Theme.Main.PreferenceFragmentStyle</item>
<item name="preferenceStyle">@style/Theme.Main.PreferenceStyle</item>
<item name="preferenceTheme">@style/Theme.Main.PreferenceTheme</item>
<item name="switchPreferenceStyle">@style/Theme.Main.SwitchPreferenceStyle</item>
</style>
<style name="Theme.Main.DialogPreferenceStyle" parent="@*android:style/Preference.DeviceDefault.DialogPreference">
<item name="allowDividerAbove">false</item>
<item name="allowDividerBelow">true</item>
<item name="singleLineTitle">false</item>
<item name="android:iconSpaceReserved">true</item>
</style>
<style name="Theme.Main.PreferenceCategoryStyle" parent="@*android:style/Preference.DeviceDefault.Category">
<item name="allowDividerAbove">true</item>
<item name="allowDividerBelow">true</item>
<item name="android:layout">@layout/preference_category_material_settings</item>
</style>
<style name="Theme.Main.PreferenceFragmentStyle" parent="@*android:style/PreferenceFragment.Material">
<item name="allowDividerAfterLastItem">false</item>
</style>
<style name="Theme.Main.PreferenceStyle" parent="@*android:style/Preference.DeviceDefault">
<item name="allowDividerAbove">false</item>
<item name="allowDividerBelow">true</item>
<item name="singleLineTitle">false</item>
<item name="android:layout">@layout/preference_material_settings</item>
</style>
<style name="Theme.Main.PreferenceTheme">
</style>
<style name="Theme.Main.SwitchPreferenceStyle" parent="@style/Theme.Main.PreferenceStyle">
<item name="widgetLayout">@*android:layout/preference_widget_switch</item>
</style>
</resources>
+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2020 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
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
</PreferenceScreen>
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2020 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.settings.device;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, DisplayService.class));
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2017 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.settings.device;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.provider.SearchIndexableResource;
import android.provider.SearchIndexablesProvider;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_ICON_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_ACTION;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RANK;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS;
public class DeviceSettingsSearchIndexablesProvider extends SearchIndexablesProvider {
public static final int SEARCH_IDX_BUTTON_PANEL = 0;
private static final String TAG = "ConfigPanelSearchIndexablesProvider";
private static SearchIndexableResource[] INDEXABLE_RES = new SearchIndexableResource[]{
new SearchIndexableResource(1, R.xml.display_panel,
DisplaySettingsActivity.class.getName(),
R.drawable.ic_settings_additional_buttons),
};
private static Object[] generateResourceRef(SearchIndexableResource sir) {
Object[] ref = new Object[7];
ref[COLUMN_INDEX_XML_RES_RANK] = sir.rank;
ref[COLUMN_INDEX_XML_RES_RESID] = sir.xmlResId;
ref[COLUMN_INDEX_XML_RES_CLASS_NAME] = null;
ref[COLUMN_INDEX_XML_RES_ICON_RESID] = sir.iconResId;
ref[COLUMN_INDEX_XML_RES_INTENT_ACTION] = "com.android.settings.action.EXTRA_SETTINGS";
ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE] = "org.lineageos.settings.device";
ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS] = sir.className;
return ref;
}
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor queryXmlResources(String[] projection) {
MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
cursor.addRow(generateResourceRef(INDEXABLE_RES[SEARCH_IDX_BUTTON_PANEL]));
return cursor;
}
@Override
public Cursor queryRawData(String[] projection) {
MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
return cursor;
}
@Override
public Cursor queryNonIndexableKeys(String[] projection) {
MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS);
return cursor;
}
}
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2020 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.settings.device;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.util.Log;
import android.view.WindowManagerPolicyConstants;
public class DisplayService extends Service {
private static final String TAG = DisplayService.class.getSimpleName();
final Receiver mReceiver = new Receiver();
@Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mReceiver.init();
return super.onStartCommand(intent, flags, startId);
}
final class Receiver extends BroadcastReceiver {
private boolean mExternalDisplayConnected = false;
public void init() {
IntentFilter filter = new IntentFilter();
filter.addAction(WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(this, filter);
}
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPrefs = context.getSharedPreferences("org.lineageos.settings.device_preferences", context.MODE_PRIVATE);
Log.w(TAG, intent.getAction());
String action = intent.getAction();
switch (action) {
case WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED:
mExternalDisplayConnected = intent.getBooleanExtra(WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE, false);
case Intent.ACTION_SCREEN_ON:
DisplayUtils.setInternalDisplayState(!(mExternalDisplayConnected && sharedPrefs.getBoolean("disable_internal_on_external_connected", false)));
default:
break;
}
}
}
;
}
@@ -0,0 +1,80 @@
/*
* Copyright (C) 2020 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.settings.device;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.view.WindowManagerPolicyConstants;
public class DisplaySettingsActivity extends PreferenceActivity {
public final Receiver mReceiver = new Receiver();
private DisplaySettingsFragment mFragment;
public boolean mExternalDisplayConnected;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mFragment = new DisplaySettingsFragment();
getFragmentManager().beginTransaction().replace(android.R.id.content, mFragment).commit();
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mReceiver);
}
protected void onResume() {
super.onResume();
mReceiver.init(this);
}
final class Receiver extends BroadcastReceiver {
private boolean mReceivedInitialIntent = false;
public boolean mBlocked;
public void init(Context context) {
// Refresh UI on external display status change
IntentFilter filter = new IntentFilter();
filter.addAction(WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED);
mReceivedInitialIntent = false;
context.registerReceiver(this, filter);
}
public void onReceive(Context context, Intent intent) {
mExternalDisplayConnected = intent.getBooleanExtra(WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE, false);
if (mBlocked)
return;
if (mReceivedInitialIntent)
recreate();
mReceivedInitialIntent = true;
}
}
;
}
@@ -0,0 +1,286 @@
/*
* Copyright (C) 2020 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.settings.device;
import android.app.ActionBar;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.RemoteException;
import android.util.Log;
import android.view.MenuItem;
import android.app.AlertDialog;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceFragment;
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
implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = DisplaySettingsFragment.class.getSimpleName();
public boolean mInModeChange = false;
private INvDisplay mDisplayService;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
try {
mDisplayService = INvDisplay.getService(true /* retry */);
} catch (RemoteException e) {
}
addPreferencesFromResource(R.xml.display_panel);
PreferenceScreen preferenceScreen = this.getPreferenceScreen();
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);
}
final ActionBar actionBar = getActivity().getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
}
@Override
public void onResume() {
super.onResume();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
prefs.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
super.onPause();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
getActivity().onBackPressed();
return true;
}
return false;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPrefs, String key) {
HashMap<String, Integer> uidMap = DisplayUtils.makeUidMap(mDisplayService);
if (key.startsWith("mode_")) {
String hash = key.substring(5);
int display = uidMap.getOrDefault(hash, -1);
if (display >= 0) {
int modeIndex = Integer.valueOf(sharedPrefs.getString(key, ""));
((DisplaySettingsActivity)getActivity()).mReceiver.mBlocked = true;
performModeChange(sharedPrefs, key, modeIndex, display);
}
return;
}
if (key.equals("disable_internal_on_external_connected")) {
DisplayUtils.setInternalDisplayState(!(((DisplaySettingsActivity)getActivity()).mExternalDisplayConnected && sharedPrefs.getBoolean(key, false)));
return;
}
}
private void performModeChange(SharedPreferences sharedPrefs, String key, int modeIndex, int display) {
try {
mDisplayService.modeDefaultSetIndex(display, modeIndex);
} catch (RemoteException e) {
Log.e(TAG, "Failed to set default display mode");
return;
}
DialogInterface.OnClickListener confirmationDialogClickListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
try {
mDisplayService.modeDefaultCommit(display);
mDisplayService.modeDefaultStore(display);
} catch (RemoteException e) {
Log.e(TAG, "Failed to save default display mode");;
}
break;
case DialogInterface.BUTTON_NEGATIVE:
try {
mDisplayService.modeDefaultRollback(display);
mDisplayService.modeUpdate(display);
} catch (RemoteException e) {
Log.e(TAG, "Failed to rollback display mode");
}
break;
}
HwcSvcDisplayMode currentMode;
try {
currentMode = mDisplayService.getMode(display, HwcSvcModeType.HWC_SVC_MODE_TYPE_CURRENT);
} catch (RemoteException e) {
Log.e(TAG, "Failed to read display mode");
((DisplaySettingsActivity)getActivity()).mReceiver.mBlocked = false;
getActivity().recreate();
return;
}
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString(key, String.valueOf(currentMode.index));
editor.commit();
((DisplaySettingsActivity)getActivity()).mReceiver.mBlocked = false;
getActivity().recreate();
}
};
int waitTime = getResources().getInteger(R.integer.mode_confirmation_wait_time);
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));
AlertDialog confirmationDialog = builder.create();
confirmationDialog.show();
new CountDownTimer(waitTime * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
if (confirmationDialog != null && isAdded())
confirmationDialog.setMessage(getString(R.string.mode_confirmation_summary, millisUntilFinished / 1000));
}
@Override
public void onFinish() {
if (confirmationDialog != null && isAdded())
confirmationDialog.getButton(DialogInterface.BUTTON_NEGATIVE).performClick();
}
}.start();
}
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, new Comparator() {
public int compare(Object a, Object b) {
HwcSvcDisplayMode modeA = (HwcSvcDisplayMode) a;
HwcSvcDisplayMode modeB = (HwcSvcDisplayMode) b;
if (modeA.xres == modeB.xres) {
if (modeA.yres == modeB.yres) {
if (modeA.refresh == modeB.refresh)
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<String>();
ArrayList<String> modeIndices = new ArrayList<String>();
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);
}
}
}
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2019 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.lineageos.settings.device;
import android.os.RemoteException;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Arrays;
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.HwcSvcDisplayModePixEnc;
import vendor.nvidia.hardware.graphics.display.V1_0.HwcSvcEdidInfo;
import vendor.nvidia.hardware.graphics.display.V1_0.INvDisplay;
public class DisplayUtils {
private static final String TAG = DisplayUtils.class.getSimpleName();
public static void setInternalDisplayState(boolean state) {
Log.d(TAG, "setInternalDisplayState: " + String.valueOf(state));
try {
FileOutputStream enableFile = new FileOutputStream("/sys/bus/platform/devices/tegradc.0/enable");
byte[] buf = new byte[2];
buf[0] = (byte) (state ? '1' : '0');
buf[1] = '\n';
enableFile.write(buf);
enableFile.close();
} catch (IOException e) {
Log.w(TAG, "Failed to write display state");
}
}
public static HashMap<String, Integer> makeUidMap(INvDisplay displayService) {
HashMap<String, Integer> uidMap = new HashMap<String, Integer>();
for (int i = HwcSvcDisplay.HWC_SVC_DISPLAY_PANEL; i <= HwcSvcDisplay.HWC_SVC_DISPLAY_HDMI2; i++) {
try {
String displayUid = String.valueOf(makeDisplayLabel(displayService.edidGetInfo(i), i).hashCode()); // A unique id we can use to identify the display
uidMap.put(displayUid, i);
} catch (RemoteException e) {
continue;
}
}
return uidMap;
}
public static String makeDisplayLabel(HwcSvcEdidInfo edid, int display) {
if (!edid.monitor_name.isEmpty())
return (edid.manufacturer_id.isEmpty() ? "" : (edid.manufacturer_id + " - ")) + edid.monitor_name; // Report name from edid if present
if (display == HwcSvcDisplay.HWC_SVC_DISPLAY_PANEL)
return "Internal Panel"; // Most internal panels do not have an edid
return "Unknown";
}
public static String makeModeInfoString(HwcSvcDisplayMode mode) {
return String.format("%dx%d %sHz", mode.xres, mode.yres, new DecimalFormat("###.##").format(mode.refresh));
}
public static String makeColorInfoString(HwcSvcDisplayMode mode) {
String encodingStr = "";
String colorimetryStr = "";
switch (mode.pixenc) {
case HwcSvcDisplayModePixEnc.HWC_SVC_DISP_PIXENC_YUV444:
encodingStr = "YUV444";
break;
case HwcSvcDisplayModePixEnc.HWC_SVC_DISP_PIXENC_YUV422:
encodingStr = "YUV422";
break;
case HwcSvcDisplayModePixEnc.HWC_SVC_DISP_PIXENC_YUV420:
encodingStr = "YUV420";
break;
default:
encodingStr = "RGB";
break;
}
if (mode.colorimetry != 1)
colorimetryStr = "Rec. 709";
else
colorimetryStr = "Rec. 2020";
return String.format("%s %d-bit %s", encodingStr, mode.bpc, colorimetryStr);
}
}