redwood: Import XiaomiParts from surya device tree

This commit is contained in:
chrisl7
2024-09-25 19:30:47 +05:30
committed by thepriyanshujangid
parent 8b66ff518e
commit 25d218e190
51 changed files with 3352 additions and 0 deletions

View File

@@ -153,6 +153,13 @@ PRODUCT_PACKAGES += \
# DebugFS
PRODUCT_SET_DEBUGFS_RESTRICTIONS := true
# Device Settings
PRODUCT_PACKAGES += \
XiaomiParts
PRODUCT_COPY_FILES += \
$(LOCAL_PATH)/parts/privapp-permissions-parts.xml:$(TARGET_COPY_OUT_SYSTEM_EXT)/etc/permissions/privapp-permissions-parts.xml
# Display
PRODUCT_PACKAGES += \
android.hardware.graphics.mapper@3.0-impl-qti-display \

28
parts/Android.bp Executable file
View File

@@ -0,0 +1,28 @@
//
// Copyright (C) 2017-2020 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
android_app {
name: "XiaomiParts",
srcs: ["src/**/*.java"],
certificate: "platform",
platform_apis: true,
system_ext_specific: true,
privileged: true,
static_libs: [
"androidx.core_core",
"androidx.preference_preference",
"org.lineageos.settings.resources",
"SettingsLib",
],
optimize: {
proguard_flags_files: ["proguard.flags"],
},
}

114
parts/AndroidManifest.xml Executable file
View File

@@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.lineageos.settings"
android:versionCode="4"
android:versionName="4.0"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application
android:label="@string/device_settings_app_name"
android:persistent="true"
android:directBootAware="true">
<!-- TODO after package rename in U:
android:defaultToDeviceProtectedStorage="true" -->
<receiver
android:name=".BootCompletedReceiver"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name=".refreshrate.RefreshActivity"
android:label="@string/refresh_title"
android:exported="true"
android:theme="@style/Theme.SubSettingsBase">
<intent-filter>
<action android:name="com.android.settings.action.IA_SETTINGS" />
</intent-filter>
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.display" />
<meta-data
android:name="com.android.settings.summary"
android:resource="@string/refresh_summary" />
</activity>
<service
android:name=".refreshrate.RefreshService"
android:permission="RefreshService">
</service>
<activity
android:name=".TileEntryActivity"
android:label="@string/device_settings_app_name"
android:exported="true"
android:theme="@style/Theme.SubSettingsBase">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
</intent-filter>
</activity>
<service
android:name=".refreshrate.RefreshTileService"
android:exported="true"
android:icon="@drawable/ic_refresh_tile"
android:label="@string/refresh_rate_tile_title"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE"/>
</intent-filter>
</service>
<activity
android:name=".speaker.ClearSpeakerActivity"
android:exported="true"
android:label="@string/clear_speaker_title"
android:theme="@style/Theme.SubSettingsBase">
<intent-filter>
<action android:name="com.android.settings.action.IA_SETTINGS" />
</intent-filter>
<meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.sound" />
<meta-data android:name="com.android.settings.summary"
android:resource="@string/clear_speaker_summary" />
</activity>
<activity
android:name=".thermal.ThermalSettingsActivity"
android:exported="true"
android:label="@string/thermal_title"
android:theme="@style/Theme.SubSettingsBase">
<intent-filter>
<action android:name="com.android.settings.action.IA_SETTINGS" />
</intent-filter>
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.battery" />
<meta-data
android:name="com.android.settings.summary"
android:resource="@string/thermal_summary" />
</activity>
<activity
android:name=".thermal.TouchSettingsActivity"
android:theme="@style/Theme.SubSettingsBase"
android:exported="true" />
<service
android:name=".thermal.ThermalService"
android:permission="ThermalService">
</service>
</application>
</manifest>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2017-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.
-->
<permissions>
<privapp-permissions package="org.lineageos.settings">
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
</privapp-permissions>
</permissions>

3
parts/proguard.flags Executable file
View File

@@ -0,0 +1,3 @@
-keep class org.lineageos.settings.* {
*;
}

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M17 1.01L7 1C5.9 1 5 1.9 5 3v4h2V3h10v18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M1 8v1.56h1.56v6.22H4.1V8H1Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M4.89 8v1.56H8v1.55H6.44c-0.4 0-0.8 0.17-1.1 0.46-0.29 0.29-0.45 0.68-0.45 1.1v3.1h4.67v-1.55H6.44v-1.55H8c0.41 0 0.8-0.17 1.1-0.46 0.3-0.3 0.46-0.69 0.46-1.1V9.56c0-0.42-0.17-0.81-0.46-1.1C8.8 8.16 8.41 8 8 8H4.89Z"/>
<path
android:fillColor="#ff000000"
android:strokeColor="#ff000000"
android:strokeWidth="1"
android:pathData="M11.89 9.06h-0.5v0.5 4.66 0.5h0.5 1.55 0.5v-0.5-4.66-0.5h-0.5-1.55ZM11.14 8.8c0.2-0.2 0.47-0.31 0.75-0.31h1.55c0.28 0 0.55 0.11 0.75 0.3 0.2 0.2 0.31 0.48 0.31 0.76v4.66c0 0.28-0.11 0.55-0.3 0.75-0.2 0.2-0.48 0.3-0.76 0.3H11.9c-0.28 0-0.55-0.1-0.75-0.3-0.2-0.2-0.3-0.47-0.3-0.75V9.56c0-0.28 0.1-0.55 0.3-0.75Z"/>
</vector>

View File

@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M6.55 8c-0.4 0-0.8 0.16-1.1 0.46C5.17 8.75 5 9.14 5 9.56v4.66c0 0.4 0.16 0.8 0.46 1.1 0.29 0.29 0.68 0.45 1.1 0.45H8.1c0.41 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1v-1.55c0-0.41-0.16-0.8-0.45-1.1-0.3-0.29-0.69-0.45-1.1-0.45H6.55V9.55h3.11V8h-3.1Zm0 4.66h1.56v1.56H6.55v-1.56Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M12 8c-0.42 0-0.81 0.16-1.1 0.46-0.3 0.29-0.46 0.68-0.46 1.1v4.66c0 0.4 0.16 0.8 0.45 1.1 0.3 0.29 0.69 0.45 1.1 0.45h1.56c0.4 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1V9.56c0-0.4-0.16-0.8-0.46-1.1C14.35 8.17 13.96 8 13.54 8H12Zm0 1.55h1.55v4.67h-1.56V9.55Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M17 1.01L7 1C5.9 1 5 1.9 5 3v4h2V3h10v18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99Z"/>
</vector>

View File

@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M17 1.01L7 1C5.9 1 5 1.9 5 3v4h2V3h10v18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M8.1 15.77c0.42 0 0.82-0.16 1.1-0.46 0.3-0.29 0.46-0.68 0.46-1.1V9.56c0-0.4-0.16-0.8-0.45-1.1C8.9 8.17 8.52 8 8.1 8H6.55c-0.4 0-0.8 0.16-1.1 0.46C5.17 8.75 5 9.14 5 9.56v1.55c0 0.41 0.16 0.8 0.46 1.1 0.29 0.29 0.68 0.45 1.1 0.45H8.1v1.56H5v1.55h3.1Zm0-4.66H6.56V9.55h1.56v1.56Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M12 8c-0.42 0-0.81 0.16-1.1 0.46-0.3 0.29-0.46 0.68-0.46 1.1v4.66c0 0.4 0.16 0.8 0.45 1.1 0.3 0.29 0.69 0.45 1.1 0.45h1.56c0.4 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1V9.56c0-0.4-0.16-0.8-0.46-1.1C14.35 8.17 13.96 8 13.54 8H12Zm0 1.55h1.55v4.67h-1.56V9.55Z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M17 3.01V15l2 2V3.01c0-1.1-0.9-1.99-2-1.99L7 1C6 0.99 5 1.99 5 2.99L7 5V3.01h10Zm4.2 18.19L19 19.01l-2-2-10-10-2-2-2.19-2.19L1.4 4.23 5 7.84v13.17c0 1.1 0.9 2 2 2h10c0.85 0 1.58-0.55 1.87-1.3l0.91 0.91 1.41-1.42ZM17 21.01H7L17 21v-0.99 1Zm-10 0V9.84l10 10.17V21L7 21.01Z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#ff000000"
android:pathData="M7 3h10v4h2V3c0-1.1-0.9-1.99-2-1.99L7 1C5.9 1 5 1.9 5 3v5 4H2l4 4 4-4H7V3Zm10 18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2v-5-4h3l-4-4-4 4h3v0.22V21Z"/>
</vector>

View File

