DeviceSettings: rework bypass charging
* Drop Lineage Health dependency * Turn bypass charging into a tri-state (0-BYPASS_OFF, 1-BYPASS_WAITING, 2-BYPASS_OFF * Add target limit Change-Id: I06b6e9e8da7ffc20c769d47627d07cc189e884b4
This commit is contained in:
36
BoardConfig.mk
Normal file
36
BoardConfig.mk
Normal file
@@ -0,0 +1,36 @@
|
||||
#
|
||||
# Copyright (C) 2021-2025 The LineageOS Project
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# Partitions
|
||||
BOARD_SUPER_PARTITION_SIZE := 13329498112
|
||||
|
||||
# Include the common OEM chipset BoardConfig.
|
||||
include device/oneplus/sm8750-common/BoardConfigCommon.mk
|
||||
|
||||
DEVICE_PATH := device/oneplus/dodge
|
||||
|
||||
# Assert
|
||||
TARGET_OTA_ASSERT_DEVICE := OP5D0DL1,OP5D55L1
|
||||
|
||||
# Display
|
||||
TARGET_SCREEN_DENSITY := 640
|
||||
|
||||
# Kernel
|
||||
TARGET_KERNEL_ADDITIONAL_FLAGS += CONFIG_DODGE_DTB=y
|
||||
|
||||
# Properties
|
||||
TARGET_ODM_PROP += $(DEVICE_PATH)/odm.prop
|
||||
TARGET_SYSTEM_EXT_PROP += $(DEVICE_PATH)/system_ext.prop
|
||||
TARGET_VENDOR_PROP += $(DEVICE_PATH)/vendor.prop
|
||||
|
||||
# Recovery
|
||||
TARGET_RECOVERY_UI_MARGIN_HEIGHT := 103
|
||||
|
||||
# SEPolicy
|
||||
BOARD_VENDOR_SEPOLICY_DIRS += device/oneplus/dodge/sepolicy/vendor
|
||||
|
||||
# Include the proprietary files BoardConfig.
|
||||
include vendor/oneplus/dodge/BoardConfigVendor.mk
|
||||
@@ -111,6 +111,12 @@
|
||||
android:resource="@string/bypass_charging_summary" />
|
||||
</activity>
|
||||
|
||||
<!-- BypassCharging service to monitor battery level -->
|
||||
<service
|
||||
android:name=".bypasschrg.BypassChargingService"
|
||||
android:exported="true"
|
||||
android:foregroundServiceType="connectedDevice" />
|
||||
|
||||
<!-- BypassChargingTile service -->
|
||||
<service
|
||||
android:name=".bypasschrg.BypassChargingTile"
|
||||
|
||||
20
DeviceSettings/res/drawable/ic_bypass_waiting.xml
Normal file
20
DeviceSettings/res/drawable/ic_bypass_waiting.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="30dp"
|
||||
android:viewportWidth="32"
|
||||
android:viewportHeight="40"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M23,18a6,6 0,1 0,-6 -6A6,6 0,0 0,23 18ZM22,10a1,1 0,0 1,2 0v1.38l1.45,0.73a1,1 0,0 1,0.44 1.34A1,1 0,0 1,25 14a0.93,0.93 0,0 1,-0.45 -0.11l-2,-1A1,1 0,0 1,22 12Z" />
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M2,17v4a1,1 0,0 0,1 1H4V16H3A1,1 0,0 0,2 17Z" />
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M23,20a8,8 0,0 1,-8 -8H8a2,2 0,0 0,-2 2V24a2,2 0,0 0,2 2H28a2,2 0,0 0,2 -2V15.86A8,8 0,0 1,23 20Z" />
|
||||
|
||||
</vector>
|
||||
25
DeviceSettings/res/drawable/ic_custom_seekbar_minus.xml
Normal file
25
DeviceSettings/res/drawable/ic_custom_seekbar_minus.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018-2021 crDroid Android Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0" >
|
||||
<path
|
||||
android:fillColor="?android:attr/colorControlNormal"
|
||||
android:pathData="M24 4C12.972 4 4 12.972 4 24s8.972 20 20 20s20 -8.972 20 -20S35.028 4 24 4zM32.5 25.5h-17c-0.829 0 -1.5 -0.671 -1.5 -1.5s0.671 -1.5 1.5 -1.5h17c0.829 0 1.5 0.671 1.5 1.5S33.329 25.5 32.5 25.5z" />
|
||||
</vector>
|
||||
25
DeviceSettings/res/drawable/ic_custom_seekbar_plus.xml
Normal file
25
DeviceSettings/res/drawable/ic_custom_seekbar_plus.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018-2021 crDroid Android Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0" >
|
||||
<path
|
||||
android:fillColor="?android:attr/colorControlNormal"
|
||||
android:pathData="M24 4C12.972 4 4 12.972 4 24s8.972 20 20 20s20 -8.972 20 -20S35.028 4 24 4zM32.5 25.5h-7v7c0 0.829 -0.672 1.5 -1.5 1.5s-1.5 -0.671 -1.5 -1.5v-7h-7c-0.828 0 -1.5 -0.671 -1.5 -1.5s0.672 -1.5 1.5 -1.5h7v-7c0 -0.829 0.672 -1.5 1.5 -1.5s1.5 0.671 1.5 1.5v7h7c0.828 0 1.5 0.671 1.5 1.5S33.328 25.5 32.5 25.5z" />
|
||||
</vector>
|
||||
26
DeviceSettings/res/drawable/ic_custom_seekbar_reset.xml
Normal file
26
DeviceSettings/res/drawable/ic_custom_seekbar_reset.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 Havoc-OS
|
||||
Copyright (C) 2022 DerpFest
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0" >
|
||||
<path
|
||||
android:fillColor="?android:attr/colorControlNormal"
|
||||
android:pathData="M14.123456746339798,12.042328000068665 c0,-0.7430335164070133 -0.6079365134239197,-1.3509700298309326 -1.3509700298309326,-1.3509700298309326 s-1.3509700298309326,0.6079365134239197 -1.3509700298309326,1.3509700298309326 s0.6079365134239197,1.3509700298309326 1.3509700298309326,1.3509700298309326 s1.3509700298309326,-0.6079365134239197 1.3509700298309326,-1.3509700298309326 zM12.772486716508865,5.962962865829468 c-3.3571605241298674,0 -6.079365134239197,2.7222046101093293 -6.079365134239197,6.079365134239197 L4.66666653752327,12.042328000068665 l2.7019400596618652,2.7019400596618652 l2.7019400596618652,-2.7019400596618652 L8.044091612100601,12.042328000068665 c0,-2.6141270077228547 2.1142680966854095,-4.728395104408264 4.728395104408264,-4.728395104408264 s4.728395104408264,2.1142680966854095 4.728395104408264,4.728395104408264 s-2.1142680966854095,4.728395104408264 -4.728395104408264,4.728395104408264 c-1.0199823725223542,0 -1.965661393404007,-0.3309876573085789 -2.742469160556793,-0.8781305193901066 l-0.9591887211799618,0.9726984214782719 C10.097566057443618,17.648853623867033 11.380987585783004,18.12169313430786 12.772486716508865,18.12169313430786 c3.3571605241298674,0 6.079365134239197,-2.7222046101093293 6.079365134239197,-6.079365134239197 s-2.7222046101093293,-6.079365134239197 -6.079365134239197,-6.079365134239197 z" />
|
||||
</vector>
|
||||
12
DeviceSettings/res/drawable/ic_waiting.xml
Normal file
12
DeviceSettings/res/drawable/ic_waiting.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="50"
|
||||
android:viewportHeight="50"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M41.9,23.9c-0.3,-6.1 -4,-11.8 -9.5,-14.4 -6,-2.7 -13.3,-1.6 -18.3,2.6 -4.8,4 -7,10.5 -5.6,16.6 1.3,6 6,10.9 11.9,12.5 7.1,2 13.6,-1.4 17.6,-7.2 -3.6,4.8 -9.1,8 -15.2,6.9 -6.1,-1.1 -11.1,-5.7 -12.5,-11.7 -1.5,-6.4 1.5,-13.1 7.2,-16.4 5.9,-3.4 14.2,-2.1 18.1,3.7 1,1.4 1.7,3.1 2,4.8 0.3,1.4 0.2,2.9 0.4,4.3 0.2,1.3 1.3,3 2.8,2.1 1.3,-0.8 1.2,-2.5 1.1,-3.8 0,-0.4 0.1,0.7 0,0z" />
|
||||
|
||||
</vector>
|
||||
150
DeviceSettings/res/layout/custom_seekbar_preference.xml
Normal file
150
DeviceSettings/res/layout/custom_seekbar_preference.xml
Normal file
@@ -0,0 +1,150 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2017-2022 crDroid Android 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"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:background="?android:attr/activatedBackgroundIndicator"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/icon_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="48dp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingEnd="7dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<androidx.preference.internal.PreferenceImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitCenter"
|
||||
android:paddingStart="8dp"
|
||||
app:maxWidth="48dp"
|
||||
app:maxHeight="48dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:ellipsize="marquee" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@android:id/title"
|
||||
android:layout_alignStart="@android:id/title"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:maxLines="10"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/value_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@android:id/summary"
|
||||
android:layout_alignStart="@android:id/title" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reset"
|
||||
android:src="@drawable/ic_custom_seekbar_reset"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_toEndOf="@id/value"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/seekbar_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/value_frame"
|
||||
android:layout_alignStart="@android:id/title" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/minus"
|
||||
android:src="@drawable/ic_custom_seekbar_minus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/plus"
|
||||
android:src="@drawable/ic_custom_seekbar_plus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/seekbar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_toEndOf="@id/minus"
|
||||
android:layout_toStartOf="@id/plus"
|
||||
android:layout_centerVertical="true" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<!-- Preference should place its actual preference widget here. -->
|
||||
<LinearLayout android:id="@android:id/widget_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="end|center_vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:orientation="vertical" />
|
||||
</LinearLayout>
|
||||
11
DeviceSettings/res/values/attrs.xml
Normal file
11
DeviceSettings/res/values/attrs.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
<declare-styleable name="CustomSeekBarPreference">
|
||||
<attr name="defaultValueText" format="string" />
|
||||
<attr name="interval" format="integer" />
|
||||
<attr name="showSign" format="boolean" />
|
||||
<attr name="units" format="string|reference" />
|
||||
<attr name="continuousUpdates" format="boolean" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@@ -81,7 +81,20 @@
|
||||
<string name="bypass_charging_unavailable">Bypass charging is not supported on this device</string>
|
||||
<string name="bypass_charging_enabled">Enabled</string>
|
||||
<string name="bypass_charging_disabled">Disabled</string>
|
||||
<<<<<<< HEAD:DeviceSettings/res/values/strings.xml
|
||||
<string name="bypass_charging_error">Coudn\'t enable Bypass Charging.</string>
|
||||
=======
|
||||
<string name="bypass_charging_error">It was not possible to change Bypass Charging status. Please, try again later.</string>
|
||||
<string name="bypass_charging_target_title">Target level</string>
|
||||
<string name="bypass_charging_target_summary">Battery will charge until it reaches target level, then bypass charging will be activated.</string>
|
||||
<string name="bypass_charging_waiting">Battery will charge until it reaches target level</string>
|
||||
|
||||
<!-- Custom seekbar -->
|
||||
<string name="custom_seekbar_value">Value: <xliff:g id="v">%s</xliff:g></string>
|
||||
<string name="custom_seekbar_default_value">by default</string>
|
||||
<string name="custom_seekbar_default_value_to_set">Default value: <xliff:g id="v">%s</xliff:g>\nLong tap to set</string>
|
||||
<string name="custom_seekbar_default_value_is_set">Default value is set</string>
|
||||
>>>>>>> 96046be (DeviceSettings: rework bypass charging):device-settings/res/values/strings.xml
|
||||
|
||||
<!-- GameBar Overlay -->
|
||||
<string name="game_bar_title">GameBar</string>
|
||||
|
||||
@@ -1,14 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<SwitchPreferenceCompat
|
||||
android:key="bypass_charging"
|
||||
android:title="@string/bypass_charging_title"
|
||||
android:icon="@drawable/ic_bypass_charging"
|
||||
android:summary="@string/bypass_charging_summary"
|
||||
android:persistent="false" />
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="bypass_charging_info"
|
||||
android:title="@string/bypass_charging_info_title"
|
||||
android:selectable="false" />
|
||||
<PreferenceCategory
|
||||
android:key="bypass_charging_category"
|
||||
android:title="@string/bypass_charging_category_title">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="bypass_charging"
|
||||
android:title="@string/bypass_charging_title"
|
||||
android:icon="@drawable/ic_bypass_charging"
|
||||
android:summary="@string/bypass_charging_summary"
|
||||
android:persistent="false" />
|
||||
|
||||
<org.lineageos.device.DeviceSettings.preferences.CustomSeekBarPreference
|
||||
android:key="bypass_charging_target"
|
||||
android:title="@string/bypass_charging_target_title"
|
||||
android:summary="@string/bypass_charging_target_summary"
|
||||
android:icon="@drawable/ic_bypass_waiting"
|
||||
android:dependency="bypass_charging"
|
||||
android:defaultValue="0"
|
||||
android:max="100"
|
||||
settings:min="0"
|
||||
settings:interval="5"
|
||||
settings:units="%"
|
||||
settings:showSign="true" />
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="bypass_charging_info"
|
||||
android:title="@string/bypass_charging_info_title"
|
||||
android:selectable="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -29,14 +29,14 @@ import android.media.AudioManager;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String SLIDER_STATE
|
||||
= "/proc/tristatekey/tri_state";
|
||||
/* Alert Slider */
|
||||
public static final String NODE_SLIDER_STATE = "/proc/tristatekey/tri_state";
|
||||
|
||||
public static final String NOTIF_SLIDER_PANEL_KEY = "notification_slider";
|
||||
public static final String NOTIF_SLIDER_USAGE_KEY = "slider_usage";
|
||||
public static final String NOTIF_SLIDER_ACTION_TOP_KEY = "action_top_position";
|
||||
public static final String NOTIF_SLIDER_ACTION_MIDDLE_KEY = "action_middle_position";
|
||||
public static final String NOTIF_SLIDER_ACTION_BOTTOM_KEY = "action_bottom_position";
|
||||
public static final String KEY_NOTIF_SLIDER_PANEL = "notification_slider";
|
||||
public static final String KEY_NOTIF_SLIDER_USAGE = "slider_usage";
|
||||
public static final String KEY_NOTIF_SLIDER_ACTION_TOP = "action_top_position";
|
||||
public static final String KEY_NOTIF_SLIDER_ACTION_MIDDLE = "action_middle_position";
|
||||
public static final String KEY_NOTIF_SLIDER_ACTION_BOTTOM = "action_bottom_position";
|
||||
|
||||
public static final String EXTRA_SLIDER_USAGE = "usage";
|
||||
public static final String EXTRA_SLIDER_ACTIONS = "actions";
|
||||
@@ -76,4 +76,17 @@ public class Constants {
|
||||
// Holds <preference_key> -> <proc_node> mapping
|
||||
public static final Map<String, String> sBooleanNodePreferenceMap = new HashMap<>();
|
||||
public static final Map<String, String> sStringNodePreferenceMap = new HashMap<>();
|
||||
|
||||
/* OnePulse PWM */
|
||||
public static final String NODE_ONEPULSE_PWM = "/sys/kernel/oplus_display/pwm_onepulse";
|
||||
public static final String KEY_ONEPULSE_PWM = "onepulse_pwm";
|
||||
|
||||
/* Bypass Charging */
|
||||
public static final String NODE_BYPASS_CHARGING = "/sys/class/oplus_chg/battery/mmi_charging_enable";
|
||||
public static final String KEY_BYPASS_CHARGING = "bypass_charging";
|
||||
public static final String KEY_BYPASS_CHARGING_TARGET = "bypass_charging_target";
|
||||
|
||||
public static final int BYPASS_OFF = 0;
|
||||
public static final int BYPASS_WAITING = 1;
|
||||
public static final int BYPASS_ON = 2;
|
||||
}
|
||||
|
||||
@@ -98,17 +98,30 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
// mUSB2FastChargeModeSwitch.setEnabled(false);
|
||||
// }
|
||||
|
||||
<<<<<<< HEAD:DeviceSettings/src/org/lineageos/device/DeviceSettings/DeviceSettings.java
|
||||
=======
|
||||
mOnePulsePWMSwitch = (SwitchPreferenceCompat) findPreference(Constants.KEY_ONEPULSE_PWM);
|
||||
if (Utils.fileWritable(Constants.NODE_ONEPULSE_PWM)) {
|
||||
mOnePulsePWMSwitch.setEnabled(true);
|
||||
mOnePulsePWMSwitch.setChecked(sharedPrefs.getBoolean(Constants.KEY_ONEPULSE_PWM,
|
||||
Utils.getFileValueAsBoolean(Constants.NODE_ONEPULSE_PWM, false)));
|
||||
mOnePulsePWMSwitch.setOnPreferenceChangeListener(this);
|
||||
} else {
|
||||
mOnePulsePWMSwitch.setEnabled(false);
|
||||
}
|
||||
|
||||
>>>>>>> 96046be (DeviceSettings: rework bypass charging):device-settings/src/org/lineageos/device/settings/DeviceSettings.java
|
||||
initNotificationSliderPreference();
|
||||
}
|
||||
|
||||
private void initNotificationSliderPreference() {
|
||||
registerPreferenceListener(Constants.NOTIF_SLIDER_USAGE_KEY);
|
||||
registerPreferenceListener(Constants.NOTIF_SLIDER_ACTION_TOP_KEY);
|
||||
registerPreferenceListener(Constants.NOTIF_SLIDER_ACTION_MIDDLE_KEY);
|
||||
registerPreferenceListener(Constants.NOTIF_SLIDER_ACTION_BOTTOM_KEY);
|
||||
registerPreferenceListener(Constants.KEY_NOTIF_SLIDER_USAGE);
|
||||
registerPreferenceListener(Constants.KEY_NOTIF_SLIDER_ACTION_TOP);
|
||||
registerPreferenceListener(Constants.KEY_NOTIF_SLIDER_ACTION_MIDDLE);
|
||||
registerPreferenceListener(Constants.KEY_NOTIF_SLIDER_ACTION_BOTTOM);
|
||||
|
||||
ListPreference usagePref = (ListPreference) findPreference(
|
||||
Constants.NOTIF_SLIDER_USAGE_KEY);
|
||||
Constants.KEY_NOTIF_SLIDER_USAGE);
|
||||
handleSliderUsageChange(usagePref.getValue());
|
||||
}
|
||||
|
||||
@@ -138,18 +151,28 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
// Utils.writeValue(FILE_FAST_CHARGE, enabled ? "1" : "0");
|
||||
// return true;
|
||||
// }
|
||||
<<<<<<< HEAD:DeviceSettings/src/org/lineageos/device/DeviceSettings/DeviceSettings.java
|
||||
=======
|
||||
if (preference == mOnePulsePWMSwitch) {
|
||||
boolean enabled = (Boolean) newValue;
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
sharedPrefs.edit().putBoolean(Constants.KEY_ONEPULSE_PWM, enabled).commit();
|
||||
Utils.writeValue(Constants.NODE_ONEPULSE_PWM, enabled ? "1" : "0");
|
||||
return true;
|
||||
}
|
||||
>>>>>>> 96046be (DeviceSettings: rework bypass charging):device-settings/src/org/lineageos/device/settings/DeviceSettings.java
|
||||
|
||||
String key = preference.getKey();
|
||||
switch (key) {
|
||||
case Constants.NOTIF_SLIDER_USAGE_KEY:
|
||||
case Constants.KEY_NOTIF_SLIDER_USAGE:
|
||||
return handleSliderUsageChange((String) newValue) &&
|
||||
handleSliderUsageDefaultsChange((String) newValue) &&
|
||||
notifySliderUsageChange((String) newValue);
|
||||
case Constants.NOTIF_SLIDER_ACTION_TOP_KEY:
|
||||
case Constants.KEY_NOTIF_SLIDER_ACTION_TOP:
|
||||
return notifySliderActionChange(0, (String) newValue);
|
||||
case Constants.NOTIF_SLIDER_ACTION_MIDDLE_KEY:
|
||||
case Constants.KEY_NOTIF_SLIDER_ACTION_MIDDLE:
|
||||
return notifySliderActionChange(1, (String) newValue);
|
||||
case Constants.NOTIF_SLIDER_ACTION_BOTTOM_KEY:
|
||||
case Constants.KEY_NOTIF_SLIDER_ACTION_BOTTOM:
|
||||
return notifySliderActionChange(2, (String) newValue);
|
||||
default:
|
||||
break;
|
||||
@@ -252,11 +275,11 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
private boolean updateSliderActions(int entriesResId, int entryValuesResId) {
|
||||
String[] entries = getResources().getStringArray(entriesResId);
|
||||
String[] entryValues = getResources().getStringArray(entryValuesResId);
|
||||
return updateSliderPreference(Constants.NOTIF_SLIDER_ACTION_TOP_KEY,
|
||||
return updateSliderPreference(Constants.KEY_NOTIF_SLIDER_ACTION_TOP,
|
||||
entries, entryValues) &&
|
||||
updateSliderPreference(Constants.NOTIF_SLIDER_ACTION_MIDDLE_KEY,
|
||||
updateSliderPreference(Constants.KEY_NOTIF_SLIDER_ACTION_MIDDLE,
|
||||
entries, entryValues) &&
|
||||
updateSliderPreference(Constants.NOTIF_SLIDER_ACTION_BOTTOM_KEY,
|
||||
updateSliderPreference(Constants.KEY_NOTIF_SLIDER_ACTION_BOTTOM,
|
||||
entries, entryValues);
|
||||
}
|
||||
|
||||
@@ -266,11 +289,11 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
return false;
|
||||
}
|
||||
|
||||
return updateSliderPreferenceValue(Constants.NOTIF_SLIDER_ACTION_TOP_KEY,
|
||||
return updateSliderPreferenceValue(Constants.KEY_NOTIF_SLIDER_ACTION_TOP,
|
||||
defaults[0]) &&
|
||||
updateSliderPreferenceValue(Constants.NOTIF_SLIDER_ACTION_MIDDLE_KEY,
|
||||
updateSliderPreferenceValue(Constants.KEY_NOTIF_SLIDER_ACTION_MIDDLE,
|
||||
defaults[1]) &&
|
||||
updateSliderPreferenceValue(Constants.NOTIF_SLIDER_ACTION_BOTTOM_KEY,
|
||||
updateSliderPreferenceValue(Constants.KEY_NOTIF_SLIDER_ACTION_BOTTOM,
|
||||
defaults[2]);
|
||||
}
|
||||
|
||||
@@ -300,15 +323,15 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
ListPreference p;
|
||||
|
||||
p = (ListPreference) findPreference(
|
||||
Constants.NOTIF_SLIDER_ACTION_TOP_KEY);
|
||||
Constants.KEY_NOTIF_SLIDER_ACTION_TOP);
|
||||
actions[0] = Integer.parseInt(p.getValue());
|
||||
|
||||
p = (ListPreference) findPreference(
|
||||
Constants.NOTIF_SLIDER_ACTION_MIDDLE_KEY);
|
||||
Constants.KEY_NOTIF_SLIDER_ACTION_MIDDLE);
|
||||
actions[1] = Integer.parseInt(p.getValue());
|
||||
|
||||
p = (ListPreference) findPreference(
|
||||
Constants.NOTIF_SLIDER_ACTION_BOTTOM_KEY);
|
||||
Constants.KEY_NOTIF_SLIDER_ACTION_BOTTOM);
|
||||
actions[2] = Integer.parseInt(p.getValue());
|
||||
|
||||
return actions;
|
||||
@@ -322,7 +345,7 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
|
||||
private boolean notifySliderActionChange(int index, String value) {
|
||||
ListPreference p = (ListPreference) findPreference(
|
||||
Constants.NOTIF_SLIDER_USAGE_KEY);
|
||||
Constants.KEY_NOTIF_SLIDER_USAGE);
|
||||
int usage = Integer.parseInt(p.getValue());
|
||||
|
||||
int[] actions = getCurrentSliderActions();
|
||||
@@ -348,7 +371,7 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
SharedPreferences prefs = context.getSharedPreferences(
|
||||
context.getPackageName() + "_preferences", Context.MODE_PRIVATE);
|
||||
|
||||
String usage = prefs.getString(Constants.NOTIF_SLIDER_USAGE_KEY,
|
||||
String usage = prefs.getString(Constants.KEY_NOTIF_SLIDER_USAGE,
|
||||
res.getString(R.string.config_defaultNotificationSliderUsage));
|
||||
|
||||
int defaultsResId = getDefaultResIdForUsage(usage);
|
||||
@@ -362,19 +385,19 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
}
|
||||
|
||||
String actionTop = prefs.getString(
|
||||
Constants.NOTIF_SLIDER_ACTION_TOP_KEY, defaults[0]);
|
||||
Constants.KEY_NOTIF_SLIDER_ACTION_TOP, defaults[0]);
|
||||
|
||||
String actionMiddle = prefs.getString(
|
||||
Constants.NOTIF_SLIDER_ACTION_MIDDLE_KEY, defaults[1]);
|
||||
Constants.KEY_NOTIF_SLIDER_ACTION_MIDDLE, defaults[1]);
|
||||
|
||||
String actionBottom = prefs.getString(
|
||||
Constants.NOTIF_SLIDER_ACTION_BOTTOM_KEY, defaults[2]);
|
||||
Constants.KEY_NOTIF_SLIDER_ACTION_BOTTOM, defaults[2]);
|
||||
|
||||
prefs.edit()
|
||||
.putString(Constants.NOTIF_SLIDER_USAGE_KEY, usage)
|
||||
.putString(Constants.NOTIF_SLIDER_ACTION_TOP_KEY, actionTop)
|
||||
.putString(Constants.NOTIF_SLIDER_ACTION_MIDDLE_KEY, actionMiddle)
|
||||
.putString(Constants.NOTIF_SLIDER_ACTION_BOTTOM_KEY, actionBottom)
|
||||
.putString(Constants.KEY_NOTIF_SLIDER_USAGE, usage)
|
||||
.putString(Constants.KEY_NOTIF_SLIDER_ACTION_TOP, actionTop)
|
||||
.putString(Constants.KEY_NOTIF_SLIDER_ACTION_MIDDLE, actionMiddle)
|
||||
.putString(Constants.KEY_NOTIF_SLIDER_ACTION_BOTTOM, actionBottom)
|
||||
.commit();
|
||||
|
||||
sendUpdateBroadcast(context, Integer.parseInt(usage), new int[] {
|
||||
@@ -393,6 +416,18 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
||||
// }
|
||||
// }
|
||||
|
||||
<<<<<<< HEAD:DeviceSettings/src/org/lineageos/device/DeviceSettings/DeviceSettings.java
|
||||
=======
|
||||
public static void restoreOnePulsePwmSetting(Context context) {
|
||||
if (Utils.fileWritable(Constants.NODE_ONEPULSE_PWM)) {
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean value = sharedPrefs.getBoolean(Constants.KEY_ONEPULSE_PWM,
|
||||
Utils.getFileValueAsBoolean(Constants.NODE_ONEPULSE_PWM, false));
|
||||
Utils.writeValue(Constants.NODE_ONEPULSE_PWM, value ? "1" : "0");
|
||||
}
|
||||
}
|
||||
|
||||
>>>>>>> 96046be (DeviceSettings: rework bypass charging):device-settings/src/org/lineageos/device/settings/DeviceSettings.java
|
||||
private static int getDefaultResIdForUsage(String usage) {
|
||||
switch (usage) {
|
||||
case Constants.NOTIF_SLIDER_FOR_NOTIFICATION:
|
||||
|
||||
@@ -80,7 +80,7 @@ public abstract class SliderControllerBase {
|
||||
}
|
||||
|
||||
try {
|
||||
int state = Integer.parseInt(FileUtils.readOneLine(Constants.SLIDER_STATE).trim());
|
||||
int state = Integer.parseInt(FileUtils.readOneLine(Constants.NODE_SLIDER_STATE).trim());
|
||||
ret = processAction(mActions[state - 1]);
|
||||
if (ret > 0 && notify) {
|
||||
sendUpdateBroadcast(context, state - 1, ret);
|
||||
|
||||
@@ -17,53 +17,30 @@
|
||||
|
||||
package org.lineageos.device.DeviceSettings.bypasschrg;
|
||||
|
||||
import static lineageos.health.HealthInterface.MODE_AUTO;
|
||||
import static lineageos.health.HealthInterface.MODE_LIMIT;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.os.BatteryManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.lineageos.device.DeviceSettings.Constants;
|
||||
import org.lineageos.device.DeviceSettings.R;
|
||||
import org.lineageos.device.DeviceSettings.utils.FileUtils;
|
||||
|
||||
/**
|
||||
* This class is implemented to coexist with Lineage Charging Control (CC).
|
||||
* Bypass Charging will override (disable) CC, while it's enabled.
|
||||
* CC status will be restored, when Bypass Charging is disabled.
|
||||
* Any user changes to CC settings, while Bypass Charging is enabled,
|
||||
* will override Bypass Charging settings.
|
||||
*/
|
||||
public class BypassChargingController {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final boolean DEBUG = true;
|
||||
private static final String TAG = "BypassChargingController";
|
||||
private static final String BYPASS_CHARGING_NODE = "/sys/class/oplus_chg/battery/mmi_charging_enable";
|
||||
private static final String KEY_BYPASS_CHARGING_ENABLED = "bypass_charging_enabled";
|
||||
|
||||
// Bypass modes
|
||||
private static final String BYPASS_CHARGING_ENABLED = "0";
|
||||
private static final String BYPASS_CHARGING_DISABLED = "1";
|
||||
private static final String KEY_BATTERY_LEVEL = "current_battery_level";
|
||||
|
||||
private static final int CC_LIMIT_MIN = 10;
|
||||
private static final int CC_LIMIT_MAX = 100;
|
||||
private static final int CC_LIMIT_DEF = 80;
|
||||
|
||||
// Charging Control settings
|
||||
private static final String KEY_CHARGING_CONTROL_ENABLED = "charging_control_enabled";
|
||||
private static final String KEY_CHARGING_CONTROL_MODE = "charging_control_mode";
|
||||
private static final String KEY_CHARGING_CONTROL_LIMIT = "charging_control_charging_limit";
|
||||
private int mBatteryLevel;
|
||||
|
||||
private Context mContext;
|
||||
private ContentResolver mContentResolver;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private static BypassChargingController sInstance;
|
||||
public static synchronized BypassChargingController getInstance(Context context) {
|
||||
@@ -76,37 +53,45 @@ public class BypassChargingController {
|
||||
private BypassChargingController(Context context) {
|
||||
mContext = context.getApplicationContext();
|
||||
mContentResolver = mContext.getContentResolver();
|
||||
mBatteryLevel = getLevelFromIntent();
|
||||
if (isValidLevel(mBatteryLevel)) {
|
||||
saveCurrentBatteryLevel(mBatteryLevel);
|
||||
}
|
||||
}
|
||||
|
||||
private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
switch(uri.getLastPathSegment()) {
|
||||
case KEY_CHARGING_CONTROL_ENABLED:
|
||||
case KEY_CHARGING_CONTROL_MODE:
|
||||
case KEY_CHARGING_CONTROL_LIMIT:
|
||||
break;
|
||||
// Called from Service when battery level changes
|
||||
public void onBatteryLevelChanged(int level) {
|
||||
synchronized (mLock) {
|
||||
if (isValidLevel(level) && (mBatteryLevel == -1 || mBatteryLevel != level)) {
|
||||
mBatteryLevel = level;
|
||||
saveCurrentBatteryLevel(level);
|
||||
maybeEnableBypassCharging();
|
||||
if (DEBUG) Log.d(TAG, "Battery level changed (service): " + level + "%");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public boolean isBypassChargingSupported() {
|
||||
return isNodeAccessible(BYPASS_CHARGING_NODE);
|
||||
}
|
||||
|
||||
public boolean isBypassChargingEnabled() {
|
||||
try {
|
||||
String value = FileUtils.readOneLine(BYPASS_CHARGING_NODE);
|
||||
return value != null && BYPASS_CHARGING_ENABLED.equals(value);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to read bypass sysnode", e);
|
||||
return false;
|
||||
// get battery level using a sticky intent
|
||||
private int getLevelFromIntent() {
|
||||
android.content.IntentFilter filter =
|
||||
new android.content.IntentFilter(android.content.Intent.ACTION_BATTERY_CHANGED);
|
||||
android.content.Intent intent = mContext.registerReceiver(null, filter);
|
||||
|
||||
if (intent == null) {
|
||||
if (DEBUG) Log.w(TAG, "Sticky battery intent was null");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int extraLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||
int extraScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
||||
|
||||
return (extraLevel >= 0 && extraScale > 0) ?
|
||||
(int)((extraLevel / (float)extraScale) * 100) : -1;
|
||||
}
|
||||
|
||||
private boolean isNodeAccessible(String node) {
|
||||
try {
|
||||
String value = FileUtils.readOneLine(node);
|
||||
String status = FileUtils.readOneLine(node);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Node " + node + " not accessible", e);
|
||||
@@ -114,102 +99,146 @@ public class BypassChargingController {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean writeToNode(String value) {
|
||||
try {
|
||||
FileUtils.writeLine(BYPASS_CHARGING_NODE, value);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to write bypass sysnode", e);
|
||||
private boolean writeToNode(String status) {
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
FileUtils.writeLine(Constants.NODE_BYPASS_CHARGING, status);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to write bypass sysnode", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private int readFromNode() {
|
||||
synchronized (mLock) {
|
||||
try {
|
||||
String value = FileUtils.readOneLine(Constants.NODE_BYPASS_CHARGING);
|
||||
return Integer.parseInt(value);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to read bypass sysnode", e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBypassChargingSupported() {
|
||||
return isNodeAccessible(Constants.NODE_BYPASS_CHARGING);
|
||||
}
|
||||
|
||||
private void maybeEnableBypassCharging() {
|
||||
if (mBatteryLevel >= getBypassChargingTarget()
|
||||
&& getBypassChargingStatus() == Constants.BYPASS_WAITING) {
|
||||
if (writeToNode(BYPASS_CHARGING_ENABLED)) {
|
||||
saveBypassChargingStatus(Constants.BYPASS_ON);
|
||||
BypassChargingService.stop(mContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void maybeDisableBypassCharging(int target) {
|
||||
if (mBatteryLevel < target
|
||||
&& getBypassChargingStatus() == Constants.BYPASS_ON) {
|
||||
if (writeToNode(BYPASS_CHARGING_DISABLED)) {
|
||||
saveBypassChargingStatus(Constants.BYPASS_WAITING);
|
||||
BypassChargingService.start(mContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean enableBypassCharging() {
|
||||
int level = getCurrentBatteryLevel();
|
||||
|
||||
if (!isValidLevel(level)) {
|
||||
if (DEBUG) Log.w(TAG, "Cannot enable bypass: invalid battery level " + level);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setBypassCharging(boolean enable) {
|
||||
if (enable) {
|
||||
enableBypassCharging();
|
||||
if (getBypassChargingTarget() > level) {
|
||||
saveBypassChargingStatus(Constants.BYPASS_WAITING);
|
||||
BypassChargingService.start(mContext);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
disableBypassCharging();
|
||||
else if (writeToNode(BYPASS_CHARGING_ENABLED)) {
|
||||
saveBypassChargingStatus(Constants.BYPASS_ON);
|
||||
BypassChargingService.stop(mContext);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void enableBypassCharging() {
|
||||
setChargingControlEnabled(true);
|
||||
setChargingControlMode(MODE_LIMIT);
|
||||
setChargingControlLimit(CC_LIMIT_MIN);
|
||||
writeToNode(BYPASS_CHARGING_ENABLED);
|
||||
public boolean disableBypassCharging() {
|
||||
if (writeToNode(BYPASS_CHARGING_DISABLED)) {
|
||||
saveBypassChargingStatus(Constants.BYPASS_OFF);
|
||||
BypassChargingService.stop(mContext);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void disableBypassCharging() {
|
||||
writeToNode(BYPASS_CHARGING_DISABLED);
|
||||
setChargingControlLimit(CC_LIMIT_DEF);
|
||||
// setChargingControlMode(MODE_AUTO);
|
||||
setChargingControlEnabled(false);
|
||||
}
|
||||
|
||||
private void saveBypassChargingEnabled(boolean enabled) {
|
||||
private void saveBypassChargingStatus(int status) {
|
||||
PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||
.edit()
|
||||
.putBoolean(KEY_BYPASS_CHARGING_ENABLED, enabled)
|
||||
.commit();
|
||||
.putInt(Constants.KEY_BYPASS_CHARGING, status)
|
||||
.apply();
|
||||
}
|
||||
|
||||
private boolean isSavedBypassChargingEnabled() {
|
||||
public int getBypassChargingStatus() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||
.getBoolean(KEY_BYPASS_CHARGING_ENABLED, false);
|
||||
.getInt(Constants.KEY_BYPASS_CHARGING, Constants.BYPASS_OFF);
|
||||
}
|
||||
|
||||
private void backupChargingControlSettings() {
|
||||
public void setBypassChargingTarget(int target) {
|
||||
if (target >= 0 && target <= 100) {
|
||||
saveBypassChargingTarget(target);
|
||||
if (getBypassChargingStatus() == Constants.BYPASS_ON) {
|
||||
maybeDisableBypassCharging(target);
|
||||
}
|
||||
else {
|
||||
maybeEnableBypassCharging();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveBypassChargingTarget(int target) {
|
||||
PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||
.edit()
|
||||
.putInt(KEY_CHARGING_CONTROL_MODE, getChargingControlMode())
|
||||
.putInt(KEY_CHARGING_CONTROL_LIMIT, getChargingControlLimit())
|
||||
.putBoolean(KEY_CHARGING_CONTROL_ENABLED, isChargingControlEnabled())
|
||||
.commit();
|
||||
.putInt(Constants.KEY_BYPASS_CHARGING_TARGET, target)
|
||||
.apply();
|
||||
}
|
||||
|
||||
private void restoreChargingControlSettings() {
|
||||
SharedPreferences sharedPreferences =
|
||||
PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
setChargingControlMode(sharedPreferences.getInt(
|
||||
KEY_CHARGING_CONTROL_LIMIT, CC_LIMIT_DEF));
|
||||
setChargingControlMode(sharedPreferences.getInt(
|
||||
KEY_CHARGING_CONTROL_MODE, MODE_AUTO));
|
||||
setChargingControlEnabled(sharedPreferences.getBoolean(
|
||||
KEY_CHARGING_CONTROL_ENABLED, false));
|
||||
public int getBypassChargingTarget() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||
.getInt(Constants.KEY_BYPASS_CHARGING_TARGET, 0);
|
||||
}
|
||||
|
||||
private boolean isChargingControlEnabled() {
|
||||
return Settings.System.getInt(mContentResolver,
|
||||
KEY_CHARGING_CONTROL_ENABLED, 0) != 0;
|
||||
}
|
||||
|
||||
private void setChargingControlEnabled(boolean enabled) {
|
||||
Settings.System.putInt(mContentResolver,
|
||||
KEY_CHARGING_CONTROL_ENABLED, enabled ? 1 : 0);
|
||||
}
|
||||
|
||||
private int getChargingControlMode() {
|
||||
return Settings.System.getInt(mContentResolver,
|
||||
KEY_CHARGING_CONTROL_MODE, MODE_AUTO);
|
||||
}
|
||||
|
||||
private void setChargingControlMode(int mode) {
|
||||
Settings.System.putInt(mContentResolver,
|
||||
KEY_CHARGING_CONTROL_MODE, mode);
|
||||
}
|
||||
|
||||
private int getChargingControlLimit() {
|
||||
return Settings.System.getInt(mContentResolver,
|
||||
KEY_CHARGING_CONTROL_LIMIT, CC_LIMIT_DEF);
|
||||
}
|
||||
|
||||
private void setChargingControlLimit(int limit) {
|
||||
if (limit < CC_LIMIT_MIN || limit > CC_LIMIT_MAX) {
|
||||
return;
|
||||
private void saveCurrentBatteryLevel(int level) {
|
||||
synchronized (mLock) {
|
||||
if (isValidLevel(level)) {
|
||||
PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||
.edit()
|
||||
.putInt(KEY_BATTERY_LEVEL, level)
|
||||
.apply();
|
||||
} else {
|
||||
if (DEBUG) Log.w(TAG, "Attempted to save invalid battery level: " + level);
|
||||
}
|
||||
}
|
||||
Settings.System.putInt(mContentResolver,
|
||||
KEY_CHARGING_CONTROL_LIMIT, limit);
|
||||
}
|
||||
|
||||
public int getCurrentBatteryLevel() {
|
||||
synchronized (mLock) {
|
||||
int level = PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||
.getInt(KEY_BATTERY_LEVEL, -1);
|
||||
if (!isValidLevel(level)) {
|
||||
if (DEBUG) Log.w(TAG, "Battery level is invalid or not set: " + level);
|
||||
}
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidLevel(int level) {
|
||||
return level >= 0 && level <= 100;
|
||||
}
|
||||
|
||||
private void showToast(int resId) {
|
||||
|
||||
@@ -21,12 +21,12 @@ import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.TwoStatePreference;
|
||||
|
||||
import org.lineageos.device.DeviceSettings.Constants;
|
||||
import org.lineageos.device.DeviceSettings.R;
|
||||
import org.lineageos.device.DeviceSettings.preferences.CustomSeekBarPreference;
|
||||
|
||||
public class BypassChargingFragment extends PreferenceFragmentCompat {
|
||||
|
||||
private static final String KEY_BYPASS_CHARGING = "bypass_charging";
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.bypass_charging_settings, rootKey);
|
||||
@@ -35,16 +35,33 @@ public class BypassChargingFragment extends PreferenceFragmentCompat {
|
||||
BypassChargingController.getInstance(getContext());
|
||||
boolean bypassSupported = bypassController.isBypassChargingSupported();
|
||||
|
||||
TwoStatePreference bypassPreference = findPreference(KEY_BYPASS_CHARGING);
|
||||
bypassPreference.setEnabled(bypassSupported);
|
||||
if (bypassSupported) {
|
||||
bypassPreference.setChecked(bypassController.isBypassChargingEnabled());
|
||||
bypassPreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
bypassController.setBypassCharging((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
bypassPreference.setSummary(R.string.bypass_charging_unavailable);
|
||||
TwoStatePreference bypassPreference = findPreference(Constants.KEY_BYPASS_CHARGING);
|
||||
if (bypassPreference != null) {
|
||||
bypassPreference.setEnabled(bypassSupported);
|
||||
if (bypassSupported) {
|
||||
bypassPreference.setChecked(bypassController.getBypassChargingStatus() != Constants.BYPASS_OFF);
|
||||
bypassPreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
boolean enable = (boolean) newValue;
|
||||
if (enable) {
|
||||
bypassController.enableBypassCharging();
|
||||
}
|
||||
else {
|
||||
bypassController.disableBypassCharging();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
bypassPreference.setSummary(R.string.bypass_charging_unavailable);
|
||||
}
|
||||
}
|
||||
|
||||
CustomSeekBarPreference targetPreference = findPreference(Constants.KEY_BYPASS_CHARGING_TARGET);
|
||||
if (targetPreference != null) {
|
||||
targetPreference.setValue(bypassController.getBypassChargingTarget());
|
||||
targetPreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
bypassController.setBypassChargingTarget((int) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (C) 2025 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* 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.device.DeviceSettings.bypasschrg;
|
||||
|
||||
import static android.os.BatteryManager.EXTRA_LEVEL;
|
||||
import static android.os.BatteryManager.EXTRA_SCALE;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.UserHandle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import org.lineageos.device.DeviceSettings.Constants;
|
||||
import org.lineageos.device.DeviceSettings.R;
|
||||
|
||||
public class BypassChargingService extends Service {
|
||||
public static final String CHANNEL_ID = "bypass_charging_channel";
|
||||
public static final int NOTIF_ID = 1337;
|
||||
private static final String TAG = "BypassChargingService";
|
||||
|
||||
private BypassChargingController mController;
|
||||
private BroadcastReceiver mBatteryReceiver;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mController = BypassChargingController.getInstance(getApplicationContext());
|
||||
createNotificationChannel();
|
||||
startForeground(NOTIF_ID, buildNotification());
|
||||
registerBatteryReceiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
unregisterBatteryReceiver();
|
||||
stopForeground(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null; // Not a bound service
|
||||
}
|
||||
|
||||
private void registerBatteryReceiver() {
|
||||
if (mBatteryReceiver != null) return;
|
||||
mBatteryReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
int extraLevel = intent.getIntExtra(EXTRA_LEVEL, -1);
|
||||
int extraScale = intent.getIntExtra(EXTRA_SCALE, -1);
|
||||
int level = (extraLevel >= 0 && extraScale > 0) ?
|
||||
(int) ((extraLevel / (float) extraScale) * 100) : -1;
|
||||
|
||||
Log.d(TAG, "Battery level in service: " + level);
|
||||
mController.onBatteryLevelChanged(level);
|
||||
}
|
||||
};
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
registerReceiver(mBatteryReceiver, filter);
|
||||
}
|
||||
|
||||
private void unregisterBatteryReceiver() {
|
||||
if (mBatteryReceiver != null) {
|
||||
try {
|
||||
unregisterReceiver(mBatteryReceiver);
|
||||
} catch (Exception e) {}
|
||||
mBatteryReceiver = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
getString(R.string.bypass_charging_title),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
);
|
||||
channel.setDescription(getString(R.string.bypass_charging_waiting));
|
||||
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||
if (manager != null) manager.createNotificationChannel(channel);
|
||||
}
|
||||
}
|
||||
|
||||
private Notification buildNotification() {
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle(getString(R.string.bypass_charging_title))
|
||||
.setContentText(getString(R.string.bypass_charging_waiting))
|
||||
.setSmallIcon(R.drawable.ic_bypass_charging)
|
||||
.setOngoing(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
// Static method to start/stop service from anywhere
|
||||
public static void start(Context context) {
|
||||
Intent intent = new Intent(context, BypassChargingService.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundServiceAsUser(intent, UserHandle.CURRENT);
|
||||
} else {
|
||||
context.startService(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public static void stop(Context context) {
|
||||
Intent intent = new Intent(context, BypassChargingService.class);
|
||||
context.stopService(intent);
|
||||
}
|
||||
}
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package org.lineageos.device.DeviceSettings.bypasschrg;
|
||||
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
|
||||
|
||||
import org.lineageos.device.DeviceSettings.Constants;
|
||||
import org.lineageos.device.DeviceSettings.R;
|
||||
|
||||
public class BypassChargingTile extends TileService {
|
||||
@@ -35,26 +38,42 @@ public class BypassChargingTile extends TileService {
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
mEnabled = mBypassController.isBypassChargingEnabled();
|
||||
updateTileState();
|
||||
int status = mBypassController.getBypassChargingStatus();
|
||||
mEnabled = status != Constants.BYPASS_OFF;
|
||||
updateTileState(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
if (mEnabled == mBypassController.isBypassChargingEnabled()) {
|
||||
mEnabled = !mEnabled;
|
||||
updateTileState();
|
||||
mBypassController.setBypassCharging(mEnabled);
|
||||
boolean enabled = mBypassController.getBypassChargingStatus() != Constants.BYPASS_OFF;
|
||||
if (mEnabled == enabled) {
|
||||
boolean success;
|
||||
if (mEnabled) {
|
||||
success = mBypassController.disableBypassCharging() ? true : false;
|
||||
}
|
||||
else {
|
||||
success = mBypassController.enableBypassCharging() ? true : false;
|
||||
}
|
||||
if (success) {
|
||||
mEnabled = !mEnabled;
|
||||
updateTileState(mBypassController.getBypassChargingStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTileState() {
|
||||
private void updateTileState(int status) {
|
||||
Tile tile = getQsTile();
|
||||
if (tile == null) return;
|
||||
|
||||
tile.setState(mEnabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||
tile.setState(status==Constants.BYPASS_OFF ? Tile.STATE_INACTIVE : Tile.STATE_ACTIVE);
|
||||
tile.setLabel(getString(R.string.bypass_charging_title));
|
||||
tile.setContentDescription(getString(R.string.bypass_charging_summary));
|
||||
if (status==Constants.BYPASS_WAITING) {
|
||||
tile.setIcon(Icon.createWithResource(this, R.drawable.ic_bypass_waiting));
|
||||
}
|
||||
else {
|
||||
tile.setIcon(Icon.createWithResource(this, R.drawable.ic_bypass_charging));
|
||||
}
|
||||
tile.updateTile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2023 crDroid Android 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.device.settings.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.PorterDuff;
|
||||
import androidx.core.content.res.TypedArrayUtils;
|
||||
import androidx.preference.*;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.lineageos.device.DeviceSettings.R;
|
||||
import com.android.settingslib.Utils;
|
||||
|
||||
public class CustomSeekBarPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
|
||||
protected final String TAG = getClass().getName();
|
||||
private static final String SETTINGS_NS = "http://schemas.android.com/apk/res/com.android.settings";
|
||||
protected static final String ANDROIDNS = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
protected int mInterval = 1;
|
||||
protected boolean mShowSign = false;
|
||||
protected String mUnits = "";
|
||||
protected boolean mContinuousUpdates = false;
|
||||
|
||||
protected int mMinValue = 0;
|
||||
protected int mMaxValue = 100;
|
||||
protected boolean mDefaultValueExists = false;
|
||||
protected int mDefaultValue;
|
||||
protected boolean mDefaultValueTextExists = false;
|
||||
protected String mDefaultValueText;
|
||||
|
||||
protected int mValue;
|
||||
|
||||
protected TextView mValueTextView;
|
||||
protected ImageView mResetImageView;
|
||||
protected ImageView mMinusImageView;
|
||||
protected ImageView mPlusImageView;
|
||||
protected SeekBar mSeekBar;
|
||||
|
||||
protected boolean mTrackingTouch = false;
|
||||
protected int mTrackingValue;
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekBarPreference);
|
||||
try {
|
||||
mShowSign = a.getBoolean(R.styleable.CustomSeekBarPreference_showSign, mShowSign);
|
||||
String units = a.getString(R.styleable.CustomSeekBarPreference_units);
|
||||
if (units != null)
|
||||
mUnits = " " + units;
|
||||
mContinuousUpdates = a.getBoolean(R.styleable.CustomSeekBarPreference_continuousUpdates, mContinuousUpdates);
|
||||
String defaultValueText = a.getString(R.styleable.CustomSeekBarPreference_defaultValueText);
|
||||
mDefaultValueTextExists = defaultValueText != null && !defaultValueText.isEmpty();
|
||||
if (mDefaultValueTextExists) {
|
||||
mDefaultValueText = defaultValueText;
|
||||
}
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
try {
|
||||
String newInterval = attrs.getAttributeValue(SETTINGS_NS, "interval");
|
||||
if (newInterval != null)
|
||||
mInterval = Integer.parseInt(newInterval);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Invalid interval value", e);
|
||||
}
|
||||
mMinValue = attrs.getAttributeIntValue(SETTINGS_NS, "min", mMinValue);
|
||||
mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, "max", mMaxValue);
|
||||
if (mMaxValue < mMinValue)
|
||||
mMaxValue = mMinValue;
|
||||
String defaultValue = attrs.getAttributeValue(ANDROIDNS, "defaultValue");
|
||||
mDefaultValueExists = defaultValue != null && !defaultValue.isEmpty();
|
||||
if (mDefaultValueExists) {
|
||||
mDefaultValue = getLimitedValue(Integer.parseInt(defaultValue));
|
||||
mValue = mDefaultValue;
|
||||
} else {
|
||||
mValue = mMinValue;
|
||||
}
|
||||
|
||||
mSeekBar = new SeekBar(context, attrs);
|
||||
setLayoutResource(R.layout.custom_seekbar_preference);
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, TypedArrayUtils.getAttr(context,
|
||||
androidx.preference.R.attr.seekBarPreferenceStyle,
|
||||
com.android.internal.R.attr.seekBarPreferenceStyle));
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDependencyChanged(Preference dependency, boolean disableDependent) {
|
||||
super.onDependencyChanged(dependency, disableDependent);
|
||||
this.setShouldDisableView(true);
|
||||
if (mSeekBar != null)
|
||||
mSeekBar.setEnabled(!disableDependent);
|
||||
if (mResetImageView != null)
|
||||
mResetImageView.setEnabled(!disableDependent);
|
||||
if (mPlusImageView != null)
|
||||
mPlusImageView.setEnabled(!disableDependent);
|
||||
if (mMinusImageView != null)
|
||||
mMinusImageView.setEnabled(!disableDependent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
try
|
||||
{
|
||||
// move our seekbar to the new view we've been given
|
||||
ViewParent oldContainer = mSeekBar.getParent();
|
||||
ViewGroup newContainer = (ViewGroup) holder.findViewById(R.id.seekbar);
|
||||
if (oldContainer != newContainer) {
|
||||
// remove the seekbar from the old view
|
||||
if (oldContainer != null) {
|
||||
((ViewGroup) oldContainer).removeView(mSeekBar);
|
||||
}
|
||||
// remove the existing seekbar (there may not be one) and add ours
|
||||
newContainer.removeAllViews();
|
||||
newContainer.addView(mSeekBar, ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Error binding view: " + ex.toString());
|
||||
}
|
||||
|
||||
mSeekBar.setMax(getSeekValue(mMaxValue));
|
||||
mSeekBar.setProgress(getSeekValue(mValue));
|
||||
mSeekBar.setEnabled(isEnabled());
|
||||
|
||||
mValueTextView = (TextView) holder.findViewById(R.id.value);
|
||||
mResetImageView = (ImageView) holder.findViewById(R.id.reset);
|
||||
mMinusImageView = (ImageView) holder.findViewById(R.id.minus);
|
||||
mPlusImageView = (ImageView) holder.findViewById(R.id.plus);
|
||||
|
||||
updateValueViews();
|
||||
|
||||
mSeekBar.setOnSeekBarChangeListener(this);
|
||||
mResetImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Toast.makeText(getContext(), getContext().getString(R.string.custom_seekbar_default_value_to_set, getTextValue(mDefaultValue)),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
mResetImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mDefaultValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mMinusImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setValue(mValue - mInterval, true);
|
||||
}
|
||||
});
|
||||
mMinusImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mMaxValue - mMinValue > mInterval * 2 && mMaxValue + mMinValue < mValue * 2 ? Math.floorDiv(mMaxValue + mMinValue, 2) : mMinValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mPlusImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setValue(mValue + mInterval, true);
|
||||
}
|
||||
});
|
||||
mPlusImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mMaxValue - mMinValue > mInterval * 2 && mMaxValue + mMinValue > mValue * 2 ? -1 * Math.floorDiv(-1 * (mMaxValue + mMinValue), 2) : mMaxValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected int getLimitedValue(int v) {
|
||||
return v < mMinValue ? mMinValue : (v > mMaxValue ? mMaxValue : v);
|
||||
}
|
||||
|
||||
protected int getSeekValue(int v) {
|
||||
return 0 - Math.floorDiv(mMinValue - v, mInterval);
|
||||
}
|
||||
|
||||
protected String getTextValue(int v) {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && v == mDefaultValue) {
|
||||
return mDefaultValueText;
|
||||
}
|
||||
return (mShowSign && v > 0 ? "+" : "") + String.valueOf(v) + mUnits;
|
||||
}
|
||||
|
||||
protected void updateValueViews() {
|
||||
if (mValueTextView != null) {
|
||||
if (!mTrackingTouch || mContinuousUpdates) {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && mValue == mDefaultValue) {
|
||||
mValueTextView.setText(mDefaultValueText + " (" +
|
||||
getContext().getString(R.string.custom_seekbar_default_value) + ")");
|
||||
} else {
|
||||
mValueTextView.setText(getContext().getString(R.string.custom_seekbar_value, getTextValue(mValue)) +
|
||||
(mDefaultValueExists && mValue == mDefaultValue ? " (" +
|
||||
getContext().getString(R.string.custom_seekbar_default_value) + ")" : ""));
|
||||
}
|
||||
} else {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && mTrackingValue == mDefaultValue) {
|
||||
mValueTextView.setText("[" + mDefaultValueText + "]");
|
||||
} else {
|
||||
mValueTextView.setText(getContext().getString(R.string.custom_seekbar_value, "[" + getTextValue(mTrackingValue) + "]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mResetImageView != null) {
|
||||
if (!mDefaultValueExists || mValue == mDefaultValue || mTrackingTouch)
|
||||
mResetImageView.setVisibility(View.INVISIBLE);
|
||||
else
|
||||
mResetImageView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mMinusImageView != null) {
|
||||
if (mValue == mMinValue || mTrackingTouch) {
|
||||
mMinusImageView.setClickable(false);
|
||||
mMinusImageView.setColorFilter(Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorTertiary),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
mMinusImageView.setClickable(true);
|
||||
mMinusImageView.clearColorFilter();
|
||||
}
|
||||
}
|
||||
if (mPlusImageView != null) {
|
||||
if (mValue == mMaxValue || mTrackingTouch) {
|
||||
mPlusImageView.setClickable(false);
|
||||
mPlusImageView.setColorFilter(Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorTertiary),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
mPlusImageView.setClickable(true);
|
||||
mPlusImageView.clearColorFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void changeValue(int newValue) {
|
||||
// for subclasses
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
int newValue = getLimitedValue(mMinValue + (progress * mInterval));
|
||||
if (mTrackingTouch && !mContinuousUpdates) {
|
||||
mTrackingValue = newValue;
|
||||
updateValueViews();
|
||||
} else if (mValue != newValue) {
|
||||
// change rejected, revert to the previous value
|
||||
if (!callChangeListener(newValue)) {
|
||||
mSeekBar.setProgress(getSeekValue(mValue));
|
||||
return;
|
||||
}
|
||||
// change accepted, store it
|
||||
changeValue(newValue);
|
||||
persistInt(newValue);
|
||||
|
||||
mValue = newValue;
|
||||
updateValueViews();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
mTrackingValue = mValue;
|
||||
mTrackingTouch = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
mTrackingTouch = false;
|
||||
if (!mContinuousUpdates)
|
||||
onProgressChanged(mSeekBar, getSeekValue(mTrackingValue), false);
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
|
||||
if (restoreValue)
|
||||
mValue = getPersistedInt(mValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultValue(Object defaultValue) {
|
||||
if (defaultValue instanceof Integer)
|
||||
setDefaultValue((Integer) defaultValue, mSeekBar != null);
|
||||
else
|
||||
setDefaultValue(defaultValue == null ? (String) null : defaultValue.toString(), mSeekBar != null);
|
||||
}
|
||||
|
||||
public void setDefaultValue(int newValue, boolean update) {
|
||||
newValue = getLimitedValue(newValue);
|
||||
if (!mDefaultValueExists || mDefaultValue != newValue) {
|
||||
mDefaultValueExists = true;
|
||||
mDefaultValue = newValue;
|
||||
if (update)
|
||||
updateValueViews();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultValue(String newValue, boolean update) {
|
||||
if (mDefaultValueExists && (newValue == null || newValue.isEmpty())) {
|
||||
mDefaultValueExists = false;
|
||||
if (update)
|
||||
updateValueViews();
|
||||
} else if (newValue != null && !newValue.isEmpty()) {
|
||||
setDefaultValue(Integer.parseInt(newValue), update);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(int newValue) {
|
||||
mValue = getLimitedValue(newValue);
|
||||
if (mSeekBar != null) mSeekBar.setProgress(getSeekValue(mValue));
|
||||
}
|
||||
|
||||
public void setValue(int newValue, boolean update) {
|
||||
newValue = getLimitedValue(newValue);
|
||||
if (mValue != newValue) {
|
||||
if (update)
|
||||
mSeekBar.setProgress(getSeekValue(newValue));
|
||||
else
|
||||
mValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setMax(int max) {
|
||||
mMaxValue = max < mMinValue ? mMinValue : max;
|
||||
mSeekBar.setMax(mMaxValue);
|
||||
}
|
||||
|
||||
public void setMin(int min) {
|
||||
mMinValue = min > mMaxValue ? mMaxValue : min;
|
||||
mSeekBar.setMin(mMinValue);
|
||||
}
|
||||
|
||||
public void refresh(int newValue) {
|
||||
setValue(newValue, mSeekBar != null);
|
||||
}
|
||||
}
|
||||
35
device-settings/res/xml/bypass_charging_settings.xml
Normal file
35
device-settings/res/xml/bypass_charging_settings.xml
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="bypass_charging_category"
|
||||
android:title="@string/bypass_charging_category_title">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="bypass_charging"
|
||||
android:title="@string/bypass_charging_title"
|
||||
android:icon="@drawable/ic_bypass_charging"
|
||||
android:summary="@string/bypass_charging_summary"
|
||||
android:persistent="false" />
|
||||
|
||||
<org.lineageos.device.settings.preferences.CustomSeekBarPreference
|
||||
android:key="bypass_charging_target"
|
||||
android:title="@string/bypass_charging_target_title"
|
||||
android:summary="@string/bypass_charging_target_summary"
|
||||
android:icon="@drawable/ic_bypass_waiting"
|
||||
android:dependency="bypass_charging"
|
||||
android:defaultValue="0"
|
||||
android:max="100"
|
||||
settings:min="0"
|
||||
settings:interval="5"
|
||||
settings:units="%"
|
||||
settings:showSign="true" />
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="bypass_charging_info"
|
||||
android:title="@string/bypass_charging_info_title"
|
||||
android:selectable="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2023 crDroid Android 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.device.settings.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.PorterDuff;
|
||||
import androidx.core.content.res.TypedArrayUtils;
|
||||
import androidx.preference.*;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.lineageos.device.settings.R;
|
||||
import com.android.settingslib.Utils;
|
||||
|
||||
public class CustomSeekBarPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
|
||||
protected final String TAG = getClass().getName();
|
||||
private static final String SETTINGS_NS = "http://schemas.android.com/apk/res/com.android.settings";
|
||||
protected static final String ANDROIDNS = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
protected int mInterval = 1;
|
||||
protected boolean mShowSign = false;
|
||||
protected String mUnits = "";
|
||||
protected boolean mContinuousUpdates = false;
|
||||
|
||||
protected int mMinValue = 0;
|
||||
protected int mMaxValue = 100;
|
||||
protected boolean mDefaultValueExists = false;
|
||||
protected int mDefaultValue;
|
||||
protected boolean mDefaultValueTextExists = false;
|
||||
protected String mDefaultValueText;
|
||||
|
||||
protected int mValue;
|
||||
|
||||
protected TextView mValueTextView;
|
||||
protected ImageView mResetImageView;
|
||||
protected ImageView mMinusImageView;
|
||||
protected ImageView mPlusImageView;
|
||||
protected SeekBar mSeekBar;
|
||||
|
||||
protected boolean mTrackingTouch = false;
|
||||
protected int mTrackingValue;
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekBarPreference);
|
||||
try {
|
||||
mShowSign = a.getBoolean(R.styleable.CustomSeekBarPreference_showSign, mShowSign);
|
||||
String units = a.getString(R.styleable.CustomSeekBarPreference_units);
|
||||
if (units != null)
|
||||
mUnits = " " + units;
|
||||
mContinuousUpdates = a.getBoolean(R.styleable.CustomSeekBarPreference_continuousUpdates, mContinuousUpdates);
|
||||
String defaultValueText = a.getString(R.styleable.CustomSeekBarPreference_defaultValueText);
|
||||
mDefaultValueTextExists = defaultValueText != null && !defaultValueText.isEmpty();
|
||||
if (mDefaultValueTextExists) {
|
||||
mDefaultValueText = defaultValueText;
|
||||
}
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
try {
|
||||
String newInterval = attrs.getAttributeValue(SETTINGS_NS, "interval");
|
||||
if (newInterval != null)
|
||||
mInterval = Integer.parseInt(newInterval);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Invalid interval value", e);
|
||||
}
|
||||
mMinValue = attrs.getAttributeIntValue(SETTINGS_NS, "min", mMinValue);
|
||||
mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, "max", mMaxValue);
|
||||
if (mMaxValue < mMinValue)
|
||||
mMaxValue = mMinValue;
|
||||
String defaultValue = attrs.getAttributeValue(ANDROIDNS, "defaultValue");
|
||||
mDefaultValueExists = defaultValue != null && !defaultValue.isEmpty();
|
||||
if (mDefaultValueExists) {
|
||||
mDefaultValue = getLimitedValue(Integer.parseInt(defaultValue));
|
||||
mValue = mDefaultValue;
|
||||
} else {
|
||||
mValue = mMinValue;
|
||||
}
|
||||
|
||||
mSeekBar = new SeekBar(context, attrs);
|
||||
setLayoutResource(R.layout.custom_seekbar_preference);
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, TypedArrayUtils.getAttr(context,
|
||||
androidx.preference.R.attr.seekBarPreferenceStyle,
|
||||
com.android.internal.R.attr.seekBarPreferenceStyle));
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDependencyChanged(Preference dependency, boolean disableDependent) {
|
||||
super.onDependencyChanged(dependency, disableDependent);
|
||||
this.setShouldDisableView(true);
|
||||
if (mSeekBar != null)
|
||||
mSeekBar.setEnabled(!disableDependent);
|
||||
if (mResetImageView != null)
|
||||
mResetImageView.setEnabled(!disableDependent);
|
||||
if (mPlusImageView != null)
|
||||
mPlusImageView.setEnabled(!disableDependent);
|
||||
if (mMinusImageView != null)
|
||||
mMinusImageView.setEnabled(!disableDependent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
try
|
||||
{
|
||||
// move our seekbar to the new view we've been given
|
||||
ViewParent oldContainer = mSeekBar.getParent();
|
||||
ViewGroup newContainer = (ViewGroup) holder.findViewById(R.id.seekbar);
|
||||
if (oldContainer != newContainer) {
|
||||
// remove the seekbar from the old view
|
||||
if (oldContainer != null) {
|
||||
((ViewGroup) oldContainer).removeView(mSeekBar);
|
||||
}
|
||||
// remove the existing seekbar (there may not be one) and add ours
|
||||
newContainer.removeAllViews();
|
||||
newContainer.addView(mSeekBar, ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Error binding view: " + ex.toString());
|
||||
}
|
||||
|
||||
mSeekBar.setMax(getSeekValue(mMaxValue));
|
||||
mSeekBar.setProgress(getSeekValue(mValue));
|
||||
mSeekBar.setEnabled(isEnabled());
|
||||
|
||||
mValueTextView = (TextView) holder.findViewById(R.id.value);
|
||||
mResetImageView = (ImageView) holder.findViewById(R.id.reset);
|
||||
mMinusImageView = (ImageView) holder.findViewById(R.id.minus);
|
||||
mPlusImageView = (ImageView) holder.findViewById(R.id.plus);
|
||||
|
||||
updateValueViews();
|
||||
|
||||
mSeekBar.setOnSeekBarChangeListener(this);
|
||||
mResetImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Toast.makeText(getContext(), getContext().getString(R.string.custom_seekbar_default_value_to_set, getTextValue(mDefaultValue)),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
mResetImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mDefaultValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mMinusImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setValue(mValue - mInterval, true);
|
||||
}
|
||||
});
|
||||
mMinusImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mMaxValue - mMinValue > mInterval * 2 && mMaxValue + mMinValue < mValue * 2 ? Math.floorDiv(mMaxValue + mMinValue, 2) : mMinValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mPlusImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setValue(mValue + mInterval, true);
|
||||
}
|
||||
});
|
||||
mPlusImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mMaxValue - mMinValue > mInterval * 2 && mMaxValue + mMinValue > mValue * 2 ? -1 * Math.floorDiv(-1 * (mMaxValue + mMinValue), 2) : mMaxValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected int getLimitedValue(int v) {
|
||||
return v < mMinValue ? mMinValue : (v > mMaxValue ? mMaxValue : v);
|
||||
}
|
||||
|
||||
protected int getSeekValue(int v) {
|
||||
return 0 - Math.floorDiv(mMinValue - v, mInterval);
|
||||
}
|
||||
|
||||
protected String getTextValue(int v) {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && v == mDefaultValue) {
|
||||
return mDefaultValueText;
|
||||
}
|
||||
return (mShowSign && v > 0 ? "+" : "") + String.valueOf(v) + mUnits;
|
||||
}
|
||||
|
||||
protected void updateValueViews() {
|
||||
if (mValueTextView != null) {
|
||||
if (!mTrackingTouch || mContinuousUpdates) {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && mValue == mDefaultValue) {
|
||||
mValueTextView.setText(mDefaultValueText + " (" +
|
||||
getContext().getString(R.string.custom_seekbar_default_value) + ")");
|
||||
} else {
|
||||
mValueTextView.setText(getContext().getString(R.string.custom_seekbar_value, getTextValue(mValue)) +
|
||||
(mDefaultValueExists && mValue == mDefaultValue ? " (" +
|
||||
getContext().getString(R.string.custom_seekbar_default_value) + ")" : ""));
|
||||
}
|
||||
} else {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && mTrackingValue == mDefaultValue) {
|
||||
mValueTextView.setText("[" + mDefaultValueText + "]");
|
||||
} else {
|
||||
mValueTextView.setText(getContext().getString(R.string.custom_seekbar_value, "[" + getTextValue(mTrackingValue) + "]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mResetImageView != null) {
|
||||
if (!mDefaultValueExists || mValue == mDefaultValue || mTrackingTouch)
|
||||
mResetImageView.setVisibility(View.INVISIBLE);
|
||||
else
|
||||
mResetImageView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mMinusImageView != null) {
|
||||
if (mValue == mMinValue || mTrackingTouch) {
|
||||
mMinusImageView.setClickable(false);
|
||||
mMinusImageView.setColorFilter(Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorTertiary),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
mMinusImageView.setClickable(true);
|
||||
mMinusImageView.clearColorFilter();
|
||||
}
|
||||
}
|
||||
if (mPlusImageView != null) {
|
||||
if (mValue == mMaxValue || mTrackingTouch) {
|
||||
mPlusImageView.setClickable(false);
|
||||
mPlusImageView.setColorFilter(Utils.getColorAttrDefaultColor(getContext(), android.R.attr.textColorTertiary),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else {
|
||||
mPlusImageView.setClickable(true);
|
||||
mPlusImageView.clearColorFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void changeValue(int newValue) {
|
||||
// for subclasses
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
int newValue = getLimitedValue(mMinValue + (progress * mInterval));
|
||||
if (mTrackingTouch && !mContinuousUpdates) {
|
||||
mTrackingValue = newValue;
|
||||
updateValueViews();
|
||||
} else if (mValue != newValue) {
|
||||
// change rejected, revert to the previous value
|
||||
if (!callChangeListener(newValue)) {
|
||||
mSeekBar.setProgress(getSeekValue(mValue));
|
||||
return;
|
||||
}
|
||||
// change accepted, store it
|
||||
changeValue(newValue);
|
||||
persistInt(newValue);
|
||||
|
||||
mValue = newValue;
|
||||
updateValueViews();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
mTrackingValue = mValue;
|
||||
mTrackingTouch = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
mTrackingTouch = false;
|
||||
if (!mContinuousUpdates)
|
||||
onProgressChanged(mSeekBar, getSeekValue(mTrackingValue), false);
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
|
||||
if (restoreValue)
|
||||
mValue = getPersistedInt(mValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultValue(Object defaultValue) {
|
||||
if (defaultValue instanceof Integer)
|
||||
setDefaultValue((Integer) defaultValue, mSeekBar != null);
|
||||
else
|
||||
setDefaultValue(defaultValue == null ? (String) null : defaultValue.toString(), mSeekBar != null);
|
||||
}
|
||||
|
||||
public void setDefaultValue(int newValue, boolean update) {
|
||||
newValue = getLimitedValue(newValue);
|
||||
if (!mDefaultValueExists || mDefaultValue != newValue) {
|
||||
mDefaultValueExists = true;
|
||||
mDefaultValue = newValue;
|
||||
if (update)
|
||||
updateValueViews();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultValue(String newValue, boolean update) {
|
||||
if (mDefaultValueExists && (newValue == null || newValue.isEmpty())) {
|
||||
mDefaultValueExists = false;
|
||||
if (update)
|
||||
updateValueViews();
|
||||
} else if (newValue != null && !newValue.isEmpty()) {
|
||||
setDefaultValue(Integer.parseInt(newValue), update);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(int newValue) {
|
||||
mValue = getLimitedValue(newValue);
|
||||
if (mSeekBar != null) mSeekBar.setProgress(getSeekValue(mValue));
|
||||
}
|
||||
|
||||
public void setValue(int newValue, boolean update) {
|
||||
newValue = getLimitedValue(newValue);
|
||||
if (mValue != newValue) {
|
||||
if (update)
|
||||
mSeekBar.setProgress(getSeekValue(newValue));
|
||||
else
|
||||
mValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setMax(int max) {
|
||||
mMaxValue = max < mMinValue ? mMinValue : max;
|
||||
mSeekBar.setMax(mMaxValue);
|
||||
}
|
||||
|
||||
public void setMin(int min) {
|
||||
mMinValue = min > mMaxValue ? mMaxValue : min;
|
||||
mSeekBar.setMin(mMinValue);
|
||||
}
|
||||
|
||||
public void refresh(int newValue) {
|
||||
setValue(newValue, mSeekBar != null);
|
||||
}
|
||||
}
|
||||
70
device.mk
Normal file
70
device.mk
Normal file
@@ -0,0 +1,70 @@
|
||||
#
|
||||
# Copyright (C) 2021-2025 The LineageOS Project
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
# AAPT
|
||||
PRODUCT_AAPT_CONFIG := normal
|
||||
PRODUCT_AAPT_PREF_CONFIG := xxxhdpi
|
||||
|
||||
# Audio
|
||||
PRODUCT_COPY_FILES += \
|
||||
$(LOCAL_PATH)/configs/audio/audio_policy_volumes.xml:$(TARGET_COPY_OUT_VENDOR)/etc/audio_policy_volumes.xml \
|
||||
$(LOCAL_PATH)/configs/audio/default_volume_tables.xml:$(TARGET_COPY_OUT_VENDOR)/etc/default_volume_tables.xml
|
||||
|
||||
# Boot animation
|
||||
TARGET_SCREEN_HEIGHT := 3168
|
||||
TARGET_SCREEN_WIDTH := 1440
|
||||
|
||||
# Display
|
||||
PRODUCT_COPY_FILES += \
|
||||
$(LOCAL_PATH)/configs/display/displayconfig.xml:$(TARGET_COPY_OUT_VENDOR)/etc/displayconfig/display_id_4630946756802996883.xml
|
||||
|
||||
# LiveDisplay
|
||||
$(call soong_config_set,OPLUS_LINEAGE_LIVEDISPLAY_HAL,ENABLE_AF,false)
|
||||
$(call soong_config_set,OPLUS_LINEAGE_LIVEDISPLAY_HAL,ENABLE_SE,false)
|
||||
|
||||
|
||||
# Overlays
|
||||
DEVICE_PACKAGE_OVERLAYS += \
|
||||
$(LOCAL_PATH)/overlay-lineage
|
||||
|
||||
PRODUCT_PACKAGES += \
|
||||
OPlusFrameworksResTarget \
|
||||
OPlusSettingsProviderResTarget \
|
||||
OPlusSettingsResTarget \
|
||||
OPlusSystemUIResTarget
|
||||
|
||||
# Power
|
||||
$(call soong_config_set,qtipower,mode_ext_lib,power-ext-oplus)
|
||||
|
||||
# PowerShare
|
||||
PRODUCT_PACKAGES += \
|
||||
vendor.lineage.powershare-service.oplus
|
||||
|
||||
# Regional properties
|
||||
PRODUCT_COPY_FILES += \
|
||||
$(LOCAL_PATH)/recovery/root/vendor/odm/etc/23821/build.default.prop:$(TARGET_COPY_OUT_ODM)/etc/23821/build.default.prop \
|
||||
$(LOCAL_PATH)/recovery/root/vendor/odm/etc/23893/build.EU.prop:$(TARGET_COPY_OUT_ODM)/etc/23893/build.EU.prop \
|
||||
$(LOCAL_PATH)/recovery/root/vendor/odm/etc/23893/build.IN.prop:$(TARGET_COPY_OUT_ODM)/etc/23893/build.IN.prop \
|
||||
$(LOCAL_PATH)/recovery/root/vendor/odm/etc/23893/build.NA.prop:$(TARGET_COPY_OUT_ODM)/etc/23893/build.NA.prop \
|
||||
$(LOCAL_PATH)/recovery/root/vendor/odm/etc/23893/build.default.prop:$(TARGET_COPY_OUT_ODM)/etc/23893/build.default.prop
|
||||
|
||||
# Soong namespaces
|
||||
PRODUCT_SOONG_NAMESPACES += \
|
||||
$(LOCAL_PATH)
|
||||
|
||||
# Touch features
|
||||
$(call soong_config_set,OPLUS_LINEAGE_TOUCH_HAL,ENABLE_GM,true)
|
||||
$(call soong_config_set,OPLUS_LINEAGE_TOUCH_HAL,ENABLE_HTPR,false)
|
||||
|
||||
# Vibrator
|
||||
$(call soong_config_set,OPLUS_LINEAGE_VIBRATOR_HAL,USE_EFFECT_STREAM,true)
|
||||
$(call soong_config_set,OPLUS_LINEAGE_VIBRATOR_HAL,INCLUDE_DIR,$(LOCAL_PATH)/vibrator/include)
|
||||
|
||||
# Inherit from the common OEM chipset makefile.
|
||||
$(call inherit-product, device/oneplus/sm8750-common/common.mk)
|
||||
|
||||
# Inherit from the proprietary files makefile.
|
||||
$(call inherit-product, vendor/oneplus/dodge/dodge-vendor.mk)
|
||||
@@ -16,4 +16,5 @@
|
||||
<bool name="config_proximityCheckOnWake">true</bool>
|
||||
<bool name="config_proximityCheckOnWakeEnabledByDefault">true</bool>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
8
sepolicy/vendor/system_app.te
vendored
Normal file
8
sepolicy/vendor/system_app.te
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Bypass Charging
|
||||
allow system_app vendor_sysfs_usb_supply:file w_file_perms;
|
||||
|
||||
# Gamebar
|
||||
allow system_app { proc_stat vendor_sysfs_kgsl vendor_sysfs_kgsl_gpuclk }:file r_file_perms;
|
||||
|
||||
# OnePulse PWM
|
||||
rw_dir_file(system_app, vendor_sysfs_graphics);
|
||||
Reference in New Issue
Block a user