@@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M21.12 7.88l-1.54 1.54C19.85 10.23 20 11.1 20 12c0 4.41-3.59 8-8 8s-8-3.59-8-8s3.59-8 8-8c0.9 0 1.77 0.15 2.58 0.42l1.53-1.53C14.85 2.32 13.46 2 12 2C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10c0-1.47-0.32-2.86-0.88-4.12z"/>
<path
android:fillColor="#ff000000"
android:pathData="M10.5 13.71c0.18 0.19 0.4 0.33 0.65 0.44c0.24 0.1 0.5 0.15 0.76 0.15c0.27 0 0.53-0.05 0.77-0.15c0.24-0.1 0.46-0.25 0.65-0.44l5.66-8.49l-8.5 5.66c-0.18 0.19-0.33 0.4-0.43 0.65c-0.1 0.24-0.15 0.5-0.15 0.77c0 0.26 0.05 0.52 0.15 0.76c0.1 0.24 0.25 0.47 0.44 0.65z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M20 5h-3.17L15 3H9L7.17 5H4C2.9 5 2 5.9 2 7v12c0 1.1 0.9 2 2 2h16c1.1 0 2-0.9 2-2V7c0-1.1-0.9-2-2-2zm0 14H4V7h16v12zM12 9c-2.21 0-4 1.79-4 4s1.79 4 4 4s4-1.79 4-4s-1.79-4-4-4z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8c0-1.85 0.63-3.55 1.69-4.9L16.9 18.31c-1.4 1.1-3.12 1.7-4.9 1.69zm6.31-3.1L7.1 5.69C8.5 4.59 10.22 3.99 12 4c4.42 0 8 3.58 8 8c0 1.85-0.63 3.55-1.69 4.9z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M6.54 5C6.6 5.89 6.75 6.76 6.99 7.59l-1.2 1.2C5.38 7.59 5.12 6.32 5.03 5h1.51zm9.86 12.02c0.85 0.24 1.72 0.39 2.6 0.45v1.49c-1.32-0.09-2.59-0.35-3.8-0.75l1.2-1.19zM7.5 3H4C3.45 3 3 3.45 3 4c0 9.39 7.61 17 17 17c0.55 0 1-0.45 1-1v-3.49c0-0.55-0.45-1-1-1c-1.24 0-2.45-0.2-3.57-0.57c-0.1-0.04-0.2-0.05-0.31-0.05c-0.26 0-0.51 0.1-0.71 0.29l-2.2 2.2c-2.83-1.45-5.14-3.76-6.59-6.59l2.2-2.2C9.1 8.31 9.18 7.92 9.07 7.57C8.69 6.42 8.5 5.21 8.5 4c0-0.55-0.45-1-1-1z"/>
</vector>

View File

@@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#ff000000"
android:pathData="M21 6H3C1.9 6 1 6.9 1 8v8c0 1.1 0.9 2 2 2h18c1.1 0 2-0.9 2-2V8c0-1.1-0.9-2-2-2Zm0 10H3V8h18v8ZM6 15h2v-2h2v-2H8V9H6v2H4v2h2v2Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M14.5 15c0.83 0 1.5-0.67 1.5-1.5S15.33 12 14.5 12 13 12.67 13 13.5s0.67 1.5 1.5 1.5Z"/>
<path
android:fillColor="#ff000000"
android:pathData="M18.5 12c0.83 0 1.5-0.67 1.5-1.5S19.33 9 18.5 9 17 9.67 17 10.5s0.67 1.5 1.5 1.5Z"/>
</vector>

14
parts/res/drawable/ic_touch.xml Executable file
View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#FF000000"
android:pathData="M22.99 5.7l0.01 10c0 1.1-0.9 2-2 2h-2.97v-2H21v-10H3v10h3v2H3c-1.1 0-2-0.9-2-2v-10c0-1.1 0.9-2 2-2h18c1.1 0 1.99 0.9 1.99 2Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M15.51 15.96l-2.42-1.2c-0.09-0.04-0.18-0.06-0.28-0.06H12.4v-3.2c0-0.44-0.36-0.8-0.8-0.8-0.44 0-0.8 0.36-0.8 0.8v5.73c-1.92-0.4-1.89-0.4-1.96-0.4-0.16 0-0.31 0.07-0.42 0.17L8 17.43l2.63 2.64c0.15 0.14 0.35 0.23 0.57 0.23h3.62c0.4 0 0.71-0.3 0.77-0.68l0.4-2.81L16 16.7c0-0.33-0.2-0.62-0.49-0.74Z"/>
</vector>

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015 The Android Open Source Project
(C) 2018-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.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<FrameLayout
android:id="@android:id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/summary">
<ImageView
android:id="@android:id/icon"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_marginEnd="12dp"
android:layout_gravity="start|center_vertical" />
</FrameLayout>
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@android:id/icon_frame"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:textColor="?android:attr/textColorPrimary" />
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_toEndOf="@android:id/icon_frame"
android:maxLines="4"
android:paddingTop="8dp"
android:paddingBottom="5dp"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary" />
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_below="@android:id/summary"
android:layout_gravity="center_vertical"
android:layout_toEndOf="@android:id/icon_frame"
android:tickMark="@null"
android:paddingStart="0dp"
android:paddingEnd="12dp"
style="@android:style/Widget.Material.SeekBar.Discrete" />
</RelativeLayout>

View File

@@ -0,0 +1,18 @@
<?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.
-->
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/refresh_rv_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@@ -0,0 +1,73 @@
<?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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="4dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingTop="4dp">
<ImageView
android:id="@+id/app_icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:layout_marginEnd="8dp"
android:layout_gravity="center_vertical"
android:scaleType="centerInside" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorPrimary"
style="?android:attr/textAppearanceMedium" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<Spinner
android:id="@+id/app_mode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView
android:id="@+id/state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:scaleType="centerInside"
android:src="@drawable/ic_refresh_default" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

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.
-->
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/thermal_rv_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical" />

View File

@@ -0,0 +1,82 @@
<?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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingBottom="4dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingTop="4dp">
<ImageView
android:id="@+id/app_icon"
android:layout_width="@android:dimen/app_icon_size"
android:layout_height="@android:dimen/app_icon_size"
android:layout_marginEnd="8dp"
android:layout_gravity="center_vertical"
android:scaleType="centerInside" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="8dp"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/app_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:singleLine="true"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorPrimary"
style="?android:attr/textAppearanceMedium" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<Spinner
android:id="@+id/app_mode"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<ImageView
android:id="@+id/touch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:scaleType="centerInside"
android:src="@drawable/ic_touch"
android:visibility="invisible" />
<ImageView
android:id="@+id/state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:scaleType="centerInside"
android:src="@drawable/ic_thermal_default" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

Binary file not shown.

32
parts/res/values/integers.xml Executable file
View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 20 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>
<!-- Gaming Profiles -->
<integer name="touch_response_default">3</integer>
<integer name="touch_response_max">3</integer>
<integer name="touch_sensitivity_default">0</integer>
<integer name="touch_sensitivity_max">2</integer>
<integer name="touch_resistant_default">2</integer>
<integer name="touch_resistant_max">3</integer>
<!-- Refresh Rate -->
<integer-array name="refresh_rate_tile_blocklist">
<item>30</item>
<item>48</item>
<item>50</item>
</integer-array>
</resources>

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013-2016 The CyanogenMod Project
2017-2022 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>
<!-- Clear Speaker -->
<string name="clear_speaker_title">Clear speaker</string>
<string name="clear_speaker_summary">Play a 30-second audio to clear the speaker</string>
<string name="clear_speaker_description">Run this feature once or twice if you find that your speaker is lightly blocked by dust. Set media volume to maximum.\n\nIf the speaker is blocked heavily, run this feature 2-5 times while shaking your device with the speaker facing downwards.</string>
<!-- Thermal profiles -->
<string name="thermal_title">Optimization profiles</string>
<string name="thermal_summary">Adjust per-app profiles for optimum performance</string>
<string name="thermal_default">No optimization</string>
<string name="thermal_benchmark">Performance</string>
<string name="thermal_camera">Camera</string>
<string name="thermal_dialer">Dialer</string>
<string name="thermal_gaming">Games</string>
<!-- Touch Control Settings -->
<string name="touch_control_title">Touch screen optimizations</string>
<string name="touch_game_mode_title">Enable game mode</string>
<string name="touch_game_mode_summary">Helps to improve the gaming experience by optimizing the touch screen</string>
<string name="touch_response_title">Touch response</string>
<string name="touch_response_summary">Controls touch response</string>
<string name="touch_sensitivity_title">Touch sensitivity</string>
<string name="touch_sensitivity_summary">Controls the sensitivity for repeated taps</string>
<string name="touch_resistant_title">Touch-resistant area</string>
<string name="touch_resistant_summary">Reduces sensitivity near the edges to prevent accidental touches</string>
<!-- Refresh Rate per-app -->
<string name="refresh_rate_tile_title">Refresh Rate</string>
<string name="refresh_title">Refresh rate per-app</string>
<string name="refresh_summary">Set a specific refresh rate for each application</string>
<string name="refresh_default">Default</string>
<string name="refresh_medium">Medium (60Hz)</string>
<string name="refresh_high">High (90Hz)</string>
<string name="refresh_extreme">Extreme (120Hz)</string>
</resources>

20
parts/res/values/styles.xml Executable file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2015-2016 The CyanogenMod Project
2017-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="TextAppearance.Medium" parent="@android:style/TextAppearance.Material.Medium" />
</resources>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/clear_speaker_title">
<SwitchPreference
android:key="clear_speaker_pref"
android:title="@string/clear_speaker_title"
android:summary="@string/clear_speaker_summary"/>
<com.android.settingslib.widget.FooterPreference
android:key="footer_preference"
android:title="@string/clear_speaker_description"
android:selectable="false" />
</PreferenceScreen>

View File

@@ -0,0 +1,49 @@
<?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">
<SwitchPreference
android:defaultValue="false"
android:key="touch_game_mode"
android:summary="@string/touch_game_mode_summary"
android:title="@string/touch_game_mode_title" />
<org.lineageos.settings.widget.SeekBarPreference
android:key="touch_response"
android:title="@string/touch_response_title"
android:summary="@string/touch_response_summary"
android:layout="@layout/preference_slider"
android:defaultValue="@integer/touch_response_default"
android:max="@integer/touch_response_max" />
<org.lineageos.settings.widget.SeekBarPreference
android:key="touch_sensitivity"
android:title="@string/touch_sensitivity_title"
android:summary="@string/touch_sensitivity_summary"
android:layout="@layout/preference_slider"
android:defaultValue="@integer/touch_sensitivity_default"
android:max="@integer/touch_sensitivity_max" />
<org.lineageos.settings.widget.SeekBarPreference
android:key="touch_resistant"
android:title="@string/touch_resistant_title"
android:summary="@string/touch_resistant_summary"
android:layout="@layout/preference_slider"
android:defaultValue="@integer/touch_resistant_default"
android:max="@integer/touch_resistant_max" />
</PreferenceScreen>

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* 2017-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;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import androidx.preference.PreferenceManager;
import android.util.Log;
import org.lineageos.settings.utils.FileUtils;
import org.lineageos.settings.thermal.ThermalUtils;
import org.lineageos.settings.refreshrate.RefreshUtils;
public class BootCompletedReceiver extends BroadcastReceiver {
private static final boolean DEBUG = false;
private static final String TAG = "XiaomiParts";
@Override
public void onReceive(final Context context, Intent intent) {
Log.i(TAG, "Received intent: " + intent.getAction());
switch (intent.getAction()) {
case Intent.ACTION_LOCKED_BOOT_COMPLETED:
onLockedBootCompleted(context);
break;
case Intent.ACTION_BOOT_COMPLETED:
onBootCompleted(context);
break;
}
}
private static void onLockedBootCompleted(Context context) {
// Services that don't require reading from data.
}
private static void onBootCompleted(Context context) {
// Data is now accessible (user has just unlocked).
RefreshUtils.initialize(context);
ThermalUtils.startService(context);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
*
* 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;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
import org.lineageos.settings.refreshrate.RefreshActivity;
public class TileEntryActivity extends Activity {
private static final String TAG = "TileEntryActivity";
private static final String REFRESH_TILE = "org.lineageos.settings.refreshrate.RefreshTileService";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ComponentName sourceClass = getIntent().getParcelableExtra(Intent.EXTRA_COMPONENT_NAME);
switch (sourceClass.getClassName()) {
case REFRESH_TILE:
openActivitySafely(new Intent(this, RefreshActivity.class));
break;
default:
finish();
break;
}
}
private void openActivitySafely(Intent dest) {
try {
dest.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
finish();
startActivity(dest);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "No activity found for " + dest);
finish();
}
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2020-2022 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.refreshrate;
import android.os.Bundle;
import android.view.MenuItem;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
public class RefreshActivity extends CollapsingToolbarBaseActivity {
private static final String TAG_REFRESH = "refresh";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
new RefreshSettingsFragment(), TAG_REFRESH).commit();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return false;
}
}

View File

@@ -0,0 +1,117 @@
/*
* 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.refreshrate;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.IActivityTaskManager;
import android.app.Service;
import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.os.RemoteException;
public class RefreshService extends Service {
private static final String TAG = "RefreshService";
private static final boolean DEBUG = true;
private String mPreviousApp;
private RefreshUtils mRefreshUtils;
private IActivityTaskManager mActivityTaskManager;
private final TaskStackListener mTaskListener = new TaskStackListener() {
@Override
public void onTaskStackChanged() {
try {
final RootTaskInfo info = mActivityTaskManager.getFocusedRootTaskInfo();
if (info == null || info.topActivity == null) {
return;
}
String foregroundApp = info.topActivity.getPackageName();
if (!foregroundApp.equals(mPreviousApp)) {
mRefreshUtils.setRefreshRate(foregroundApp);
mPreviousApp = foregroundApp;
}
} catch (Exception e) {}
}
};
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mPreviousApp = "";
mRefreshUtils.setDefaultRefreshRate(context);
}
};
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
mRefreshUtils = new RefreshUtils(this);
mRefreshUtils.setDefaultRefreshRate(this);
try {
mActivityTaskManager = ActivityTaskManager.getService();
mActivityTaskManager.registerTaskStackListener(mTaskListener);
} catch (RemoteException e) {
// Do nothing
}
registerReceiver();
super.onCreate();
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "Destroying service");
unregisterReceiver();
try {
ActivityTaskManager.getService().unregisterTaskStackListener(mTaskListener);
} catch (RemoteException e) {
// Do nothing
}
mRefreshUtils.setDefaultRefreshRate(this);
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void registerReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
this.registerReceiver(mIntentReceiver, filter);
}
private void unregisterReceiver() {
this.unregisterReceiver(mIntentReceiver);
}
}

View File

@@ -0,0 +1,415 @@
/**
* 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.refreshrate;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SectionIndexer;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceFragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.android.settingslib.applications.ApplicationsState;
import org.lineageos.settings.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RefreshSettingsFragment extends PreferenceFragment
implements ApplicationsState.Callbacks {
private AllPackagesAdapter mAllPackagesAdapter;
private ApplicationsState mApplicationsState;
private ApplicationsState.Session mSession;
private ActivityFilter mActivityFilter;
private RefreshUtils mRefreshUtils;
private RecyclerView mAppsRecyclerView;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
mSession = mApplicationsState.newSession(this);
mSession.onResume();
mActivityFilter = new ActivityFilter(getActivity().getPackageManager());
mAllPackagesAdapter = new AllPackagesAdapter(getActivity());
mRefreshUtils = new RefreshUtils(getActivity());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.refresh_layout, container, false);
}
@Override
public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAppsRecyclerView = view.findViewById(R.id.refresh_rv_view);
mAppsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mAppsRecyclerView.setAdapter(mAllPackagesAdapter);
}
@Override
public void onResume() {
super.onResume();
rebuild();
}
@Override
public void onDestroy() {
super.onDestroy();
mSession.onPause();
mSession.onDestroy();
}
@Override
public void onPackageListChanged() {
mActivityFilter.updateLauncherInfoList();
rebuild();
}
@Override
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> entries) {
if (entries != null) {
handleAppEntries(entries);
mAllPackagesAdapter.notifyDataSetChanged();
}
}
@Override
public void onLoadEntriesCompleted() {
rebuild();
}
@Override
public void onAllSizesComputed() {
}
@Override
public void onLauncherInfoChanged() {
}
@Override
public void onPackageIconChanged() {
}
@Override
public void onPackageSizeChanged(String packageName) {
}
@Override
public void onRunningStateChanged(boolean running) {
}
private void handleAppEntries(List<ApplicationsState.AppEntry> entries) {
final ArrayList<String> sections = new ArrayList<String>();
final ArrayList<Integer> positions = new ArrayList<Integer>();
final PackageManager pm = getActivity().getPackageManager();
String lastSectionIndex = null;
int offset = 0;
for (int i = 0; i < entries.size(); i++) {
final ApplicationInfo info = entries.get(i).info;
final String label = (String) info.loadLabel(pm);
final String sectionIndex;
if (!info.enabled) {
sectionIndex = "--"; // XXX
} else if (TextUtils.isEmpty(label)) {
sectionIndex = "";
} else {
sectionIndex = label.substring(0, 1).toUpperCase();
}
if (lastSectionIndex == null ||
!TextUtils.equals(sectionIndex, lastSectionIndex)) {
sections.add(sectionIndex);
positions.add(offset);
lastSectionIndex = sectionIndex;
}
offset++;
}
mAllPackagesAdapter.setEntries(entries, sections, positions);
}
private void rebuild() {
mSession.rebuild(mActivityFilter, ApplicationsState.ALPHA_COMPARATOR);
}
private int getStateDrawable(int state) {
switch (state) {
case RefreshUtils.STATE_MEDIUM:
return R.drawable.ic_refresh_60;
case RefreshUtils.STATE_HIGH:
return R.drawable.ic_refresh_90;
case RefreshUtils.STATE_EXTREME:
return R.drawable.ic_refresh_120;
case RefreshUtils.STATE_DEFAULT:
default:
return R.drawable.ic_refresh_default;
}
}
private class ViewHolder extends RecyclerView.ViewHolder {
private TextView title;
private Spinner mode;
private ImageView icon;
private View rootView;
private ImageView stateIcon;
private ViewHolder(View view) {
super(view);
this.title = view.findViewById(R.id.app_name);
this.mode = view.findViewById(R.id.app_mode);
this.icon = view.findViewById(R.id.app_icon);
this.stateIcon = view.findViewById(R.id.state);
this.rootView = view;
view.setTag(this);
}
}
private class ModeAdapter extends BaseAdapter {
private final LayoutInflater inflater;
private final int[] items = {
R.string.refresh_default,
R.string.refresh_medium,
R.string.refresh_high,
R.string.refresh_extreme
};
private ModeAdapter(Context context) {
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return items.length;
}
@Override
public Object getItem(int position) {
return items[position];
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view;
if (convertView != null) {
view = (TextView) convertView;
} else {
view = (TextView) inflater.inflate(android.R.layout.simple_spinner_dropdown_item,
parent, false);
}
view.setText(items[position]);
view.setTextSize(14f);
return view;
}
}
private class AllPackagesAdapter extends RecyclerView.Adapter<ViewHolder>
implements AdapterView.OnItemSelectedListener, SectionIndexer {
private List<ApplicationsState.AppEntry> mEntries = new ArrayList<>();
private String[] mSections;
private int[] mPositions;
public AllPackagesAdapter(Context context) {
mActivityFilter = new ActivityFilter(context.getPackageManager());
}
@Override
public int getItemCount() {
return mEntries.size();
}
@Override
public long getItemId(int position) {
return mEntries.get(position).id;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.refresh_list_item, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Context context = holder.itemView.getContext();
ApplicationsState.AppEntry entry = mEntries.get(position);
if (entry == null) {
return;
}
holder.mode.setAdapter(new ModeAdapter(context));
holder.mode.setOnItemSelectedListener(this);
holder.title.setText(entry.label);
holder.title.setOnClickListener(v -> holder.mode.performClick());
mApplicationsState.ensureIcon(entry);
holder.icon.setImageDrawable(entry.icon);
int packageState = mRefreshUtils.getStateForPackage(entry.info.packageName);
holder.mode.setSelection(packageState, false);
holder.mode.setTag(entry);
holder.stateIcon.setImageResource(getStateDrawable(packageState));
holder.stateIcon.setOnClickListener(v -> holder.mode.performClick());
}
private void setEntries(List<ApplicationsState.AppEntry> entries,
List<String> sections, List<Integer> positions) {
mEntries = entries;
mSections = sections.toArray(new String[sections.size()]);
mPositions = new int[positions.size()];
for (int i = 0; i < positions.size(); i++) {
mPositions[i] = positions.get(i);
}
notifyDataSetChanged();
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
final ApplicationsState.AppEntry entry = (ApplicationsState.AppEntry) parent.getTag();
int currentState = mRefreshUtils.getStateForPackage(entry.info.packageName);
if (currentState != position) {
mRefreshUtils.writePackage(entry.info.packageName, position);
notifyDataSetChanged();
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
@Override
public int getPositionForSection(int section) {
if (section < 0 || section >= mSections.length) {
return -1;
}
return mPositions[section];
}
@Override
public int getSectionForPosition(int position) {
if (position < 0 || position >= getItemCount()) {
return -1;
}
final int index = Arrays.binarySearch(mPositions, position);
/*
* Consider this example: section positions are 0, 3, 5; the supplied
* position is 4. The section corresponding to position 4 starts at
* position 3, so the expected return value is 1. Binary search will not
* find 4 in the array and thus will return -insertPosition-1, i.e. -3.
* To get from that number to the expected value of 1 we need to negate
* and subtract 2.
*/
return index >= 0 ? index : -index - 2;
}
@Override
public Object[] getSections() {
return mSections;
}
}
private class ActivityFilter implements ApplicationsState.AppFilter {
private final PackageManager mPackageManager;
private final List<String> mLauncherResolveInfoList = new ArrayList<String>();
private ActivityFilter(PackageManager packageManager) {
this.mPackageManager = packageManager;
updateLauncherInfoList();
}
public void updateLauncherInfoList() {
Intent i = new Intent(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfoList = mPackageManager.queryIntentActivities(i, 0);
synchronized (mLauncherResolveInfoList) {
mLauncherResolveInfoList.clear();
for (ResolveInfo ri : resolveInfoList) {
mLauncherResolveInfoList.add(ri.activityInfo.packageName);
}
}
}
@Override
public void init() {
}
@Override
public boolean filterApp(ApplicationsState.AppEntry entry) {
boolean show = !mAllPackagesAdapter.mEntries.contains(entry.info.packageName);
if (show) {
synchronized (mLauncherResolveInfoList) {
show = mLauncherResolveInfoList.contains(entry.info.packageName);
}
}
return show;
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2021 crDroid Android Project
* Copyright (C) 2021 Chaldeaprjkt
*
* 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.refreshrate;
import android.content.Context;
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import android.view.Display;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
public class RefreshTileService extends TileService {
private static final String KEY_MIN_REFRESH_RATE = "min_refresh_rate";
private static final String KEY_PEAK_REFRESH_RATE = "peak_refresh_rate";
private Context context;
private Tile tile;
private final List<Integer> availableRates = new ArrayList<>();
private int activeRateMin;
private int activeRateMax;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
Display.Mode mode = context.getDisplay().getMode();
Display.Mode[] modes = context.getDisplay().getSupportedModes();
for (Display.Mode m : modes) {
int rate = (int) Math.round(m.getRefreshRate());
if (m.getPhysicalWidth() == mode.getPhysicalWidth() &&
m.getPhysicalHeight() == mode.getPhysicalHeight()) {
availableRates.add(rate);
}
}
syncFromSettings();
}
private int getSettingOf(String key) {
float rate = Settings.System.getFloat(context.getContentResolver(), key, 120);
int active = availableRates.indexOf((int) Math.round(rate));
return Math.max(active, 0);
}
private void syncFromSettings() {
activeRateMin = getSettingOf(KEY_MIN_REFRESH_RATE);
activeRateMax = getSettingOf(KEY_PEAK_REFRESH_RATE);
}
private void cycleRefreshRate() {
if (activeRateMax == 0) {
if(activeRateMin == 0) {
activeRateMin = availableRates.size();
}
activeRateMax = activeRateMin;
float rate = availableRates.get(activeRateMin - 1);
Settings.System.putFloat(context.getContentResolver(), KEY_MIN_REFRESH_RATE, rate);
}
float rate = availableRates.get(activeRateMax - 1);
Settings.System.putFloat(context.getContentResolver(), KEY_PEAK_REFRESH_RATE, rate);
}
private void updateTileView() {
String displayText;
int min = availableRates.get(activeRateMin);
int max = availableRates.get(activeRateMax);
displayText = String.format(Locale.US, min == max ? "%d Hz" : "%d - %d Hz", min, max);
tile.setContentDescription(displayText);
tile.setSubtitle(displayText);
tile.setState(min == max ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
tile.updateTile();
}
@Override
public void onStartListening() {
super.onStartListening();
tile = getQsTile();
syncFromSettings();
updateTileView();
}
@Override
public void onClick() {
super.onClick();
cycleRefreshRate();
syncFromSettings();
updateTileView();
}
}

View File

@@ -0,0 +1,182 @@
/*
* 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.refreshrate;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.UserHandle;
import android.view.Display;
import android.provider.Settings;
import androidx.preference.PreferenceManager;
public final class RefreshUtils {
private static final String REFRESH_CONTROL = "refresh_control";
private static final String REFRESH_SERVICE = "refresh_service";
private static final String KEY_PEAK_REFRESH_RATE = "peak_refresh_rate";
private static final String KEY_MIN_REFRESH_RATE = "min_refresh_rate";
private Context mContext;
protected static final int STATE_DEFAULT = 0;
protected static final int STATE_MEDIUM = 1;
protected static final int STATE_HIGH = 2;
protected static final int STATE_EXTREME = 3;
private static final float REFRESH_STATE_DEFAULT = 120f;
private static final float REFRESH_STATE_MEDIUM = 60f;
private static final float REFRESH_STATE_HIGH = 90f;
private static final float REFRESH_STATE_EXTREME = 120f;
private static final String REFRESH_MEDIUM = "refresh.medium";
private static final String REFRESH_HIGH = "refresh.high=";
private static final String REFRESH_EXTREME = "refresh.extreme=";
private static boolean isAppInList = false;
private static float defaultMaxRate;
private static float defaultMinRate;
private SharedPreferences mSharedPrefs;
protected RefreshUtils(Context context) {
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
mContext = context;
}
public static void initialize(Context context) {
defaultMaxRate = Settings.System.getFloat(context.getContentResolver(), KEY_PEAK_REFRESH_RATE, REFRESH_STATE_DEFAULT);
defaultMinRate = Settings.System.getFloat(context.getContentResolver(), KEY_MIN_REFRESH_RATE, REFRESH_STATE_DEFAULT);
if (isServiceEnabled(context))
startService(context);
else
setDefaultRefreshRate(context);
}
public static void startService(Context context) {
context.startServiceAsUser(new Intent(context, RefreshService.class),
UserHandle.CURRENT);
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(REFRESH_SERVICE, "true").apply();
}
protected static void stopService(Context context) {
context.stopService(new Intent(context, RefreshService.class));
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(REFRESH_SERVICE, "false").apply();
}
protected static boolean isServiceEnabled(Context context) {
return true;
}
private void writeValue(String profiles) {
mSharedPrefs.edit().putString(REFRESH_CONTROL, profiles).apply();
}
private String getValue() {
String value = mSharedPrefs.getString(REFRESH_CONTROL, null);
if (value == null || value.isEmpty()) {
value = REFRESH_MEDIUM + ":" + REFRESH_HIGH + ":" + REFRESH_EXTREME;
writeValue(value);
}
return value;
}
protected void writePackage(String packageName, int mode) {
String value = getValue();
value = value.replace(packageName + ",", "");
String[] modes = value.split(":");
String finalString;
switch (mode) {
case STATE_MEDIUM:
modes[0] = modes[0] + packageName + ",";
break;
case STATE_HIGH:
modes[1] = modes[1] + packageName + ",";
break;
case STATE_EXTREME:
modes[2] = modes[2] + packageName + ",";
break;
}
finalString = modes[0] + ":" + modes[1] + ":" + modes[2];
writeValue(finalString);
}
protected int getStateForPackage(String packageName) {
String value = getValue();
String[] modes = value.split(":");
int state = STATE_DEFAULT;
if (modes[0].contains(packageName + ",")) {
state = STATE_MEDIUM;
} else if (modes[1].contains(packageName + ",")) {
state = STATE_HIGH;
} else if (modes[2].contains(packageName + ",")) {
state = STATE_EXTREME;
}
return state;
}
protected static void setDefaultRefreshRate(Context context) {
Settings.System.putFloat(context.getContentResolver(), KEY_PEAK_REFRESH_RATE, defaultMaxRate);
Settings.System.putFloat(context.getContentResolver(), KEY_MIN_REFRESH_RATE, defaultMinRate);
}
protected void setRefreshRate(String packageName) {
String value = getValue();
String modes[];
if (!isAppInList) {
defaultMaxRate = Settings.System.getFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, REFRESH_STATE_DEFAULT);
defaultMinRate = Settings.System.getFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, REFRESH_STATE_DEFAULT);
}
float minrate = defaultMinRate;
float maxrate = defaultMaxRate;
if (value != null) {
modes = value.split(":");
if (modes[0].contains(packageName + ",")) {
maxrate = REFRESH_STATE_MEDIUM;
if ( minrate > maxrate){
minrate = maxrate;
}
isAppInList = true;
} else if (modes[1].contains(packageName + ",")) {
maxrate = REFRESH_STATE_HIGH;
if ( minrate > maxrate){
minrate = maxrate;
}
isAppInList = true;
} else if (modes[2].contains(packageName + ",")) {
maxrate = REFRESH_STATE_EXTREME;
if ( minrate > maxrate){
minrate = maxrate;
}
isAppInList = true;
} else {
isAppInList = false;
}
}
Settings.System.putFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, maxrate);
Settings.System.putFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, minrate);
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2020-2022 Paranoid Android
*
* 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.speaker;
import android.os.Bundle;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
public class ClearSpeakerActivity extends CollapsingToolbarBaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction()
.replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame, new ClearSpeakerFragment())
.commit();
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2023 Paranoid Android
*
* 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.speaker;
import android.content.res.AssetFileDescriptor;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragment;
import androidx.preference.SwitchPreference;
import org.lineageos.settings.R;
import java.io.IOException;
public class ClearSpeakerFragment extends PreferenceFragment implements
Preference.OnPreferenceChangeListener {
private static final String TAG = "ClearSpeakerFragment";
private static final String PREF_CLEAR_SPEAKER = "clear_speaker_pref";
private static final int PLAY_DURATION_MS = 30000;
private Handler mHandler = new Handler(Looper.getMainLooper());
private MediaPlayer mMediaPlayer;
private SwitchPreference mClearSpeakerPref;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.clear_speaker_settings);
mClearSpeakerPref = findPreference(PREF_CLEAR_SPEAKER);
mClearSpeakerPref.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mClearSpeakerPref) {
boolean value = (Boolean) newValue;
if (value && startPlaying()) {
mHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(this::stopPlaying, PLAY_DURATION_MS);
return true;
}
}
return false;
}
@Override
public void onStop() {
super.onStop();
stopPlaying();
}
public boolean startPlaying() {
getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);
mMediaPlayer = new MediaPlayer();
mMediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.build());
mMediaPlayer.setLooping(true);
try (AssetFileDescriptor afd = getResources().openRawResourceFd(
R.raw.clear_speaker_sound)) {
mMediaPlayer.setDataSource(afd);
mMediaPlayer.setVolume(1.0f, 1.0f);
mMediaPlayer.prepare();
mMediaPlayer.start();
mClearSpeakerPref.setEnabled(false);
} catch (IOException | IllegalArgumentException e) {
Log.e(TAG, "Failed to play speaker clean sound!", e);
return false;
}
return true;
}
public void stopPlaying() {
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
try {
mMediaPlayer.stop();
} catch (IllegalStateException e) {
Log.e(TAG, "Failed to stop media player!", e);
} finally {
mMediaPlayer.reset();
mMediaPlayer.release();
mMediaPlayer = null;
}
}
mClearSpeakerPref.setEnabled(true);
mClearSpeakerPref.setChecked(false);
}
}

View File

@@ -0,0 +1,40 @@
/**
* 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.thermal;
public class Constants {
public static final int TOUCH_GAME_MODE = 0;
public static final int TOUCH_RESPONSE = 1;
public static final int TOUCH_SENSITIVITY = 2;
public static final int TOUCH_RESISTANT = 3;
public static final String PROP_TOUCH_GAME_MODE = "sys.perf_profile";
public static final String FILE_TOUCH_UP_THRESHOLD = "/proc/nvt_sensitivity_switch";
public static final String FILE_TOUCH_TOLERANCE = "/proc/nvt_pf_switch";
public static final String FILE_TOUCH_EDGE_FILTER = "/proc/nvt_er_range_switch";
public static final String DEFAULT_TOUCH_UP_THRESHOLD = "3";
public static final String DEFAULT_TOUCH_TOLERANCE = "0";
public static final String DEFAULT_TOUCH_EDGE_FILTER = "2";
public static final String PREF_TOUCH_GAME_MODE = "touch_game_mode";
public static final String PREF_TOUCH_RESISTANT = "touch_resistant";
public static final String PREF_TOUCH_RESPONSE = "touch_response";
public static final String PREF_TOUCH_SENSITIVITY = "touch_sensitivity";
}

View File

@@ -0,0 +1,97 @@
/*
* 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.thermal;
import android.app.ActivityTaskManager;
import android.app.TaskStackListener;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
public class ThermalService extends Service {
private static final String TAG = "ThermalService";
private static final boolean DEBUG = false;
private String mPreviousApp;
private ThermalUtils mThermalUtils;
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mPreviousApp = "";
mThermalUtils.setDefaultThermalProfile();
mThermalUtils.resetTouchModes();
}
};
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "Creating service");
try {
ActivityTaskManager.getService().registerTaskStackListener(mTaskListener);
} catch (RemoteException e) {
// Do nothing
}
mThermalUtils = new ThermalUtils(this);
registerReceiver();
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void registerReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
this.registerReceiver(mIntentReceiver, filter);
}
private final TaskStackListener mTaskListener = new TaskStackListener() {
@Override
public void onTaskStackChanged() {
try {
final ActivityTaskManager.RootTaskInfo focusedTask =
ActivityTaskManager.getService().getFocusedRootTaskInfo();
if (focusedTask != null && focusedTask.topActivity != null) {
ComponentName taskComponentName = focusedTask.topActivity;
String foregroundApp = taskComponentName.getPackageName();
if (!foregroundApp.equals(mPreviousApp)) {
mThermalUtils.setThermalProfile(foregroundApp);
mPreviousApp = foregroundApp;
}
}
} catch (Exception e) {}
}
};
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2020-2022 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.thermal;
import android.os.Bundle;
import android.view.MenuItem;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
public class ThermalSettingsActivity extends CollapsingToolbarBaseActivity {
private static final String TAG_THERMAL = "thermal";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
new ThermalSettingsFragment(), TAG_THERMAL).commit();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return false;
}
}

View File

@@ -0,0 +1,433 @@
/**
* 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.thermal;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SectionIndexer;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceFragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.android.settingslib.applications.ApplicationsState;
import org.lineageos.settings.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ThermalSettingsFragment extends PreferenceFragment
implements ApplicationsState.Callbacks {
private AllPackagesAdapter mAllPackagesAdapter;
private ApplicationsState mApplicationsState;
private ApplicationsState.Session mSession;
private ActivityFilter mActivityFilter;
private ThermalUtils mThermalUtils;
private RecyclerView mAppsRecyclerView;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
mSession = mApplicationsState.newSession(this);
mSession.onResume();
mActivityFilter = new ActivityFilter(getActivity().getPackageManager());
mAllPackagesAdapter = new AllPackagesAdapter(getActivity());
mThermalUtils = new ThermalUtils(getActivity());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.thermal_layout, container, false);
}
@Override
public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAppsRecyclerView = view.findViewById(R.id.thermal_rv_view);
mAppsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
mAppsRecyclerView.setAdapter(mAllPackagesAdapter);
}
@Override
public void onResume() {
super.onResume();
getActivity().setTitle(getResources().getString(R.string.thermal_title));
rebuild();
}
@Override
public void onDestroy() {
super.onDestroy();
mSession.onPause();
mSession.onDestroy();
}
@Override
public void onPackageListChanged() {
mActivityFilter.updateLauncherInfoList();
rebuild();
}
@Override
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> entries) {
if (entries != null) {
handleAppEntries(entries);
mAllPackagesAdapter.notifyDataSetChanged();
}
}
@Override
public void onLoadEntriesCompleted() {
rebuild();
}
@Override
public void onAllSizesComputed() {
}
@Override
public void onLauncherInfoChanged() {
}
@Override
public void onPackageIconChanged() {
}
@Override
public void onPackageSizeChanged(String packageName) {
}
@Override
public void onRunningStateChanged(boolean running) {
}
private void handleAppEntries(List<ApplicationsState.AppEntry> entries) {
final ArrayList<String> sections = new ArrayList<String>();
final ArrayList<Integer> positions = new ArrayList<Integer>();
final PackageManager pm = getActivity().getPackageManager();
String lastSectionIndex = null;
int offset = 0;
for (int i = 0; i < entries.size(); i++) {
final ApplicationInfo info = entries.get(i).info;
final String label = (String) info.loadLabel(pm);
final String sectionIndex;
if (!info.enabled) {
sectionIndex = "--"; // XXX
} else if (TextUtils.isEmpty(label)) {
sectionIndex = "";
} else {
sectionIndex = label.substring(0, 1).toUpperCase();
}
if (lastSectionIndex == null ||
!TextUtils.equals(sectionIndex, lastSectionIndex)) {
sections.add(sectionIndex);
positions.add(offset);
lastSectionIndex = sectionIndex;
}
offset++;
}
mAllPackagesAdapter.setEntries(entries, sections, positions);
}
private void rebuild() {
mSession.rebuild(mActivityFilter, ApplicationsState.ALPHA_COMPARATOR);
}
private int getStateDrawable(int state) {
switch (state) {
case ThermalUtils.STATE_BENCHMARK:
return R.drawable.ic_thermal_benchmark;
case ThermalUtils.STATE_CAMERA:
return R.drawable.ic_thermal_camera;
case ThermalUtils.STATE_DIALER:
return R.drawable.ic_thermal_dialer;
case ThermalUtils.STATE_GAMING:
return R.drawable.ic_thermal_gaming;
case ThermalUtils.STATE_DEFAULT:
default:
return R.drawable.ic_thermal_default;
}
}
private class ViewHolder extends RecyclerView.ViewHolder {
private TextView title;
private Spinner mode;
private ImageView icon;
private View rootView;
private ImageView stateIcon;
private ImageView touchIcon;
private ViewHolder(View view) {
super(view);
this.title = view.findViewById(R.id.app_name);
this.mode = view.findViewById(R.id.app_mode);
this.icon = view.findViewById(R.id.app_icon);
this.stateIcon = view.findViewById(R.id.state);
this.touchIcon = view.findViewById(R.id.touch);
this.rootView = view;
view.setTag(this);
}
}
private class ModeAdapter extends BaseAdapter {
private final LayoutInflater inflater;
private final int[] items = {
R.string.thermal_default,
R.string.thermal_benchmark,
R.string.thermal_camera,
R.string.thermal_dialer,
R.string.thermal_gaming,
};
private ModeAdapter(Context context) {
inflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return items.length;
}
@Override
public Object getItem(int position) {
return items[position];
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view;
if (convertView != null) {
view = (TextView) convertView;
} else {
view = (TextView) inflater.inflate(android.R.layout.simple_spinner_dropdown_item,
parent, false);
}
view.setText(items[position]);
view.setTextSize(14f);
return view;
}
}
private class AllPackagesAdapter extends RecyclerView.Adapter<ViewHolder>
implements AdapterView.OnItemSelectedListener, SectionIndexer {
private List<ApplicationsState.AppEntry> mEntries = new ArrayList<>();
private String[] mSections;
private int[] mPositions;
public AllPackagesAdapter(Context context) {
mActivityFilter = new ActivityFilter(context.getPackageManager());
}
@Override
public int getItemCount() {
return mEntries.size();
}
@Override
public long getItemId(int position) {
return mEntries.get(position).id;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.thermal_list_item, parent, false));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Context context = holder.itemView.getContext();
ApplicationsState.AppEntry entry = mEntries.get(position);
if (entry == null) {
return;
}
holder.mode.setAdapter(new ModeAdapter(context));
holder.mode.setOnItemSelectedListener(this);
holder.touchIcon.setOnClickListener(v -> {
Intent intent = new Intent(getActivity(), TouchSettingsActivity.class);
intent.putExtra("appName", entry.label);
intent.putExtra("packageName", entry.info.packageName);
startActivity(intent);
});
holder.title.setText(entry.label);
holder.title.setOnClickListener(v -> holder.mode.performClick());
mApplicationsState.ensureIcon(entry);
holder.icon.setImageDrawable(entry.icon);
int packageState = mThermalUtils.getStateForPackage(entry.info.packageName);
holder.mode.setSelection(packageState, false);
holder.mode.setTag(entry);
if (packageState == ThermalUtils.STATE_BENCHMARK ||
packageState == ThermalUtils.STATE_GAMING) {
holder.touchIcon.setVisibility(View.VISIBLE);
} else {
holder.touchIcon.setVisibility(View.INVISIBLE);
}
holder.stateIcon.setImageResource(getStateDrawable(packageState));
holder.stateIcon.setOnClickListener(v -> holder.mode.performClick());
}
private void setEntries(List<ApplicationsState.AppEntry> entries,
List<String> sections, List<Integer> positions) {
mEntries = entries;
mSections = sections.toArray(new String[sections.size()]);
mPositions = new int[positions.size()];
for (int i = 0; i < positions.size(); i++) {
mPositions[i] = positions.get(i);
}
notifyDataSetChanged();
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
final ApplicationsState.AppEntry entry = (ApplicationsState.AppEntry) parent.getTag();
int currentState = mThermalUtils.getStateForPackage(entry.info.packageName);
if (currentState != position) {
mThermalUtils.writePackage(entry.info.packageName, position);
notifyDataSetChanged();
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
@Override
public int getPositionForSection(int section) {
if (section < 0 || section >= mSections.length) {
return -1;
}
return mPositions[section];
}
@Override
public int getSectionForPosition(int position) {
if (position < 0 || position >= getItemCount()) {
return -1;
}
final int index = Arrays.binarySearch(mPositions, position);
/*
* Consider this example: section positions are 0, 3, 5; the supplied
* position is 4. The section corresponding to position 4 starts at
* position 3, so the expected return value is 1. Binary search will not
* find 4 in the array and thus will return -insertPosition-1, i.e. -3.
* To get from that number to the expected value of 1 we need to negate
* and subtract 2.
*/
return index >= 0 ? index : -index - 2;
}
@Override
public Object[] getSections() {
return mSections;
}
}
private class ActivityFilter implements ApplicationsState.AppFilter {
private final PackageManager mPackageManager;
private final List<String> mLauncherResolveInfoList = new ArrayList<String>();
private ActivityFilter(PackageManager packageManager) {
this.mPackageManager = packageManager;
updateLauncherInfoList();
}
public void updateLauncherInfoList() {
Intent i = new Intent(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resolveInfoList = mPackageManager.queryIntentActivities(i, 0);
synchronized (mLauncherResolveInfoList) {
mLauncherResolveInfoList.clear();
for (ResolveInfo ri : resolveInfoList) {
mLauncherResolveInfoList.add(ri.activityInfo.packageName);
}
}
}
@Override
public void init() {
}
@Override
public boolean filterApp(ApplicationsState.AppEntry entry) {
boolean show = !mAllPackagesAdapter.mEntries.contains(entry.info.packageName);
if (show) {
synchronized (mLauncherResolveInfoList) {
show = mLauncherResolveInfoList.contains(entry.info.packageName);
}
}
return show;
}
}
}

View File

@@ -0,0 +1,196 @@
/*
* 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.thermal;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import androidx.preference.PreferenceManager;
import org.lineageos.settings.utils.FileUtils;
public final class ThermalUtils {
private static final String THERMAL_CONTROL = "thermal_control";
protected static final int STATE_DEFAULT = 0;
protected static final int STATE_BENCHMARK = 1;
protected static final int STATE_CAMERA = 2;
protected static final int STATE_DIALER = 3;
protected static final int STATE_GAMING = 4;
private static final String THERMAL_STATE_DEFAULT = "0";
private static final String THERMAL_STATE_BENCHMARK = "10";
private static final String THERMAL_STATE_CAMERA = "12";
private static final String THERMAL_STATE_DIALER = "8";
private static final String THERMAL_STATE_GAMING = "9";
private static final String THERMAL_BENCHMARK = "thermal.benchmark=";
private static final String THERMAL_CAMERA = "thermal.camera=";
private static final String THERMAL_DIALER = "thermal.dialer=";
private static final String THERMAL_GAMING = "thermal.gaming=";
private static final String THERMAL_SCONFIG = "/sys/class/thermal/thermal_message/sconfig";
private boolean mTouchModeChanged;
private Display mDisplay;
private SharedPreferences mSharedPrefs;
protected ThermalUtils(Context context) {
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
WindowManager mWindowManager = context.getSystemService(WindowManager.class);
mDisplay = mWindowManager.getDefaultDisplay();
}
public static void startService(Context context) {
context.startServiceAsUser(new Intent(context, ThermalService.class),
UserHandle.CURRENT);
}
private void writeValue(String profiles) {
mSharedPrefs.edit().putString(THERMAL_CONTROL, profiles).apply();
}
private String getValue() {
String value = mSharedPrefs.getString(THERMAL_CONTROL, null);
if (value == null || value.isEmpty()) {
value = THERMAL_BENCHMARK + ":" + THERMAL_CAMERA + ":" +
THERMAL_DIALER + ":" + THERMAL_GAMING;
writeValue(value);
}
return value;
}
protected void writePackage(String packageName, int mode) {
String value = getValue();
value = value.replace(packageName + ",", "");
String[] modes = value.split(":");
String finalString;
switch (mode) {
case STATE_BENCHMARK:
modes[0] = modes[0] + packageName + ",";
break;
case STATE_CAMERA:
modes[1] = modes[1] + packageName + ",";
break;
case STATE_DIALER:
modes[2] = modes[2] + packageName + ",";
break;
case STATE_GAMING:
modes[3] = modes[3] + packageName + ",";
break;
}
finalString = modes[0] + ":" + modes[1] + ":" + modes[2] + ":" + modes[3];
writeValue(finalString);
}
protected int getStateForPackage(String packageName) {
String value = getValue();
String[] modes = value.split(":");
int state = STATE_DEFAULT;
if (modes[0].contains(packageName + ",")) {
state = STATE_BENCHMARK;
} else if (modes[1].contains(packageName + ",")) {
state = STATE_CAMERA;
} else if (modes[2].contains(packageName + ",")) {
state = STATE_DIALER;
} else if (modes[3].contains(packageName + ",")) {
state = STATE_GAMING;
}
return state;
}
protected void setDefaultThermalProfile() {
FileUtils.writeLine(THERMAL_SCONFIG, THERMAL_STATE_DEFAULT);
}
protected void setThermalProfile(String packageName) {
String value = getValue();
String modes[];
String state = THERMAL_STATE_DEFAULT;
if (value != null) {
modes = value.split(":");
if (modes[0].contains(packageName + ",")) {
state = THERMAL_STATE_BENCHMARK;
} else if (modes[1].contains(packageName + ",")) {
state = THERMAL_STATE_CAMERA;
} else if (modes[2].contains(packageName + ",")) {
state = THERMAL_STATE_DIALER;
} else if (modes[3].contains(packageName + ",")) {
state = THERMAL_STATE_GAMING;
}
}
FileUtils.writeLine(THERMAL_SCONFIG, state);
if (state == THERMAL_STATE_BENCHMARK || state == THERMAL_STATE_GAMING) {
updateTouchModes(packageName);
} else if (mTouchModeChanged) {
resetTouchModes();
}
}
private void updateTouchModes(String packageName) {
String values = mSharedPrefs.getString(packageName, null);
resetTouchModes();
if (values == null || values.isEmpty()) {
return;
}
String[] value = values.split(",");
String gameMode = value[Constants.TOUCH_GAME_MODE];
String touchResponse = value[Constants.TOUCH_RESPONSE];
String touchSensitivity = value[Constants.TOUCH_SENSITIVITY];
String touchResistant = value[Constants.TOUCH_RESISTANT];
FileUtils.writeLine(Constants.FILE_TOUCH_TOLERANCE, touchSensitivity);
FileUtils.writeLine(Constants.FILE_TOUCH_UP_THRESHOLD, touchResponse);
FileUtils.writeLine(Constants.FILE_TOUCH_EDGE_FILTER, touchResistant);
SystemProperties.set(Constants.PROP_TOUCH_GAME_MODE, gameMode);
mTouchModeChanged = true;
}
protected void resetTouchModes() {
if (!mTouchModeChanged) {
return;
}
FileUtils.writeLine(Constants.FILE_TOUCH_TOLERANCE, Constants.DEFAULT_TOUCH_TOLERANCE);
FileUtils.writeLine(Constants.FILE_TOUCH_UP_THRESHOLD, Constants.DEFAULT_TOUCH_UP_THRESHOLD);
FileUtils.writeLine(Constants.FILE_TOUCH_EDGE_FILTER, Constants.DEFAULT_TOUCH_EDGE_FILTER);
SystemProperties.set(Constants.PROP_TOUCH_GAME_MODE, "0");
mTouchModeChanged = false;
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2022 Paranoid Android
*
* 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.thermal;
import android.os.Bundle;
import android.view.MenuItem;
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
public class TouchSettingsActivity extends CollapsingToolbarBaseActivity {
private static final String TAG_TOUCH = "touch";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TouchSettingsFragment touchSettingsFragment = new TouchSettingsFragment();
touchSettingsFragment.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
touchSettingsFragment, TAG_TOUCH).commit();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
}
return false;
}
}

View File

@@ -0,0 +1,122 @@
/**
* 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.thermal;
import android.content.SharedPreferences;
import android.os.Bundle;
import androidx.preference.PreferenceFragment;
import androidx.preference.PreferenceManager;
import androidx.preference.SwitchPreference;
import org.lineageos.settings.R;
import org.lineageos.settings.widget.SeekBarPreference;
public class TouchSettingsFragment extends PreferenceFragment
implements SharedPreferences.OnSharedPreferenceChangeListener {
private SharedPreferences mSharedPrefs;
private SeekBarPreference mTouchSensitivity;
private SeekBarPreference mTouchResponse;
private SeekBarPreference mTouchResistant;
private SwitchPreference mGameMode;
private String packageName = "";
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.touch_settings);
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
Bundle bundle = getArguments();
String appName = "";
if (bundle != null) {
appName = bundle.getString("appName", "");
packageName = bundle.getString("packageName", "");
}
getActivity().setTitle(appName);
mGameMode = (SwitchPreference) findPreference(Constants.PREF_TOUCH_GAME_MODE);
mTouchResistant = (SeekBarPreference) findPreference(Constants.PREF_TOUCH_RESISTANT);
mTouchResponse = (SeekBarPreference) findPreference(Constants.PREF_TOUCH_RESPONSE);
mTouchSensitivity = (SeekBarPreference) findPreference(Constants.PREF_TOUCH_SENSITIVITY);
updateDefaults();
}
@Override
public void onResume() {
super.onResume();
mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
super.onPause();
mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPrefs, String key) {
if (Constants.PREF_TOUCH_GAME_MODE.equals(key)) {
updateTouchModes(sharedPrefs.getBoolean(key, false) ? 1 : 0,
Constants.TOUCH_GAME_MODE);
mTouchSensitivity.setEnabled(sharedPrefs.getBoolean(key, false));
mTouchResponse.setEnabled(sharedPrefs.getBoolean(key, false));
mTouchResistant.setEnabled(sharedPrefs.getBoolean(key, false));
} else if (Constants.PREF_TOUCH_RESPONSE.equals(key)) {
updateTouchModes(sharedPrefs.getInt(key, 0), Constants.TOUCH_RESPONSE);
} else if (Constants.PREF_TOUCH_SENSITIVITY.equals(key)) {
updateTouchModes(sharedPrefs.getInt(key, 0), Constants.TOUCH_SENSITIVITY);
} else if (Constants.PREF_TOUCH_RESISTANT.equals(key)) {
updateTouchModes(sharedPrefs.getInt(key, 0), Constants.TOUCH_RESISTANT);
}
}
private void updateDefaults() {
String[] values = getTouchValues().split(",");
mGameMode.setChecked(Integer.parseInt(values[Constants.TOUCH_GAME_MODE]) == 1);
mTouchResponse.setProgress(Integer.parseInt(values[Constants.TOUCH_RESPONSE]));
mTouchSensitivity.setProgress(Integer.parseInt(values[Constants.TOUCH_SENSITIVITY]));
mTouchResistant.setProgress(Integer.parseInt(values[Constants.TOUCH_RESISTANT]));
mTouchResponse.setEnabled(Integer.parseInt(values[Constants.TOUCH_GAME_MODE]) == 1);
mTouchSensitivity.setEnabled(Integer.parseInt(values[Constants.TOUCH_GAME_MODE]) == 1);
mTouchResistant.setEnabled(Integer.parseInt(values[Constants.TOUCH_GAME_MODE]) == 1);
}
private void writeTouchValues(String modes) {
mSharedPrefs.edit().putString(packageName, modes).apply();
}
public String getTouchValues() {
String values = mSharedPrefs.getString(packageName, null);
if (values == null || values.isEmpty()) {
values = "0,3,0,2";
}
writeTouchValues(values);
return values;
}
public void updateTouchModes(int value, int mode) {
String[] values = getTouchValues().split(",");
values[mode] = String.valueOf(value);
String finalValues = values[Constants.TOUCH_GAME_MODE] + "," + values[Constants.TOUCH_RESPONSE] + ","
+ values[Constants.TOUCH_SENSITIVITY] + "," + values[Constants.TOUCH_RESISTANT];
writeTouchValues(finalValues);
}
}

View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2016 The CyanogenMod 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.utils;
import android.util.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public final class FileUtils {
private static final String TAG = "FileUtils";
private FileUtils() {
// This class is not supposed to be instantiated
}
/**
* Reads the first line of text from the given file.
* Reference {@link BufferedReader#readLine()} for clarification on what a line is
*
* @return the read line contents, or null on failure
*/
public static String readOneLine(String fileName) {
String line = null;
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(fileName), 512);
line = reader.readLine();
} catch (FileNotFoundException e) {
Log.w(TAG, "No such file " + fileName + " for reading", e);
} catch (IOException e) {
Log.e(TAG, "Could not read from file " + fileName, e);
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
// Ignored, not much we can do anyway
}
}
return line;
}
/**
* Writes the given value into the given file
*
* @return true on success, false on failure
*/
public static boolean writeLine(String fileName, String value) {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(fileName));
writer.write(value);
} catch (FileNotFoundException e) {
Log.w(TAG, "No such file " + fileName + " for writing", e);
return false;
} catch (IOException e) {
Log.e(TAG, "Could not write to file " + fileName, e);
return false;
} finally {
try {
if (writer != null) {
writer.close();
}
} catch (IOException e) {
// Ignored, not much we can do anyway
}
}
return true;
}
/**
* Checks whether the given file exists
*
* @return true if exists, false if not
*/
public static boolean fileExists(String fileName) {
final File file = new File(fileName);
return file.exists();
}
/**
* Checks whether the given file is readable
*
* @return true if readable, false if not
*/
public static boolean isFileReadable(String fileName) {
final File file = new File(fileName);
return file.exists() && file.canRead();
}
/**
* Checks whether the given file is writable
*
* @return true if writable, false if not
*/
public static boolean isFileWritable(String fileName) {
final File file = new File(fileName);
return file.exists() && file.canWrite();
}
/**
* Deletes an existing file
*
* @return true if the delete was successful, false if not
*/
public static boolean delete(String fileName) {
final File file = new File(fileName);
boolean ok = false;
try {
ok = file.delete();
} catch (SecurityException e) {
Log.w(TAG, "SecurityException trying to delete " + fileName, e);
}
return ok;
}
/**
* Renames an existing file
*
* @return true if the rename was successful, false if not
*/
public static boolean rename(String srcPath, String dstPath) {
final File srcFile = new File(srcPath);
final File dstFile = new File(dstPath);
boolean ok = false;
try {
ok = srcFile.renameTo(dstFile);
} catch (SecurityException e) {
Log.w(TAG, "SecurityException trying to rename " + srcPath + " to " + dstPath, e);
} catch (NullPointerException e) {
Log.e(TAG, "NullPointerException trying to rename " + srcPath + " to " + dstPath, e);
}
return ok;
}
}

View File

@@ -0,0 +1,280 @@
/*
* Copyright (C) 2011 The Android Open Source Project
* 2017-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.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import androidx.preference.PreferenceViewHolder;
import com.android.settingslib.RestrictedPreference;
import org.lineageos.settings.R;
/**
* Based on android.preference.SeekBarPreference, but uses support preference as base.
*/
public class SeekBarPreference extends RestrictedPreference
implements OnSeekBarChangeListener, View.OnKeyListener {
private int mProgress;
private int mMax;
private boolean mTrackingTouch;
private ImageView mIconView;
private Drawable mIcon;
public SeekBarPreference(
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.ProgressBar, defStyleAttr, defStyleRes);
setMax(a.getInt(com.android.internal.R.styleable.ProgressBar_max, mMax));
a.recycle();
a = context.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.SeekBarPreference, defStyleAttr, defStyleRes);
final int layoutResId = a.getResourceId(
com.android.internal.R.styleable.SeekBarPreference_layout,
com.android.internal.R.layout.preference_widget_seekbar);
a.recycle();
setLayoutResource(layoutResId);
}
public SeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public SeekBarPreference(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.seekBarPreferenceStyle);
}
public SeekBarPreference(Context context) {
this(context, null);
}
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
mIconView = (ImageView) view.findViewById(R.id.icon);
if (mIcon != null) {
mIconView.setImageDrawable(mIcon);
}
view.itemView.setOnKeyListener(this);
SeekBar seekBar = (SeekBar) view.findViewById(R.id.seekbar);
seekBar.setOnSeekBarChangeListener(this);
seekBar.setMax(mMax);
seekBar.setProgress(mProgress);
seekBar.setEnabled(isEnabled());
}
public ImageView getIconView() {
return mIconView;
}
public void setIconDrawable(Drawable drawable) {
if (mIconView != null) {
mIconView.setImageDrawable(drawable);
}
mIcon = drawable;
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
setProgress(restoreValue ? getPersistedInt(mProgress)
: (Integer) defaultValue);
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
return a.getInt(index, 0);
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_DOWN) {
return false;
}
SeekBar seekBar = (SeekBar) v.findViewById(R.id.seekbar);
if (seekBar == null) {
return false;
}
return seekBar.onKeyDown(keyCode, event);
}
public void setMax(int max) {
if (max != mMax) {
mMax = max;
notifyChanged();
}
}
public void setProgress(int progress) {
setProgress(progress, true);
}
private void setProgress(int progress, boolean notifyChanged) {
if (progress > mMax) {
progress = mMax;
}
if (progress < 0) {
progress = 0;
}
if (progress != mProgress) {
mProgress = progress;
persistInt(progress);
if (notifyChanged) {
notifyChanged();
}
}
}
public int getProgress() {
return mProgress;
}
/**
* Persist the seekBar's progress value if callChangeListener
* returns true, otherwise set the seekBar's progress to the stored value
*/
void syncProgress(SeekBar seekBar) {
int progress = seekBar.getProgress();
if (progress != mProgress) {
if (callChangeListener(progress)) {
setProgress(progress, false);
} else {
seekBar.setProgress(mProgress);
}
}
}
@Override
public void onProgressChanged(
SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser && !mTrackingTouch) {
syncProgress(seekBar);
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mTrackingTouch = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mTrackingTouch = false;
if (seekBar.getProgress() != mProgress) {
syncProgress(seekBar);
}
}
@Override
protected Parcelable onSaveInstanceState() {
/*
* Suppose a client uses this preference type without persisting. We
* must save the instance state so it is able to, for example, survive
* orientation changes.
*/
final Parcelable superState = super.onSaveInstanceState();
if (isPersistent()) {
// No need to save instance state since it's persistent
return superState;
}
// Save the instance state
final SavedState myState = new SavedState(superState);
myState.progress = mProgress;
myState.max = mMax;
return myState;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (!state.getClass().equals(SavedState.class)) {
// Didn't save state for us in onSaveInstanceState
super.onRestoreInstanceState(state);
return;
}
// Restore the instance state
SavedState myState = (SavedState) state;
super.onRestoreInstanceState(myState.getSuperState());
mProgress = myState.progress;
mMax = myState.max;
notifyChanged();
}
/**
* SavedState, a subclass of {@link BaseSavedState}, will store the state
* of MyPreference, a subclass of Preference.
* <p>
* It is important to always call through to super methods.
*/
private static class SavedState extends BaseSavedState {
int progress;
int max;
public SavedState(Parcel source) {
super(source);
// Restore the click counter
progress = source.readInt();
max = source.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
// Save the click counter
dest.writeInt(progress);
dest.writeInt(max);
}
public SavedState(Parcelable superState) {
super(superState);
}
@SuppressWarnings("unused")
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}

View File

@@ -120,9 +120,13 @@ on early-boot
start vendor.sensors
on boot
chmod 0664 /sys/class/thermal/thermal_message/sconfig
chown system system /sys/class/thermal/thermal_message/sconfig
chmod 0664 /sys/class/thermal/thermal_message/balance_mode
chown system system /sys/class/thermal/thermal_message/balance_mode
chmod 0664 /sys/class/thermal/thermal_message/charger_temp
chown system system /sys/class/thermal/thermal_message/charger_temp
chmod 0664 /sys/class/thermal/thermal_message/flash_state
chown cameraserver cameraserver /sys/class/thermal/thermal_message/flash_state
# Set xiaomi touch permissions

View File

@@ -0,0 +1,28 @@
app_domain(devicesettings_app)
# Allow devicesettings_app to find *_service
allow devicesettings_app {
app_api_service
audioserver_service
cameraserver_service
drmserver_service
mediaextractor_service
mediametrics_service
mediaserver_service
}:service_manager find;
# Allow devicesettings_app read and write /data/data subdirectory
allow devicesettings_app system_app_data_file:dir create_dir_perms;
allow devicesettings_app system_app_data_file:{ file lnk_file } create_file_perms;
# Allow binder communication with gpuservice
binder_call(devicesettings_app, gpuservice)
# Allow devicesettings_app to read and write to cgroup/sysfs_leds/sysfs_thermal
allow devicesettings_app sysfs_leds:dir search;
allow devicesettings_app {
cgroup
sysfs_leds
sysfs_thermal
}:{ file lnk_file } rw_file_perms;

View File

@@ -0,0 +1,2 @@
user=system seinfo=platform name=org.lineageos.devicesettings domain=devicesettings_app type=system_app_data_file
user=system seinfo=platform name=org.lineageos.settings domain=devicesettings_app type=system_app_data_file

View File

@@ -0,0 +1,2 @@
type devicesettings_app, domain;
typeattribute devicesettings_app mlstrustedsubject;

6
sepolicy/vendor/devicesettings_app.te vendored Normal file
View File

@@ -0,0 +1,6 @@
allow devicesettings_app vendor_sysfs_graphics:dir search;
allow devicesettings_app vendor_sysfs_graphics:file rw_file_perms;
allow devicesettings_app vendor_sysfs_kgsl:dir search;
allow devicesettings_app vendor_sysfs_kgsl:{ file lnk_file } rw_file_perms;

View File

@@ -16,3 +16,6 @@ allowxperm system_app apk_data_file:file ioctl {
INCFS_IOCTL_GET_BLOCK_COUNT
INCFS_IOCTL_GET_FILLED_BLOCKS
};
# Parts
allow system_app sysfs_thermal:file write;