Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f48fe7af8 | ||
|
|
69cec4a226 | ||
|
|
e3709c3a5f | ||
|
|
36fc00c6f7 | ||
|
|
691ae80522 | ||
|
|
7f7b28b7ec | ||
|
|
698b0793e0 | ||
|
|
ba3f515548 | ||
|
|
61f4eca83c | ||
|
|
0daafe0ad3 | ||
|
|
176d45a401 | ||
|
|
7cca5eb75f | ||
|
|
677534ab57 | ||
|
|
39eaf77d3b | ||
|
|
32010fe8a6 | ||
|
|
1c92a3aa64 | ||
|
|
580d92d48e | ||
|
|
063ebd6340 | ||
|
|
d927eafa9d | ||
|
|
78c36e6e7a | ||
|
|
27f7258f40 | ||
|
|
79073ee5fb | ||
|
|
9517a2b2f4 | ||
|
|
902d9b8b8c | ||
|
|
2ad26e321b | ||
|
|
4b55992686 | ||
|
|
9ee13c15a6 | ||
|
|
895a9d4a5f | ||
|
|
b9551ec7b2 | ||
|
|
9839b86f36 | ||
|
|
3728b1aea2 | ||
|
|
5e170e74b3 | ||
|
|
d7b1c2071f | ||
|
|
d1362347cd | ||
|
|
e86c2261b6 | ||
|
|
740b46504e | ||
|
|
3fcf8d108e | ||
|
|
bccfa62cd8 | ||
|
|
9cbeaf7f9a | ||
|
|
a8876fd7e7 | ||
|
|
bfa2e40a46 | ||
|
|
c997706fe1 | ||
|
|
7bca1e3cbd | ||
|
|
eae47e3ba2 | ||
|
|
3b12dc0491 | ||
|
|
b9141a9f34 | ||
|
|
d5b0780c14 | ||
|
|
51e6b220d3 | ||
|
|
1990a776fb | ||
|
|
3b20b70f4d | ||
|
|
3e49ec97fe | ||
|
|
028c7ee1bd | ||
|
|
631486dfff | ||
|
|
f8d7219744 | ||
|
|
d852fdcb29 | ||
|
|
1e298d14a6 | ||
|
|
cfba3aaf95 | ||
|
|
8f96a9bf71 | ||
|
|
a54e5c546c | ||
|
|
35b87f7c6d | ||
|
|
0684cf355a | ||
|
|
ffd1ddfbf9 | ||
|
|
e005ad2aa1 | ||
|
|
a8c5e9bdd5 | ||
|
|
5a2b337dbc | ||
|
|
8e19cbb0a5 | ||
|
|
c5ea61e49f | ||
|
|
be8403dea6 | ||
|
|
bccca041aa | ||
|
|
4f22c6fe43 | ||
|
|
025b4df531 | ||
|
|
195e21ae45 | ||
|
|
57f7fb9151 | ||
|
|
e5405be694 | ||
|
|
e455368c95 | ||
|
|
0a8fe4c93c | ||
|
|
0b3cef643a | ||
|
|
a31601d296 | ||
|
|
0de72b411d | ||
|
|
d94aacfeb1 | ||
|
|
98dd114623 |
@@ -6,11 +6,6 @@ soong_namespace {
|
||||
],
|
||||
}
|
||||
|
||||
cc_library_shared {
|
||||
name: "libprotobuf-cpp-lite-3.9.1",
|
||||
shared_libs: ["libprotobuf-cpp-full-3.9.1-vendorcompat"],
|
||||
vendor: true,
|
||||
}
|
||||
|
||||
install_symlink {
|
||||
name: "firmware_wlan_mac.bin_symlink",
|
||||
|
||||
@@ -45,6 +45,11 @@ TARGET_2ND_CPU_ABI2 := armeabi
|
||||
TARGET_2ND_CPU_VARIANT := cortex-a76
|
||||
TARGET_2ND_CPU_VARIANT_RUNTIME := cortex-a76
|
||||
|
||||
# ART
|
||||
WITH_DEXPREOPT := true
|
||||
DEX_PREOPT_DEFAULT := generate-vdex-and-image
|
||||
WITH_DEXPREOPT_DEBUG_INFO := false
|
||||
|
||||
# Audio
|
||||
AUDIO_FEATURE_ENABLED_EXTN_FORMATS := true
|
||||
AUDIO_FEATURE_ENABLED_HDMI_SPK := true
|
||||
@@ -96,7 +101,6 @@ BOARD_HAVE_QCOM_FM := true
|
||||
DEVICE_FRAMEWORK_COMPATIBILITY_MATRIX_FILE := \
|
||||
hardware/qcom-caf/common/vendor_framework_compatibility_matrix.xml \
|
||||
hardware/qcom-caf/common/vendor_framework_compatibility_matrix_legacy.xml \
|
||||
vendor/lineage/config/device_framework_matrix.xml \
|
||||
$(COMMON_PATH)/framework_compatibility_matrix.xml
|
||||
|
||||
DEVICE_MANIFEST_FILE := \
|
||||
@@ -108,6 +112,9 @@ DEVICE_MATRIX_FILE := \
|
||||
ODM_MANIFEST_SKUS := nfc
|
||||
ODM_MANIFEST_NFC_FILES := $(COMMON_PATH)/manifest_nfc.xml
|
||||
|
||||
# HWUI
|
||||
HWUI_COMPILE_FOR_PERF := true
|
||||
|
||||
# Kernel
|
||||
BOARD_KERNEL_BASE := 0x00000000
|
||||
BOARD_KERNEL_IMAGE_NAME := Image.gz
|
||||
|
||||
27
common.mk
27
common.mk
@@ -22,6 +22,9 @@ $(call inherit-product, hardware/qcom-caf/common/common.mk)
|
||||
# UDFPS
|
||||
$(call soong_config_set,surfaceflinger,udfps_lib,//$(LOCAL_PATH):libudfps_extension.realme_sm7125)
|
||||
|
||||
# speaker layout channel mask
|
||||
$(call soong_config_set_bool,android_hardware_audio,skip_speaker_layout_channel_mask_field,true)
|
||||
|
||||
# Partitions
|
||||
PRODUCT_USE_DYNAMIC_PARTITIONS := true
|
||||
PRODUCT_BOARD_PLATFORM := atoll
|
||||
@@ -99,10 +102,6 @@ PRODUCT_COPY_FILES += \
|
||||
#CertifiedProps
|
||||
$(call inherit-product-if-exists, vendor/certprops/Android.mk)
|
||||
|
||||
# Core Packages
|
||||
PRODUCT_PACKAGES += \
|
||||
Parts
|
||||
|
||||
# Config Store
|
||||
PRODUCT_PACKAGES += \
|
||||
disable_configstore \
|
||||
@@ -231,9 +230,11 @@ PRODUCT_PACKAGES += \
|
||||
init.qcom.usb.rc \
|
||||
init.sm7125.rc
|
||||
|
||||
# Recovery init script
|
||||
# Recovery
|
||||
PRODUCT_PACKAGES += \
|
||||
init.recovery.qcom.sh
|
||||
init.recovery.qcom.sh \
|
||||
init.recovery.qcom.rc \
|
||||
init.recovery.usb.rc
|
||||
|
||||
# Vendor shell scripts
|
||||
PRODUCT_PACKAGES += \
|
||||
@@ -274,7 +275,7 @@ $(call inherit-product-if-exists, vendor/lawnchair/lawnchair.mk)
|
||||
PRODUCT_PACKAGES += \
|
||||
vendor.lineage.livedisplay-service.sdm
|
||||
|
||||
$(call soong_config_set,livedisplay_sdm,enable_dm,false)
|
||||
$(call soong_config_set_bool,livedisplay_sdm,enable_dm,false)
|
||||
|
||||
# Media
|
||||
PRODUCT_PACKAGES += \
|
||||
@@ -360,8 +361,8 @@ PRODUCT_DEXPREOPT_SPEED_APPS += \
|
||||
#Protobuf
|
||||
PRODUCT_PACKAGES += \
|
||||
libprotobuf-cpp-full-3.9.1-vendorcompat \
|
||||
libprotobuf-cpp-lite-3.9.1
|
||||
|
||||
libprotobuf-cpp-lite-3.9.1-vendorcompat
|
||||
|
||||
# QTI FWK Detect
|
||||
PRODUCT_PACKAGES += \
|
||||
libqti_vndfwk_detect.vendor \
|
||||
@@ -537,7 +538,6 @@ PRODUCT_PACKAGES += \
|
||||
android.frameworks.cameraservice.service@2.0.vendor \
|
||||
android.frameworks.cameraservice.service@2.1.vendor \
|
||||
android.frameworks.displayservice@1.0.vendor \
|
||||
android.frameworks.schedulerservice@1.0.vendor \
|
||||
android.frameworks.stats@1.0.vendor \
|
||||
android.hardware.atrace@1.0.vendor \
|
||||
android.frameworks.sensorservice@1.0.vendor \
|
||||
@@ -553,8 +553,6 @@ PRODUCT_PACKAGES += \
|
||||
android.hardware.audio@5.0.vendor \
|
||||
android.hardware.audio@6.0.vendor \
|
||||
android.hardware.authsecret@1.0.vendor \
|
||||
android.hardware.automotive.audiocontrol@1.0.vendor \
|
||||
android.hardware.automotive.audiocontrol@2.0.vendor \
|
||||
android.hardware.automotive.can@1.0.vendor \
|
||||
android.hardware.automotive.evs@1.0.vendor \
|
||||
android.hardware.automotive.evs@1.1.vendor \
|
||||
@@ -654,11 +652,6 @@ PRODUCT_PACKAGES += \
|
||||
android.hardware.usb@1.0.vendor \
|
||||
android.hardware.usb@1.1.vendor \
|
||||
android.hardware.usb@1.2.vendor \
|
||||
android.hardware.vibrator@1.0.vendor \
|
||||
android.hardware.vibrator@1.1.vendor \
|
||||
android.hardware.vibrator@1.2.vendor \
|
||||
android.hardware.vibrator@1.3.vendor \
|
||||
android.hardware.vr@1.0.vendor \
|
||||
android.hardware.weaver@1.0.vendor \
|
||||
android.hardware.wifi.hostapd@1.0.vendor \
|
||||
android.hardware.wifi.hostapd@1.1.vendor \
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
<?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.
|
||||
Copyright (C) 2022-2024 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
|
||||
autodetected from the Configuration. -->
|
||||
@@ -21,9 +13,6 @@
|
||||
<!-- The restoring is handled by modem if it is true-->
|
||||
<bool name="skip_restoring_network_selection">true</bool>
|
||||
|
||||
<!-- Set to true to add links to Cell Broadcast app from Settings and MMS app. -->
|
||||
<bool name="config_cellBroadcastAppLinks">true</bool>
|
||||
|
||||
<!-- M user agent string -->
|
||||
<string name="config_mms_user_agent">Android-Mms/2.0</string>
|
||||
|
||||
@@ -161,6 +150,9 @@
|
||||
Doze dreams will run whenever the power manager is in a dozing state. -->
|
||||
<string name="config_dozeComponent">com.android.systemui/com.android.systemui.doze.DozeService</string>
|
||||
|
||||
<!-- Doze: should the TYPE_PICK_UP_GESTURE sensor be used as a pulse signal. -->
|
||||
<bool name="config_dozePulsePickup">true</bool>
|
||||
|
||||
<!-- If true, the doze component is not started until after the screen has been
|
||||
turned off and the screen off animation has been performed. -->
|
||||
<bool name="config_dozeAfterScreenOffByDefault">true</bool>
|
||||
@@ -218,10 +210,6 @@
|
||||
on the headphone/microphone jack. When false use the older uevent framework. -->
|
||||
<bool name="config_useDevInputEventForAudioJack">true</bool>
|
||||
|
||||
<!-- Boolean indicating whether the HWC setColorTransform function can be performed efficiently
|
||||
in hardware. -->
|
||||
<bool name="config_setColorTransformAccelerated">true</bool>
|
||||
|
||||
<!-- Flag indicating whether the we should enable the automatic brightness in Settings.
|
||||
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
|
||||
<bool name="config_automatic_brightness_available">true</bool>
|
||||
@@ -366,11 +354,6 @@
|
||||
Equivalent to 67/255 (default for this device) -->
|
||||
<integer name="config_screenBrightnessSettingDefault">45</integer>
|
||||
|
||||
<!-- Vibrator pattern for a very short but reliable vibration for soft keyboard tap -->
|
||||
<integer-array name="config_keyboardTapVibePattern">
|
||||
<item>40</item>
|
||||
</integer-array>
|
||||
|
||||
<!-- Vibrator pattern for feedback about a long screen/key press -->
|
||||
<integer-array name="config_longPressVibePattern">
|
||||
<item>0</item>
|
||||
@@ -434,22 +417,58 @@
|
||||
|
||||
<!-- Default list of files pinned by the Pinner Service -->
|
||||
<string-array translatable="false" name="config_defaultPinnerServiceFiles">
|
||||
<item>"/apex/com.android.art/javalib/core-libart.jar"</item>
|
||||
<item>"/apex/com.android.art/javalib/core-oj.jar"</item>
|
||||
<item>"/apex/com.android.art/javalib/core-libart.jar"</item>
|
||||
<item>"/system_ext/priv-app/SystemUI/SystemUI.apk"</item>
|
||||
<item>"/system/bin/surfaceflinger"</item>
|
||||
<item>"/system/framework/boot-framework.vdex"</item>
|
||||
<item>"/system/framework/ext.jar"</item>
|
||||
<item>"/system/framework/framework-res.apk"</item>
|
||||
<item>"/system/framework/framework.jar"</item>
|
||||
<item>"/system/framework/services.jar"</item>
|
||||
<item>"/system/framework/ext.jar"</item>
|
||||
<item>"/system/framework/telephony-common.jar"</item>
|
||||
<item>"/system/lib/libEGL.so"</item>
|
||||
<item>"/system/lib/libGLESv1_CM.so"</item>
|
||||
<item>"/system/lib/libGLESv2.so"</item>
|
||||
<item>"/system/lib/libGLESv3.so"</item>
|
||||
<item>"/system/lib/libgui.so"</item>
|
||||
<item>"/system/lib/libhwui.so"</item>
|
||||
<item>"/system/lib/libui.so"</item>
|
||||
<item>"/system/lib/libvulkan.so"</item>
|
||||
<item>"/system/lib64/libEGL.so"</item>
|
||||
<item>"/system/lib64/libGLESv1_CM.so"</item>
|
||||
<item>"/system/lib64/libGLESv2.so"</item>
|
||||
<item>"/system/lib64/libGLESv3.so"</item>
|
||||
<item>"/system/lib64/libgui.so"</item>
|
||||
<item>"/system/lib64/libhwui.so"</item>
|
||||
<item>"/system_ext/priv-app/SystemUI/SystemUI.apk"</item>
|
||||
<item>"/system/lib64/libui.so"</item>
|
||||
<item>"/system/lib64/libvulkan.so"</item>
|
||||
<item>"/vendor/lib/egl/eglSubDriverAndroid.so"</item>
|
||||
<item>"/vendor/lib/egl/libEGL_adreno.so"</item>
|
||||
<item>"/vendor/lib/egl/libGLESv1_CM_adreno.so"</item>
|
||||
<item>"/vendor/lib/egl/libGLESv2_adreno.so"</item>
|
||||
<item>"/vendor/lib/hw/vulkan.adreno.so"</item>
|
||||
<item>"/vendor/lib/libCB.so"</item>
|
||||
<item>"/vendor/lib/libOpenCL.so"</item>
|
||||
<item>"/vendor/lib/libadreno_utils.so"</item>
|
||||
<item>"/vendor/lib/libgsl.so"</item>
|
||||
<item>"/vendor/lib/libllvm-glnext.so"</item>
|
||||
<item>"/vendor/lib/libllvm-qcom.so"</item>
|
||||
<item>"/vendor/lib64/egl/eglSubDriverAndroid.so"</item>
|
||||
<item>"/vendor/lib64/egl/libEGL_adreno.so"</item>
|
||||
<item>"/vendor/lib64/egl/libGLESv1_CM_adreno.so"</item>
|
||||
<item>"/vendor/lib64/egl/libGLESv2_adreno.so"</item>
|
||||
<item>"/vendor/lib64/hw/vulkan.adreno.so"</item>
|
||||
<item>"/vendor/lib64/libCB.so"</item>
|
||||
<item>"/vendor/lib64/libOpenCL.so"</item>
|
||||
<item>"/vendor/lib64/libadreno_utils.so"</item>
|
||||
<item>"/vendor/lib64/libgsl.so"</item>
|
||||
<item>"/vendor/lib64/libllvm-qgl.so"</item>
|
||||
<item>"/vendor/lib64/libllvm-glnext.so"</item>
|
||||
<item>"/vendor/lib64/libllvm-qcom.so"</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Should the pinner service pin the Home application? -->
|
||||
<bool name="config_pinnerHomeApp">true</bool>
|
||||
<!-- Bytes that the PinnerService will pin for Home app -->
|
||||
<integer name="config_pinnerHomePinBytes">6291456</integer>
|
||||
|
||||
<!-- List of files pinned by the Pinner Service with the JIT Zygote boot image b/119800099 -->
|
||||
<string-array translatable="false" name="config_jitzygoteBootImagePinnerServiceFiles">
|
||||
@@ -502,9 +521,6 @@
|
||||
available on some devices. -->
|
||||
<bool name="config_enableHapticTextHandle">true</bool>
|
||||
|
||||
<!-- Enable Zram writeback feature to allow unused pages in zram be written to flash. -->
|
||||
<bool name="config_zramWriteback">true</bool>
|
||||
|
||||
<!-- Whether to post reset runnable for all clients. Needed for some older
|
||||
vendor fingerprint HAL implementations. -->
|
||||
<bool name="config_fingerprintPostResetRunnableForAllClients">true</bool>
|
||||
@@ -565,6 +581,8 @@
|
||||
manager will disable alpha trasformation in animations where not
|
||||
strictly needed. -->
|
||||
<bool name="config_sf_limitedAlpha">true</bool>
|
||||
<!-- Whether the new Auto Selection Network UI should be shown -->
|
||||
<bool name="config_enableNewAutoSelectNetworkUI">true</bool>
|
||||
|
||||
<!-- Package name of a telephony-related system app, such as an IMS service.
|
||||
Exempted from privacy indicators. -->
|
||||
@@ -589,9 +607,7 @@
|
||||
|
||||
<!-- Whether we use large screen shade header which takes only one row compared to QS header -->
|
||||
<bool name="config_use_large_screen_shade_header">true</bool>
|
||||
|
||||
<!-- Boost Framework -->
|
||||
<bool name="config_supportsBoostFramework">true</bool>
|
||||
|
||||
|
||||
<!-- Whether WiFi display is supported by this device.
|
||||
There are many prerequisites for this feature to work correctly.
|
||||
@@ -606,4 +622,8 @@
|
||||
* The device must be provisioned with HDCP keys (for protected content).
|
||||
-->
|
||||
<bool name="config_enableWifiDisplay">true</bool>
|
||||
</resources>
|
||||
|
||||
<!-- Whether WM DisplayContent supports high performance transitions
|
||||
(lower-end devices may want to disable) -->
|
||||
<bool name="config_deviceSupportsHighPerfTransitions">false</bool>
|
||||
</resources>
|
||||
@@ -57,4 +57,7 @@
|
||||
<!-- Location on the screen of the center of the physical power button. -->
|
||||
<dimen name="physical_power_button_center_screen_location_y">912px</dimen>
|
||||
|
||||
<!-- Blur radius behind Notification Shade -->
|
||||
<dimen name="max_shade_window_blur_radius">17dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023 Paranoid Android
|
||||
<!-- Copyright (C) 2018 The Android Open Source 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
|
||||
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,
|
||||
@@ -14,8 +13,7 @@
|
||||
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"/>
|
||||
</privapp-permissions>
|
||||
</permissions>
|
||||
<resources>
|
||||
<integer name="max_depth_blur_radius">11</integer>
|
||||
<dimen name="max_depth_blur_radius_enhanced">15dp</dimen>
|
||||
</resources>
|
||||
@@ -1,43 +0,0 @@
|
||||
//
|
||||
// Copyright (C) 2017-2020 The LineageOS Project
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
android_app {
|
||||
name: "Parts",
|
||||
defaults: [
|
||||
"SettingsLibDefaults",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/**/*.kt",
|
||||
"src/**/*.java"
|
||||
],
|
||||
|
||||
certificate: "platform",
|
||||
resource_dirs: ["res"],
|
||||
platform_apis: true,
|
||||
system_ext_specific: true,
|
||||
privileged: true,
|
||||
|
||||
static_libs: [
|
||||
"androidx.core_core",
|
||||
"org.lineageos.settings.resources"
|
||||
],
|
||||
|
||||
optimize: {
|
||||
proguard_flags_files: ["proguard.flags"],
|
||||
},
|
||||
|
||||
required: [
|
||||
"privapp_whitelist_org.lineageos.settings.xml",
|
||||
],
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "privapp_whitelist_org.lineageos.settings.xml",
|
||||
src: "permissions/privapp_whitelist_org.lineageos.settings.xml",
|
||||
sub_dir: "permissions",
|
||||
system_ext_specific: true,
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015-2016 The CyanogenMod Project
|
||||
2017-2018 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="org.lineageos.settings"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
android:sharedUserId="android.uid.system">
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.GET_TASKS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.BATTERY_STATS" />
|
||||
<uses-permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="24"
|
||||
android:targetSdkVersion="30"/>
|
||||
|
||||
<application
|
||||
android:label="@string/app_title"
|
||||
android:persistent="true"
|
||||
android:defaultToDeviceProtectedStorage="true"
|
||||
android:directBootAware="true"
|
||||
android:theme="@style/Theme.SubSettingsBase">
|
||||
|
||||
<receiver
|
||||
android:name=".BootCompletedReceiver"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<provider
|
||||
android:name="androidx.startup.InitializationProvider"
|
||||
android:authorities="${applicationId}.androidx-startup"
|
||||
tools:replace="android:authorities"/>
|
||||
|
||||
<receiver
|
||||
android:name=".Startup"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- TileHandler activity -->
|
||||
<activity
|
||||
android:name=".TileHandlerActivity"
|
||||
android:exported="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@android:style/Theme.NoDisplay">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Charging Bypass Activity -->
|
||||
<activity
|
||||
android:name=".charge.ChargeActivity"
|
||||
android:label="@string/charge_bypass_title"
|
||||
android:exported="true">
|
||||
<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/charge_bypass_summary" />
|
||||
</activity>
|
||||
|
||||
<!-- Charging Bypass Monitoring Service -->
|
||||
<service
|
||||
android:name=".charge.ChargeBatteryMonitorService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="specialUse">
|
||||
<property
|
||||
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
||||
android:value="battery_optimization" />
|
||||
</service>
|
||||
|
||||
<!-- Charging Bypass Boot Receiver -->
|
||||
<receiver
|
||||
android:name=".charge.ChargeReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
<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>
|
||||
|
||||
<!-- Charging Bypass Quick Settings Tile -->
|
||||
<service
|
||||
android:name=".charge.ChargeQSTile"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic_charge_bypass"
|
||||
android:label="@string/charge_bypass_qs_tile_label"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.service.quicksettings.ACTIVE_TILE"
|
||||
android:value="false" />
|
||||
</service>
|
||||
|
||||
<!-- Charging information tile service -->
|
||||
<service
|
||||
android:name=".charginginfo.ChargingInfoTileService"
|
||||
android:icon="@drawable/ic_charging_speed"
|
||||
android:label="@string/charging_tile_label"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE"/>
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.service.quicksettings.TOGGLEABLE_TILE"
|
||||
android:value="false" />
|
||||
</service>
|
||||
|
||||
<!-- GameBar Overlay -->
|
||||
<activity
|
||||
android:name=".gamebar.GameBarSettingsActivity"
|
||||
android:label="@string/game_bar_title"
|
||||
android:theme="@style/Theme.SubSettingsBase"
|
||||
android:exported="true">
|
||||
<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.apps" />
|
||||
<meta-data
|
||||
android:name="com.android.settings.summary"
|
||||
android:resource="@string/game_bar_summary" />
|
||||
</activity>
|
||||
|
||||
<!-- GameBar AppSelector -->
|
||||
<activity android:name=".gamebar.GameBarAppSelectorActivity" />
|
||||
<activity android:name=".gamebar.GameBarAppRemoverActivity" />
|
||||
|
||||
<!-- GameBar Overlay Tile Service -->
|
||||
<service
|
||||
android:name=".gamebar.GameBarTileService"
|
||||
android:label="@string/game_bar_tile_label"
|
||||
android:icon="@drawable/ic_gamebar"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.service.quicksettings.TOGGLEABLE_TILE"
|
||||
android:value="true" />
|
||||
</service>
|
||||
|
||||
<!-- GameBar Overlay Monitor Service -->
|
||||
<service
|
||||
android:name=".gamebar.GameBarMonitorService"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- GameBar BootReceiver -->
|
||||
<receiver
|
||||
android:name=".gamebar.GameBarBootReceiver"
|
||||
android:exported="true"
|
||||
android:enabled="true"
|
||||
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -1,13 +0,0 @@
|
||||
<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="@android:color/white"
|
||||
android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4zM15,20H9V6h6V20z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9,8h6v2H9z"/>
|
||||
</vector>
|
||||
@@ -1,16 +0,0 @@
|
||||
<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="@android:color/white"
|
||||
android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4zM15,20H9V6h6V20z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M13,13a1,1 0 1,1 -2,0a1,1 0 1,1 2,0"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,10.5c-0.83,0 -1.5,0.67 -1.5,1.5h1c0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5c0,0.5 -0.75,0.75 -0.75,1.5h1c0,-0.38 0.75,-0.75 0.75,-1.5C13.5,11.17 12.83,10.5 12,10.5z"/>
|
||||
</vector>
|
||||
@@ -1,26 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorOnSurface">
|
||||
|
||||
<!-- Battery outline -->
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.67,4H14V2c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z"/>
|
||||
|
||||
<!-- Bypass indicator (diagonal line) -->
|
||||
<path
|
||||
android:fillColor="@android:color/black"
|
||||
android:pathData="M6,6l12,12"
|
||||
android:strokeColor="@android:color/white"
|
||||
android:strokeWidth="1.5"
|
||||
android:strokeLineCap="round"/>
|
||||
|
||||
<!-- Lightning bolt (partially visible) -->
|
||||
<path
|
||||
android:fillColor="@android:color/black"
|
||||
android:pathData="M11,9l1.5,0l-1.5,3l1,0l-1.5,3l-1.5,0l1.5,-3l-1,0z"/>
|
||||
|
||||
</vector>
|
||||
@@ -1,13 +0,0 @@
|
||||
<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="@android:color/white"
|
||||
android:pathData="M15.67,4H14V2h-4v2H8.33C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.33,22h7.33c0.74,0 1.34,-0.6 1.34,-1.33V5.33C17,4.6 16.4,4 15.67,4z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/black"
|
||||
android:pathData="M11,20v-5.5H9L13,7v5.5h2L11,20z"/>
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<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="@android:color/white"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-2h2v2zM13,13h-2L11,7h2v6z"/>
|
||||
</vector>
|
||||
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7,6H17A6,6 0 0,1 23,12A6,6 0 0,1 17,18C15.22,18 13.63,17.23 12.53,16H11.47C10.37,17.23 8.78,18 7,18A6,6 0 0,1 1,12A6,6 0 0,1 7,6M6,9V11H4V13H6V15H8V13H10V11H8V9H6M15.5,12A1.5,1.5 0 0,0 14,13.5A1.5,1.5 0 0,0 15.5,15A1.5,1.5 0 0,0 17,13.5A1.5,1.5 0 0,0 15.5,12M18.5,9A1.5,1.5 0 0,0 17,10.5A1.5,1.5 0 0,0 18.5,12A1.5,1.5 0 0,0 20,10.5A1.5,1.5 0 0,0 18.5,9Z" />
|
||||
</vector>
|
||||
@@ -1,9 +0,0 @@
|
||||
<!-- drawable/music_clef_bass.xml -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
<path android:fillColor="#000" android:pathData="M18.5 5A1.5 1.5 0 1 1 17 6.5A1.5 1.5 0 0 1 18.5 5M18.5 11A1.5 1.5 0 1 1 17 12.5A1.5 1.5 0 0 1 18.5 11M10 4A5 5 0 0 0 5 9V10A2 2 0 1 0 7.18 8A3 3 0 0 1 10 6A4 4 0 0 1 14 10C14 13.59 11.77 16.19 7 18.2L7.76 20.04C13.31 17.72 16 14.43 16 10A6 6 0 0 0 10 4Z" />
|
||||
</vector>
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/game_bar_fragment"
|
||||
android:name="org.lineageos.settings.gamebar.GameBarFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/game_bar_root"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#80000000"
|
||||
android:padding="8dp"
|
||||
android:orientation="vertical">
|
||||
</LinearLayout>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/app_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/app_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginEnd="8dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="bold"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_package"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
@@ -1,108 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2025 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<!-- FPS Overlay -->
|
||||
<string-array name="game_bar_fps_method_entries">
|
||||
<item>New API (Default)</item>
|
||||
<item>Legacy Sysfs</item>
|
||||
</string-array>
|
||||
<string-array name="game_bar_fps_method_values">
|
||||
<item>new</item>
|
||||
<item>legacy</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Update Interval -->
|
||||
<string-array name="fps_overlay_update_interval_entries">
|
||||
<item>Every 500ms</item>
|
||||
<item>Every second</item>
|
||||
<item>Every 2 seconds</item>
|
||||
<item>Every 5 seconds</item>
|
||||
</string-array>
|
||||
<string-array name="fps_overlay_update_interval_values">
|
||||
<item>500</item>
|
||||
<item>1000</item>
|
||||
<item>2000</item>
|
||||
<item>5000</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Position -->
|
||||
<string-array name="fps_overlay_position_entries">
|
||||
<item>Top Left</item>
|
||||
<item>Top Center</item>
|
||||
<item>Top Right</item>
|
||||
<item>Bottom Left</item>
|
||||
<item>Bottom Center</item>
|
||||
<item>Bottom Right</item>
|
||||
<item>Custom Draggable</item>
|
||||
</string-array>
|
||||
<string-array name="fps_overlay_position_values">
|
||||
<item>top_left</item>
|
||||
<item>top_center</item>
|
||||
<item>top_right</item>
|
||||
<item>bottom_left</item>
|
||||
<item>bottom_center</item>
|
||||
<item>bottom_right</item>
|
||||
<item>draggable</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Overlay color -->
|
||||
<string-array name="fps_overlay_color_entries">
|
||||
<item>White</item>
|
||||
<item>Crimson</item>
|
||||
<item>Fruit Salad</item>
|
||||
<item>Royal Blue</item>
|
||||
<item>Amber</item>
|
||||
<item>Teal</item>
|
||||
<item>Electric Violet</item>
|
||||
<item>Magenta</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="fps_overlay_color_values">
|
||||
<item>#FFFFFF</item>
|
||||
<item>#DC143C</item>
|
||||
<item>#4CAF50</item>
|
||||
<item>#4169E1</item>
|
||||
<item>#FFBF00</item>
|
||||
<item>#008080</item>
|
||||
<item>#8A2BE2</item>
|
||||
<item>#FF1493</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Overlay format -->
|
||||
<string-array name="game_bar_format_entries">
|
||||
<item>Full</item>
|
||||
<item>Minimal</item>
|
||||
</string-array>
|
||||
<string-array name="game_bar_format_values">
|
||||
<item>full</item>
|
||||
<item>minimal</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Split Mode -->
|
||||
<string-array name="game_bar_split_mode_entries">
|
||||
<item>Side-by-Side</item>
|
||||
<item>Stacked</item>
|
||||
</string-array>
|
||||
<string-array name="game_bar_split_mode_values">
|
||||
<item>side_by_side</item>
|
||||
<item>stacked</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Long press timeouts -->
|
||||
<string-array name="game_bar_longpress_entries">
|
||||
<item>1 second</item>
|
||||
<item>3 seconds</item>
|
||||
<item>5 seconds</item>
|
||||
<item>10 seconds</item>
|
||||
</string-array>
|
||||
<string-array name="game_bar_longpress_values">
|
||||
<item>1000</item>
|
||||
<item>3000</item>
|
||||
<item>5000</item>
|
||||
<item>10000</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="MinMaxSeekBarPreference">
|
||||
<attr name="minValue" format="integer" />
|
||||
<attr name="maxValue" format="integer" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@@ -1,90 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<!-- Core Settings -->
|
||||
<string name="app_title">Core Settings</string>
|
||||
<string name="tile_add">Add tile</string>
|
||||
<string name="tile_added">Tile added</string>
|
||||
<string name="tile_not_added">Tile not added</string>
|
||||
<string name="tile_already_added">Tile already added</string>
|
||||
<string name="tile_on">On</string>
|
||||
<string name="tile_off">Off</string>
|
||||
|
||||
<!-- GameBar Overlay -->
|
||||
<string name="game_bar_title">GameBar</string>
|
||||
<string name="game_bar_summary">Enable the system overlay (FPS, Temp, etc.)</string>
|
||||
<string name="overlay_permission_required">Overlay permission is required</string>
|
||||
<string name="overlay_permission_granted">Overlay permission granted</string>
|
||||
<string name="overlay_permission_denied">Overlay permission denied</string>
|
||||
<string name="game_bar_tile_label">GameBar</string>
|
||||
<string name="game_bar_tile_description">Toggle the game overlay</string>
|
||||
|
||||
<!-- Charging information tile -->
|
||||
<string name="charging_tile_label">Charging Speed</string>
|
||||
<string name="charging_tile_information">Shows real-time charging/discharging power</string>
|
||||
|
||||
<!-- Tile states -->
|
||||
<string name="charging_tile_charging">Charging</string>
|
||||
<string name="charging_tile_discharging">Discharging</string>
|
||||
<string name="charging_tile_not_charging">Not Charging</string>
|
||||
<string name="charging_tile_error">Error</string>
|
||||
|
||||
<!-- Content descriptions for accessibility -->
|
||||
<string name="charging_tile_desc_charging">Charging at %1$s watts, %2$s amps, %3$s volts</string>
|
||||
<string name="charging_tile_desc_discharging">Discharging at %1$s watts</string>
|
||||
<string name="charging_tile_desc_not_charging">Battery not charging or discharging</string>
|
||||
<string name="charging_tile_desc_error">Unable to read charging information</string>
|
||||
|
||||
<!-- Charge bypass strings -->
|
||||
<string name="charge_bypass_title">Charging Bypass</string>
|
||||
<string name="charge_bypass_summary">Configure charging bypass settings</string>
|
||||
<string name="charge_bypass_warning">Enabling charging bypass will prevent the battery from charging while plugged in. This may affect battery longevity if used incorrectly.</string>
|
||||
<string name="charge_bypass_unavailable">Charging bypass is not supported on this device</string>
|
||||
|
||||
<!-- Master toggle strings -->
|
||||
<string name="charge_bypass_master_title">Enable Charging Bypass</string>
|
||||
<string name="charge_bypass_master_summary">Allow charging bypass based on selected configuration</string>
|
||||
|
||||
<!-- Configuration category -->
|
||||
<string name="charge_bypass_configuration_title">Bypass Configuration</string>
|
||||
|
||||
<!-- Manual mode strings -->
|
||||
<string name="charge_bypass_manual_title">Manual Control</string>
|
||||
<string name="charge_bypass_manual_summary">Control charging bypass through Quick Settings tile</string>
|
||||
|
||||
<!-- Smart mode strings -->
|
||||
<string name="charge_bypass_smart_title">Smart Control</string>
|
||||
<string name="charge_bypass_smart_summary">Automatically manage charging bypass based on battery level</string>
|
||||
|
||||
<!-- Battery target strings -->
|
||||
<string name="charge_bypass_battery_target_title">Battery Target</string>
|
||||
<string name="charge_bypass_battery_target_summary">Bypass charging when battery reaches this level (%d%%)</string>
|
||||
|
||||
<!-- QS Tile strings -->
|
||||
<string name="charge_bypass_qs_tile_label">Charging Bypass</string>
|
||||
<string name="charge_bypass_qs_active">Bypass Active</string>
|
||||
<string name="charge_bypass_qs_inactive">Bypass Inactive</string>
|
||||
<string name="charge_bypass_qs_disabled">Bypass Disabled</string>
|
||||
|
||||
<!-- Notification strings -->
|
||||
<string name="charge_bypass_notification_title">Charging Bypass Active</string>
|
||||
<string name="charge_bypass_notification_text">Battery charging is currently bypassed</string>
|
||||
<string name="charge_bypass_smart_enabled">Smart charging bypass enabled at %d%%</string>
|
||||
<string name="charge_bypass_smart_disabled">Smart charging bypass disabled</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- Main bypass toggle -->
|
||||
<SwitchPreference
|
||||
android:key="bypass_charge_master"
|
||||
android:title="@string/charge_bypass_master_title"
|
||||
android:summary="@string/charge_bypass_master_summary"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<!-- Configuration category -->
|
||||
<PreferenceCategory
|
||||
android:key="bypass_configuration_category"
|
||||
android:title="@string/charge_bypass_configuration_title">
|
||||
|
||||
<!-- Manual bypass option -->
|
||||
<CheckBoxPreference
|
||||
android:key="bypass_mode_manual"
|
||||
android:title="@string/charge_bypass_manual_title"
|
||||
android:summary="@string/charge_bypass_manual_summary"
|
||||
android:defaultValue="true" />
|
||||
|
||||
<!-- Smart bypass option -->
|
||||
<CheckBoxPreference
|
||||
android:key="bypass_mode_smart"
|
||||
android:title="@string/charge_bypass_smart_title"
|
||||
android:summary="@string/charge_bypass_smart_summary"
|
||||
android:defaultValue="false" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<!-- Battery target slider (only visible in smart mode) -->
|
||||
<org.lineageos.settings.charge.MinMaxSeekBarPreference
|
||||
android:key="battery_target_slider"
|
||||
android:title="@string/charge_bypass_battery_target_title"
|
||||
android:summary="@string/charge_bypass_battery_target_summary"
|
||||
android:min="50"
|
||||
android:max="100"
|
||||
android:defaultValue="80"
|
||||
android:dependency="bypass_mode_smart" />
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -1,252 +0,0 @@
|
||||
<?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">
|
||||
|
||||
<com.android.settingslib.widget.MainSwitchPreference
|
||||
android:key="game_bar_enable"
|
||||
android:title="Enable GameBar Overlay"
|
||||
android:summary="@string/game_bar_summary"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Overlay Features"
|
||||
android:dependency="game_bar_enable">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_fps_enable"
|
||||
android:title="FPS Overlay"
|
||||
android:summary="Show current FPS on screen"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_temp_enable"
|
||||
android:title="Device Temperature"
|
||||
android:summary="Show device (battery) temperature"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_cpu_usage_enable"
|
||||
android:title="CPU Usage"
|
||||
android:summary="Show current CPU usage percentage"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_cpu_clock_enable"
|
||||
android:title="CPU Clock Speeds"
|
||||
android:summary="Show current CPU clock speeds for each core"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_cpu_temp_enable"
|
||||
android:title="CPU Temperature"
|
||||
android:summary="Show CPU temperature (thermal_zone0)"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_ram_enable"
|
||||
android:title="RAM Usage"
|
||||
android:summary="Show current RAM usage in MB"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_gpu_usage_enable"
|
||||
android:title="GPU Usage"
|
||||
android:summary="Show GPU usage percentage"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_gpu_clock_enable"
|
||||
android:title="GPU Clock Speed"
|
||||
android:summary="Show current GPU clock frequency"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_gpu_temp_enable"
|
||||
android:title="GPU Temperature"
|
||||
android:summary="Show current GPU temperature"
|
||||
android:defaultValue="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="FPS Measurement Method"
|
||||
android:dependency="game_bar_fps_enable">
|
||||
<ListPreference
|
||||
android:key="game_bar_fps_method"
|
||||
android:title="Select FPS Method"
|
||||
android:summary="Choose between the New API method (default) and Legacy Sysfs"
|
||||
android:defaultValue="new"
|
||||
android:entries="@array/game_bar_fps_method_entries"
|
||||
android:entryValues="@array/game_bar_fps_method_values" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Customization"
|
||||
android:dependency="game_bar_enable">
|
||||
|
||||
<SeekBarPreference
|
||||
android:key="game_bar_text_size"
|
||||
android:title="Text Size"
|
||||
android:summary="Adjust the size of overlay text"
|
||||
android:defaultValue="16"
|
||||
android:max="32"
|
||||
android:min="12" />
|
||||
|
||||
<SeekBarPreference
|
||||
android:key="game_bar_background_alpha"
|
||||
android:title="Background Transparency"
|
||||
android:summary="Adjust the transparency of the background"
|
||||
android:defaultValue="128"
|
||||
android:max="255"
|
||||
android:min="0" />
|
||||
|
||||
<SeekBarPreference
|
||||
android:key="game_bar_corner_radius"
|
||||
android:title="Overlay Corner Radius"
|
||||
android:summary="Adjust how rounded the overlay corners should be"
|
||||
android:defaultValue="16"
|
||||
android:max="100"
|
||||
android:min="0" />
|
||||
|
||||
<SeekBarPreference
|
||||
android:key="game_bar_padding"
|
||||
android:title="Overlay Padding"
|
||||
android:summary="Adjust the space around the stats"
|
||||
android:defaultValue="12"
|
||||
android:max="64"
|
||||
android:min="0" />
|
||||
|
||||
<SeekBarPreference
|
||||
android:key="game_bar_item_spacing"
|
||||
android:title="Item Spacing"
|
||||
android:summary="Adjust spacing between overlay lines"
|
||||
android:defaultValue="8"
|
||||
android:max="50"
|
||||
android:min="0" />
|
||||
|
||||
<ListPreference
|
||||
android:key="game_bar_update_interval"
|
||||
android:title="Update Interval"
|
||||
android:summary="Set how often the overlay values update"
|
||||
android:defaultValue="1000"
|
||||
android:entries="@array/fps_overlay_update_interval_entries"
|
||||
android:entryValues="@array/fps_overlay_update_interval_values" />
|
||||
|
||||
<ListPreference
|
||||
android:key="game_bar_title_color"
|
||||
android:title="Stat Title Color"
|
||||
android:summary="Color for 'FPS', 'Temp', 'CPU', etc. text"
|
||||
android:defaultValue="#FFFFFF"
|
||||
android:entries="@array/fps_overlay_color_entries"
|
||||
android:entryValues="@array/fps_overlay_color_values" />
|
||||
|
||||
<ListPreference
|
||||
android:key="game_bar_value_color"
|
||||
android:title="Stat Value Color"
|
||||
android:summary="Color for numeric stats (e.g., '29', '32.0°C')"
|
||||
android:defaultValue="#4CAF50"
|
||||
android:entries="@array/fps_overlay_color_entries"
|
||||
android:entryValues="@array/fps_overlay_color_values" />
|
||||
|
||||
<ListPreference
|
||||
android:key="game_bar_position"
|
||||
android:title="Overlay Position"
|
||||
android:summary="Select the position of the overlay on screen"
|
||||
android:defaultValue="top_left"
|
||||
android:entries="@array/fps_overlay_position_entries"
|
||||
android:entryValues="@array/fps_overlay_position_values" />
|
||||
|
||||
<ListPreference
|
||||
android:key="game_bar_format"
|
||||
android:title="Overlay Format"
|
||||
android:summary="Choose between Full or Minimal display"
|
||||
android:defaultValue="full"
|
||||
android:entries="@array/game_bar_format_entries"
|
||||
android:entryValues="@array/game_bar_format_values" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Split Config"
|
||||
android:dependency="game_bar_enable">
|
||||
|
||||
<ListPreference
|
||||
android:key="game_bar_split_mode"
|
||||
android:title="Split Mode"
|
||||
android:summary="Choose Side-by-Side or Stacked arrangement"
|
||||
android:defaultValue="stacked"
|
||||
android:entries="@array/game_bar_split_mode_entries"
|
||||
android:entryValues="@array/game_bar_split_mode_values" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Overlay Gesture Controls"
|
||||
android:dependency="game_bar_enable">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_single_tap_toggle"
|
||||
android:title="Enable Single Tap to Toggle"
|
||||
android:summary="Tap once to switch between full and minimal overlay formats"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_doubletap_capture"
|
||||
android:title="Enable Double Tap to Capture"
|
||||
android:summary="Double-tap overlay to start/stop capture logs"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_longpress_enable"
|
||||
android:title="Enable Long Press"
|
||||
android:summary="Long-press overlay to access GameBar settings"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<ListPreference
|
||||
android:key="game_bar_longpress_timeout"
|
||||
android:title="Long Press Duration"
|
||||
android:summary="Set the duration required to long-press the overlay"
|
||||
android:defaultValue="1000"
|
||||
android:entries="@array/game_bar_longpress_entries"
|
||||
android:entryValues="@array/game_bar_longpress_values"
|
||||
android:dependency="game_bar_longpress_enable" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Capture Logs"
|
||||
android:dependency="game_bar_enable">
|
||||
|
||||
<Preference
|
||||
android:key="game_bar_capture_start"
|
||||
android:title="Start Logging"
|
||||
android:summary="Begin capturing FPS and performance data in real-time" />
|
||||
|
||||
<Preference
|
||||
android:key="game_bar_capture_stop"
|
||||
android:title="Stop Logging"
|
||||
android:summary="Stop capturing FPS and performance data in real-time" />
|
||||
|
||||
<Preference
|
||||
android:key="game_bar_capture_export"
|
||||
android:title="Export GameBar Log Data"
|
||||
android:summary="Save the captured FPS and performance data as a CSV file" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Auto Enable GameBar">
|
||||
<SwitchPreferenceCompat
|
||||
android:key="game_bar_auto_enable"
|
||||
android:title="Auto-Enable GameBar for Selected Apps"
|
||||
android:summary="If turned on, selected apps will auto-enable GameBar even if the main switch is off"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<Preference
|
||||
android:key="game_bar_app_selector"
|
||||
android:title="Select Apps"
|
||||
android:summary="Add apps that should auto-enable GameBar" />
|
||||
|
||||
<Preference
|
||||
android:key="game_bar_app_remover"
|
||||
android:title="Remove Selected Apps"
|
||||
android:summary="Remove apps from the auto-enable list" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* 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.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
|
||||
public class BootCompletedReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "Parts";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
if (DEBUG) Log.i(TAG, "Received intent: " + intent.getAction());
|
||||
switch (intent.getAction()) {
|
||||
case Intent.ACTION_LOCKED_BOOT_COMPLETED:
|
||||
handleLockedBootCompleted(context);
|
||||
break;
|
||||
case Intent.ACTION_BOOT_COMPLETED:
|
||||
handleBootCompleted(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLockedBootCompleted(Context context) {
|
||||
if (DEBUG) Log.i(TAG, "Handling locked boot completed.");
|
||||
try {
|
||||
// Start necessary services
|
||||
startServices(context);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error during locked boot completed processing", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleBootCompleted(Context context) {
|
||||
if (DEBUG) Log.i(TAG, "Handling boot completed.");
|
||||
// Add additional boot-completed actions if needed
|
||||
}
|
||||
|
||||
private void startServices(Context context) {
|
||||
if (DEBUG) Log.i(TAG, "Starting services...");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.service.quicksettings.TileService;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.lineageos.settings.gamebar.GameBarSettingsActivity;
|
||||
import org.lineageos.settings.gamebar.GameBarTileService;
|
||||
import org.lineageos.settings.charge.ChargeActivity;
|
||||
import org.lineageos.settings.charge.ChargeQSTile;
|
||||
import org.lineageos.settings.charginginfo.ChargingInfoTileService;
|
||||
|
||||
public final class TileHandlerActivity extends Activity {
|
||||
private static final String TAG = "TileHandlerActivity";
|
||||
|
||||
// Map QS Tile services to their corresponding activity
|
||||
private static final Map<String, Class<?>> TILE_ACTIVITY_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
TILE_ACTIVITY_MAP.put(GameBarTileService.class.getName(), GameBarSettingsActivity.class);
|
||||
TILE_ACTIVITY_MAP.put(ChargeQSTile.class.getName(), ChargeActivity.class);
|
||||
TILE_ACTIVITY_MAP.put(ChargingInfoTileService.class.getName(), ChargeActivity.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
if (intent == null || !TileService.ACTION_QS_TILE_PREFERENCES.equals(intent.getAction())) {
|
||||
Log.e(TAG, "Invalid or null intent received");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
final ComponentName qsTile = intent.getParcelableExtra(Intent.EXTRA_COMPONENT_NAME);
|
||||
if (qsTile == null) {
|
||||
Log.e(TAG, "No QS tile component found in intent");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
final String qsName = qsTile.getClassName();
|
||||
final Intent targetIntent = new Intent();
|
||||
|
||||
// Check if the tile is mapped to an activity
|
||||
if (TILE_ACTIVITY_MAP.containsKey(qsName)) {
|
||||
targetIntent.setClass(this, TILE_ACTIVITY_MAP.get(qsName));
|
||||
Log.d(TAG, "Launching settings activity for QS tile: " + qsName);
|
||||
} else {
|
||||
// Default: Open app settings for the QS tile's package
|
||||
final String packageName = qsTile.getPackageName();
|
||||
if (packageName == null) {
|
||||
Log.e(TAG, "QS tile package name is null");
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
targetIntent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
targetIntent.setData(Uri.fromParts("package", packageName, null));
|
||||
Log.d(TAG, "Opening app info for package: " + packageName);
|
||||
}
|
||||
|
||||
// Ensure proper navigation behavior
|
||||
targetIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
|
||||
Intent.FLAG_ACTIVITY_CLEAR_TASK |
|
||||
Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
||||
startActivity(targetIntent);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* 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.settings.charge;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
|
||||
public class ChargeActivity extends CollapsingToolbarBaseActivity {
|
||||
|
||||
private static final String TAG_BYPASS_CHARGE = "bypass_charge";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getSupportFragmentManager().beginTransaction().replace(
|
||||
com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
||||
new ChargeSettingsFragment(), TAG_BYPASS_CHARGE).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
/*
|
||||
* 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.settings.charge;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class ChargeBatteryMonitorService extends Service {
|
||||
|
||||
private static final String TAG = "ChargeBatteryMonitorService";
|
||||
private static final String NOTIFICATION_CHANNEL_ID = "charge_bypass_channel";
|
||||
private static final int NOTIFICATION_ID = 1001;
|
||||
|
||||
private ChargeUtils mChargeUtils;
|
||||
private BatteryReceiver mBatteryReceiver;
|
||||
private NotificationManager mNotificationManager;
|
||||
private boolean mIsMonitoring = false;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mChargeUtils = new ChargeUtils(this);
|
||||
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
createNotificationChannel();
|
||||
|
||||
Log.d(TAG, "Service created");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (!mChargeUtils.isMasterToggleEnabled()) {
|
||||
Log.d(TAG, "Master toggle disabled, stopping service");
|
||||
stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
if (!mIsMonitoring) {
|
||||
startMonitoring();
|
||||
}
|
||||
|
||||
return START_STICKY; // Restart service if killed
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
stopMonitoring();
|
||||
Log.d(TAG, "Service destroyed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null; // We don't provide binding
|
||||
}
|
||||
|
||||
private void startMonitoring() {
|
||||
if (mIsMonitoring) return;
|
||||
|
||||
mBatteryReceiver = new BatteryReceiver();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
|
||||
filter.addAction(Intent.ACTION_POWER_CONNECTED);
|
||||
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
|
||||
|
||||
registerReceiver(mBatteryReceiver, filter);
|
||||
mIsMonitoring = true;
|
||||
|
||||
// Initial check
|
||||
mChargeUtils.updateBypassState();
|
||||
updateNotification();
|
||||
|
||||
Log.d(TAG, "Started battery monitoring");
|
||||
}
|
||||
|
||||
private void stopMonitoring() {
|
||||
if (!mIsMonitoring) return;
|
||||
|
||||
if (mBatteryReceiver != null) {
|
||||
unregisterReceiver(mBatteryReceiver);
|
||||
mBatteryReceiver = null;
|
||||
}
|
||||
|
||||
mIsMonitoring = false;
|
||||
stopForeground(true);
|
||||
|
||||
Log.d(TAG, "Stopped battery monitoring");
|
||||
}
|
||||
|
||||
private void createNotificationChannel() {
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
NOTIFICATION_CHANNEL_ID,
|
||||
"Charging Bypass",
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
);
|
||||
channel.setDescription("Charging bypass monitoring service");
|
||||
channel.setShowBadge(false);
|
||||
mNotificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
private void updateNotification() {
|
||||
if (!mIsMonitoring) return;
|
||||
|
||||
boolean bypassActive = mChargeUtils.isBypassChargeEnabled();
|
||||
int batteryLevel = mChargeUtils.getCurrentBatteryLevel();
|
||||
int mode = mChargeUtils.getBypassMode();
|
||||
|
||||
// If bypass is not active, hide notification completely regardless of mode
|
||||
if (!bypassActive) {
|
||||
stopForeground(true);
|
||||
mNotificationManager.cancel(NOTIFICATION_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
String title = getString(R.string.charge_bypass_notification_title);
|
||||
String text;
|
||||
|
||||
if (mode == ChargeUtils.MODE_SMART) {
|
||||
int target = mChargeUtils.getBatteryTarget();
|
||||
if (bypassActive) {
|
||||
text = getString(R.string.charge_bypass_smart_enabled, target);
|
||||
} else {
|
||||
text = "Smart mode active - Target: " + target + "% (Current: " + batteryLevel + "%)";
|
||||
}
|
||||
} else {
|
||||
text = getString(R.string.charge_bypass_notification_text);
|
||||
}
|
||||
|
||||
// Create a simple settings intent instead of ChargeActivity
|
||||
Intent settingsIntent = new Intent(android.provider.Settings.ACTION_SETTINGS);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||
this, 0, settingsIntent, PendingIntent.FLAG_IMMUTABLE
|
||||
);
|
||||
|
||||
Notification notification = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||
.setContentTitle(title)
|
||||
.setContentText(text)
|
||||
.setSmallIcon(android.R.drawable.ic_menu_manage) // Use system icon as fallback
|
||||
.setContentIntent(pendingIntent)
|
||||
.setOngoing(true)
|
||||
.setShowWhen(false)
|
||||
.build();
|
||||
|
||||
if (bypassActive) {
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
}
|
||||
}
|
||||
|
||||
private class BatteryReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
if (Intent.ACTION_BATTERY_CHANGED.equals(action) ||
|
||||
Intent.ACTION_POWER_CONNECTED.equals(action) ||
|
||||
Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
|
||||
|
||||
Log.d(TAG, "Battery state changed: " + action);
|
||||
|
||||
// Check if we should still be running
|
||||
if (!mChargeUtils.isMasterToggleEnabled()) {
|
||||
Log.d(TAG, "Master toggle disabled, stopping service");
|
||||
stopSelf();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update bypass state based on current conditions
|
||||
boolean wasActive = mChargeUtils.isBypassChargeEnabled();
|
||||
mChargeUtils.updateBypassState();
|
||||
boolean isActive = mChargeUtils.isBypassChargeEnabled();
|
||||
|
||||
// Update notification
|
||||
updateNotification();
|
||||
|
||||
// Log state changes
|
||||
if (wasActive != isActive) {
|
||||
int batteryLevel = mChargeUtils.getCurrentBatteryLevel();
|
||||
Log.d(TAG, "Bypass state changed: " + isActive +
|
||||
" (Battery: " + batteryLevel + "%)");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* 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.settings.charge;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
import android.util.Log;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class ChargeQSTile extends TileService {
|
||||
|
||||
private static final String TAG = "ChargeQSTile";
|
||||
private ChargeUtils mChargeUtils;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mChargeUtils = new ChargeUtils(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
super.onStartListening();
|
||||
updateTile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopListening() {
|
||||
super.onStopListening();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
super.onClick();
|
||||
|
||||
if (!mChargeUtils.canToggleManually()) {
|
||||
// Show inactive state if not in manual mode or master toggle is off
|
||||
updateTile();
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle manual bypass state
|
||||
boolean currentState = mChargeUtils.getManualBypassState();
|
||||
mChargeUtils.setManualBypassState(!currentState);
|
||||
|
||||
// Update tile immediately
|
||||
updateTile();
|
||||
|
||||
Log.d(TAG, "Manual bypass toggled to: " + !currentState);
|
||||
}
|
||||
|
||||
private void updateTile() {
|
||||
Tile tile = getQsTile();
|
||||
if (tile == null) return;
|
||||
|
||||
boolean masterEnabled = mChargeUtils.isMasterToggleEnabled();
|
||||
boolean isManualMode = mChargeUtils.getBypassMode() == ChargeUtils.MODE_MANUAL;
|
||||
boolean canToggle = masterEnabled && isManualMode;
|
||||
boolean bypassActive = mChargeUtils.isBypassChargeEnabled();
|
||||
|
||||
// Set tile icon
|
||||
Icon icon = Icon.createWithResource(this, R.drawable.ic_charge_bypass);
|
||||
tile.setIcon(icon);
|
||||
|
||||
// Set tile label
|
||||
tile.setLabel(getString(R.string.charge_bypass_qs_tile_label));
|
||||
|
||||
if (!masterEnabled) {
|
||||
// Master toggle is off
|
||||
tile.setState(Tile.STATE_UNAVAILABLE);
|
||||
tile.setSubtitle(getString(R.string.charge_bypass_qs_disabled));
|
||||
} else if (!isManualMode) {
|
||||
// In smart mode
|
||||
tile.setState(Tile.STATE_UNAVAILABLE);
|
||||
tile.setSubtitle("Smart Mode");
|
||||
} else if (canToggle) {
|
||||
// Manual mode and can toggle
|
||||
if (bypassActive) {
|
||||
tile.setState(Tile.STATE_ACTIVE);
|
||||
tile.setSubtitle(getString(R.string.charge_bypass_qs_active));
|
||||
} else {
|
||||
tile.setState(Tile.STATE_INACTIVE);
|
||||
tile.setSubtitle(getString(R.string.charge_bypass_qs_inactive));
|
||||
}
|
||||
} else {
|
||||
// Fallback state
|
||||
tile.setState(Tile.STATE_UNAVAILABLE);
|
||||
tile.setSubtitle(getString(R.string.charge_bypass_qs_disabled));
|
||||
}
|
||||
|
||||
tile.updateTile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTileAdded() {
|
||||
super.onTileAdded();
|
||||
updateTile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTileRemoved() {
|
||||
super.onTileRemoved();
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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.settings.charge;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
public class ChargeReceiver extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "ChargeReceiver";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(action) ||
|
||||
Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
|
||||
|
||||
Log.d(TAG, "Boot completed, restoring charge bypass settings");
|
||||
|
||||
ChargeUtils chargeUtils = new ChargeUtils(context);
|
||||
|
||||
// Check if bypass is supported on this device
|
||||
if (!chargeUtils.isBypassChargeSupported()) {
|
||||
Log.d(TAG, "Bypass not supported on this device");
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore bypass state based on saved preferences
|
||||
if (chargeUtils.isMasterToggleEnabled()) {
|
||||
Log.d(TAG, "Master toggle enabled, restoring bypass state");
|
||||
|
||||
// Reset bypass to disabled state first
|
||||
chargeUtils.enableBypassCharge(false);
|
||||
|
||||
// Start monitoring service if needed
|
||||
int mode = chargeUtils.getBypassMode();
|
||||
if (mode == ChargeUtils.MODE_SMART) {
|
||||
Intent serviceIntent = new Intent(context, ChargeBatteryMonitorService.class);
|
||||
context.startService(serviceIntent);
|
||||
Log.d(TAG, "Started battery monitoring service for smart mode");
|
||||
} else if (mode == ChargeUtils.MODE_MANUAL) {
|
||||
// In manual mode, respect the saved manual state
|
||||
// but don't automatically enable bypass on boot for safety
|
||||
chargeUtils.setManualBypassState(false);
|
||||
Log.d(TAG, "Manual mode restored, bypass disabled for safety");
|
||||
}
|
||||
|
||||
// Update bypass state based on current conditions
|
||||
chargeUtils.updateBypassState();
|
||||
|
||||
} else {
|
||||
Log.d(TAG, "Master toggle disabled, ensuring bypass is off");
|
||||
chargeUtils.enableBypassCharge(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* 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.settings.charge;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.CheckBoxPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
public class ChargeSettingsFragment extends PreferenceFragmentCompat
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private static final String TAG = "ChargeSettingsFragment";
|
||||
|
||||
// Preference keys
|
||||
private static final String KEY_BYPASS_CHARGE_MASTER = "bypass_charge_master";
|
||||
private static final String KEY_BYPASS_MODE_MANUAL = "bypass_mode_manual";
|
||||
private static final String KEY_BYPASS_MODE_SMART = "bypass_mode_smart";
|
||||
private static final String KEY_BATTERY_TARGET_SLIDER = "battery_target_slider";
|
||||
private static final String KEY_BYPASS_CONFIGURATION_CATEGORY = "bypass_configuration_category";
|
||||
|
||||
// Preferences
|
||||
private SwitchPreference mMasterToggle;
|
||||
private CheckBoxPreference mManualMode;
|
||||
private CheckBoxPreference mSmartMode;
|
||||
private MinMaxSeekBarPreference mBatteryTarget;
|
||||
private PreferenceCategory mConfigurationCategory;
|
||||
|
||||
private ChargeUtils mChargeUtils;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.charge_settings, rootKey);
|
||||
|
||||
mChargeUtils = new ChargeUtils(getActivity());
|
||||
|
||||
// Initialize preferences
|
||||
mMasterToggle = (SwitchPreference) findPreference(KEY_BYPASS_CHARGE_MASTER);
|
||||
mManualMode = (CheckBoxPreference) findPreference(KEY_BYPASS_MODE_MANUAL);
|
||||
mSmartMode = (CheckBoxPreference) findPreference(KEY_BYPASS_MODE_SMART);
|
||||
mBatteryTarget = (MinMaxSeekBarPreference) findPreference(KEY_BATTERY_TARGET_SLIDER);
|
||||
mConfigurationCategory = (PreferenceCategory) findPreference(KEY_BYPASS_CONFIGURATION_CATEGORY);
|
||||
|
||||
boolean bypassSupported = mChargeUtils.isBypassChargeSupported();
|
||||
|
||||
if (!bypassSupported) {
|
||||
// Disable all preferences if bypass is not supported
|
||||
mMasterToggle.setEnabled(false);
|
||||
mMasterToggle.setSummary(R.string.charge_bypass_unavailable);
|
||||
mConfigurationCategory.setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up master toggle
|
||||
mMasterToggle.setChecked(mChargeUtils.isMasterToggleEnabled());
|
||||
mMasterToggle.setOnPreferenceChangeListener(this);
|
||||
|
||||
// Set up mode preferences
|
||||
int currentMode = mChargeUtils.getBypassMode();
|
||||
mManualMode.setChecked(currentMode == ChargeUtils.MODE_MANUAL);
|
||||
mSmartMode.setChecked(currentMode == ChargeUtils.MODE_SMART);
|
||||
mManualMode.setOnPreferenceChangeListener(this);
|
||||
mSmartMode.setOnPreferenceChangeListener(this);
|
||||
|
||||
// Set up battery target slider - Let the preference handle all mapping internally
|
||||
int batteryTarget = mChargeUtils.getBatteryTarget();
|
||||
mBatteryTarget.setBatteryTarget(batteryTarget); // Use the new method from MinMaxSeekBarPreference
|
||||
mBatteryTarget.setOnPreferenceChangeListener(this);
|
||||
updateBatteryTargetSummary(batteryTarget);
|
||||
|
||||
Log.d(TAG, "Initial battery target: " + batteryTarget + "%");
|
||||
|
||||
// Update UI state based on master toggle
|
||||
updateConfigurationVisibility(mChargeUtils.isMasterToggleEnabled());
|
||||
updateBatteryTargetVisibility(currentMode == ChargeUtils.MODE_SMART);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
final String key = preference.getKey();
|
||||
|
||||
switch (key) {
|
||||
case KEY_BYPASS_CHARGE_MASTER:
|
||||
boolean masterEnabled = (Boolean) newValue;
|
||||
if (masterEnabled) {
|
||||
showMasterToggleWarning(() -> {
|
||||
mChargeUtils.setMasterToggleEnabled(true);
|
||||
updateConfigurationVisibility(true);
|
||||
startBatteryMonitorService();
|
||||
});
|
||||
return false; // Don't update UI until user confirms
|
||||
} else {
|
||||
mChargeUtils.setMasterToggleEnabled(false);
|
||||
mChargeUtils.enableBypassCharge(false); // Disable bypass immediately
|
||||
updateConfigurationVisibility(false);
|
||||
stopBatteryMonitorService();
|
||||
return true;
|
||||
}
|
||||
|
||||
case KEY_BYPASS_MODE_MANUAL:
|
||||
if ((Boolean) newValue) {
|
||||
mSmartMode.setChecked(false);
|
||||
mChargeUtils.setBypassMode(ChargeUtils.MODE_MANUAL);
|
||||
updateBatteryTargetVisibility(false);
|
||||
stopBatteryMonitorService();
|
||||
return true;
|
||||
}
|
||||
return false; // Don't allow unchecking without selecting another mode
|
||||
|
||||
case KEY_BYPASS_MODE_SMART:
|
||||
if ((Boolean) newValue) {
|
||||
mManualMode.setChecked(false);
|
||||
mChargeUtils.setBypassMode(ChargeUtils.MODE_SMART);
|
||||
updateBatteryTargetVisibility(true);
|
||||
startBatteryMonitorService();
|
||||
return true;
|
||||
}
|
||||
return false; // Don't allow unchecking without selecting another mode
|
||||
|
||||
case KEY_BATTERY_TARGET_SLIDER:
|
||||
// FIXED: Calculate the battery target based on the new slider value
|
||||
int sliderValue = (Integer) newValue;
|
||||
|
||||
// Create a temporary preference object to calculate the mapped value
|
||||
// since the preference hasn't been updated yet
|
||||
int actualBatteryTarget = mBatteryTarget.calculateBatteryTargetFromSlider(sliderValue);
|
||||
|
||||
Log.d(TAG, "Slider changed - Position: " + sliderValue + "%, Battery target: " + actualBatteryTarget + "%");
|
||||
|
||||
mChargeUtils.setBatteryTarget(actualBatteryTarget);
|
||||
updateBatteryTargetSummary(actualBatteryTarget);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void showMasterToggleWarning(Runnable onConfirm) {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle(R.string.charge_bypass_master_title)
|
||||
.setMessage(R.string.charge_bypass_warning)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
mMasterToggle.setChecked(true);
|
||||
if (onConfirm != null) {
|
||||
onConfirm.run();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {
|
||||
mMasterToggle.setChecked(false);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private void updateConfigurationVisibility(boolean visible) {
|
||||
mConfigurationCategory.setVisible(visible);
|
||||
if (visible) {
|
||||
int currentMode = mChargeUtils.getBypassMode();
|
||||
updateBatteryTargetVisibility(currentMode == ChargeUtils.MODE_SMART);
|
||||
} else {
|
||||
updateBatteryTargetVisibility(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBatteryTargetVisibility(boolean visible) {
|
||||
mBatteryTarget.setVisible(visible);
|
||||
}
|
||||
|
||||
private void updateBatteryTargetSummary(int value) {
|
||||
String summaryText = getString(R.string.charge_bypass_battery_target_summary, value);
|
||||
mBatteryTarget.setSummary(summaryText);
|
||||
}
|
||||
|
||||
private void startBatteryMonitorService() {
|
||||
Intent serviceIntent = new Intent(getActivity(), ChargeBatteryMonitorService.class);
|
||||
getActivity().startService(serviceIntent);
|
||||
}
|
||||
|
||||
private void stopBatteryMonitorService() {
|
||||
Intent serviceIntent = new Intent(getActivity(), ChargeBatteryMonitorService.class);
|
||||
getActivity().stopService(serviceIntent);
|
||||
}
|
||||
}
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* 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.settings.charge;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.BatteryManager;
|
||||
import android.util.Log;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.lineageos.settings.utils.FileUtils;
|
||||
|
||||
public class ChargeUtils {
|
||||
|
||||
private static final String TAG = "ChargeUtils";
|
||||
|
||||
// Sysfs node for bypass control
|
||||
public static final String BYPASS_CHARGE_NODE = "/sys/class/power_supply/battery/input_suspend";
|
||||
|
||||
// Bypass modes
|
||||
public static final int MODE_MANUAL = 0;
|
||||
public static final int MODE_SMART = 1;
|
||||
|
||||
// Bypass states
|
||||
public static final int BYPASS_DISABLED = 0;
|
||||
public static final int BYPASS_ENABLED = 1;
|
||||
|
||||
// SharedPreferences keys
|
||||
private static final String PREF_MASTER_TOGGLE = "bypass_charge_master";
|
||||
private static final String PREF_BYPASS_MODE = "bypass_mode";
|
||||
private static final String PREF_BATTERY_TARGET = "battery_target";
|
||||
private static final String PREF_MANUAL_BYPASS_STATE = "manual_bypass_state";
|
||||
|
||||
// Default values
|
||||
private static final int DEFAULT_BATTERY_TARGET = 80;
|
||||
private static final int BATTERY_HYSTERESIS = 5; // 5% hysteresis for smart mode
|
||||
|
||||
private Context mContext;
|
||||
private SharedPreferences mSharedPrefs;
|
||||
|
||||
public ChargeUtils(Context context) {
|
||||
mContext = context;
|
||||
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
}
|
||||
|
||||
// Master toggle methods
|
||||
public boolean isMasterToggleEnabled() {
|
||||
return mSharedPrefs.getBoolean(PREF_MASTER_TOGGLE, false);
|
||||
}
|
||||
|
||||
public void setMasterToggleEnabled(boolean enabled) {
|
||||
mSharedPrefs.edit().putBoolean(PREF_MASTER_TOGGLE, enabled).apply();
|
||||
if (!enabled) {
|
||||
// Disable bypass immediately when master toggle is turned off
|
||||
enableBypassCharge(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Mode management methods
|
||||
public int getBypassMode() {
|
||||
return mSharedPrefs.getInt(PREF_BYPASS_MODE, MODE_MANUAL);
|
||||
}
|
||||
|
||||
public void setBypassMode(int mode) {
|
||||
mSharedPrefs.edit().putInt(PREF_BYPASS_MODE, mode).apply();
|
||||
|
||||
// Reset bypass state when changing modes
|
||||
if (mode == MODE_MANUAL) {
|
||||
setManualBypassState(false);
|
||||
}
|
||||
|
||||
// Update bypass state based on new mode
|
||||
updateBypassState();
|
||||
}
|
||||
|
||||
// Battery target methods (for smart mode)
|
||||
public int getBatteryTarget() {
|
||||
return mSharedPrefs.getInt(PREF_BATTERY_TARGET, DEFAULT_BATTERY_TARGET);
|
||||
}
|
||||
|
||||
public void setBatteryTarget(int target) {
|
||||
mSharedPrefs.edit().putInt(PREF_BATTERY_TARGET, target).apply();
|
||||
// Immediately update bypass state if we're in smart mode
|
||||
if (getBypassMode() == MODE_SMART) {
|
||||
updateBypassState();
|
||||
}
|
||||
}
|
||||
|
||||
// Manual bypass state methods
|
||||
public boolean getManualBypassState() {
|
||||
return mSharedPrefs.getBoolean(PREF_MANUAL_BYPASS_STATE, false);
|
||||
}
|
||||
|
||||
public void setManualBypassState(boolean enabled) {
|
||||
mSharedPrefs.edit().putBoolean(PREF_MANUAL_BYPASS_STATE, enabled).apply();
|
||||
if (getBypassMode() == MODE_MANUAL) {
|
||||
updateBypassState();
|
||||
}
|
||||
}
|
||||
|
||||
// Core bypass control methods
|
||||
public boolean isBypassChargeEnabled() {
|
||||
try {
|
||||
String value = FileUtils.readOneLine(BYPASS_CHARGE_NODE);
|
||||
return value != null && value.equals("1");
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to read bypass charge status", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void enableBypassCharge(boolean enable) {
|
||||
try {
|
||||
FileUtils.writeLine(BYPASS_CHARGE_NODE, enable ? "1" : "0");
|
||||
Log.d(TAG, "Bypass charge " + (enable ? "enabled" : "disabled"));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to write bypass charge status", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Support check methods
|
||||
public boolean isNodeAccessible(String node) {
|
||||
try {
|
||||
FileUtils.readOneLine(node);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Node " + node + " not accessible", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBypassChargeSupported() {
|
||||
return isNodeAccessible(BYPASS_CHARGE_NODE);
|
||||
}
|
||||
|
||||
// Main logic for updating bypass state
|
||||
public void updateBypassState() {
|
||||
if (!isMasterToggleEnabled()) {
|
||||
enableBypassCharge(false);
|
||||
return;
|
||||
}
|
||||
|
||||
int mode = getBypassMode();
|
||||
boolean shouldBypass = false;
|
||||
|
||||
switch (mode) {
|
||||
case MODE_MANUAL:
|
||||
shouldBypass = getManualBypassState();
|
||||
break;
|
||||
|
||||
case MODE_SMART:
|
||||
shouldBypass = shouldBypassInSmartMode();
|
||||
break;
|
||||
}
|
||||
|
||||
enableBypassCharge(shouldBypass);
|
||||
}
|
||||
|
||||
// Smart mode logic
|
||||
private boolean shouldBypassInSmartMode() {
|
||||
int currentBattery = getCurrentBatteryLevel();
|
||||
int target = getBatteryTarget();
|
||||
boolean currentlyBypassed = isBypassChargeEnabled();
|
||||
|
||||
if (currentBattery >= target && !currentlyBypassed) {
|
||||
// Enable bypass when we reach target
|
||||
return true;
|
||||
} else if (currentBattery <= (target - BATTERY_HYSTERESIS) && currentlyBypassed) {
|
||||
// Disable bypass when we drop below target minus hysteresis
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keep current state if we're between thresholds
|
||||
return currentlyBypassed;
|
||||
}
|
||||
|
||||
// Battery level helper
|
||||
public int getCurrentBatteryLevel() {
|
||||
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
Intent batteryStatus = mContext.registerReceiver(null, ifilter);
|
||||
|
||||
if (batteryStatus != null) {
|
||||
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
|
||||
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
|
||||
|
||||
if (level != -1 && scale != -1) {
|
||||
return (int) ((level / (float) scale) * 100);
|
||||
}
|
||||
}
|
||||
|
||||
return -1; // Unknown battery level
|
||||
}
|
||||
|
||||
// Charging state helper
|
||||
public boolean isCharging() {
|
||||
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
Intent batteryStatus = mContext.registerReceiver(null, ifilter);
|
||||
|
||||
if (batteryStatus != null) {
|
||||
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
|
||||
return status == BatteryManager.BATTERY_STATUS_CHARGING ||
|
||||
status == BatteryManager.BATTERY_STATUS_FULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Utility methods for external components
|
||||
public String getBypassModeString() {
|
||||
switch (getBypassMode()) {
|
||||
case MODE_MANUAL:
|
||||
return "Manual";
|
||||
case MODE_SMART:
|
||||
return "Smart";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canToggleManually() {
|
||||
return isMasterToggleEnabled() && getBypassMode() == MODE_MANUAL;
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
package org.lineageos.settings.charginginfo
|
||||
|
||||
import org.lineageos.settings.R
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.BatteryManager
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
import android.util.Log
|
||||
import java.io.File
|
||||
import java.util.Timer
|
||||
import java.util.TimerTask
|
||||
|
||||
class ChargingInfoTileService : TileService() {
|
||||
private var updateTimer: Timer? = null
|
||||
private var batteryReceiver: BroadcastReceiver? = null
|
||||
private var isCharging = false
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ChargingTileService"
|
||||
private const val UPDATE_INTERVAL = 2000L // Update every 2 seconds
|
||||
|
||||
// Battery sysfs paths
|
||||
private const val CURRENT_NOW_PATH = "/sys/class/power_supply/battery/current_now"
|
||||
private const val VOLTAGE_NOW_PATH = "/sys/class/power_supply/battery/voltage_now"
|
||||
private const val STATUS_PATH = "/sys/class/power_supply/battery/status"
|
||||
}
|
||||
|
||||
override fun onStartListening() {
|
||||
super.onStartListening()
|
||||
Log.d(TAG, "Tile started listening")
|
||||
|
||||
// Register battery receiver
|
||||
registerBatteryReceiver()
|
||||
|
||||
// Start periodic updates
|
||||
startPeriodicUpdates()
|
||||
|
||||
// Initial update
|
||||
updateTile()
|
||||
}
|
||||
|
||||
override fun onStopListening() {
|
||||
super.onStopListening()
|
||||
Log.d(TAG, "Tile stopped listening")
|
||||
|
||||
// Stop updates
|
||||
stopPeriodicUpdates()
|
||||
|
||||
// Unregister receiver
|
||||
unregisterBatteryReceiver()
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
super.onClick()
|
||||
// Force update when clicked
|
||||
updateTile()
|
||||
}
|
||||
|
||||
private fun registerBatteryReceiver() {
|
||||
if (batteryReceiver == null) {
|
||||
batteryReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
Intent.ACTION_BATTERY_CHANGED,
|
||||
Intent.ACTION_POWER_CONNECTED,
|
||||
Intent.ACTION_POWER_DISCONNECTED -> {
|
||||
updateChargingStatus(intent)
|
||||
updateTile()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filter = IntentFilter().apply {
|
||||
addAction(Intent.ACTION_BATTERY_CHANGED)
|
||||
addAction(Intent.ACTION_POWER_CONNECTED)
|
||||
addAction(Intent.ACTION_POWER_DISCONNECTED)
|
||||
}
|
||||
|
||||
registerReceiver(batteryReceiver, filter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun unregisterBatteryReceiver() {
|
||||
batteryReceiver?.let {
|
||||
try {
|
||||
unregisterReceiver(it)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Log.w(TAG, "Receiver not registered")
|
||||
}
|
||||
batteryReceiver = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun startPeriodicUpdates() {
|
||||
stopPeriodicUpdates()
|
||||
updateTimer = Timer().apply {
|
||||
scheduleAtFixedRate(object : TimerTask() {
|
||||
override fun run() {
|
||||
if (isCharging) {
|
||||
updateTile()
|
||||
}
|
||||
}
|
||||
}, 0, UPDATE_INTERVAL)
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopPeriodicUpdates() {
|
||||
updateTimer?.cancel()
|
||||
updateTimer = null
|
||||
}
|
||||
|
||||
private fun updateChargingStatus(intent: Intent) {
|
||||
val status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1)
|
||||
isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING
|
||||
}
|
||||
|
||||
private fun updateTile() {
|
||||
val tile = qsTile ?: return
|
||||
|
||||
try {
|
||||
val chargingInfo = getChargingInfo()
|
||||
|
||||
tile.apply {
|
||||
when {
|
||||
chargingInfo.isCharging -> {
|
||||
state = Tile.STATE_ACTIVE
|
||||
label = "Charging"
|
||||
subtitle = "${chargingInfo.power}W"
|
||||
contentDescription = "Charging at ${chargingInfo.power}W (${chargingInfo.current}A, ${chargingInfo.voltage}V)"
|
||||
icon = Icon.createWithResource(this@ChargingInfoTileService,
|
||||
R.drawable.ic_charging_speed)
|
||||
}
|
||||
chargingInfo.isDischarging -> {
|
||||
state = Tile.STATE_INACTIVE
|
||||
label = "Discharging"
|
||||
subtitle = "${chargingInfo.power}W"
|
||||
contentDescription = "Discharging at ${chargingInfo.power}W"
|
||||
icon = Icon.createWithResource(this@ChargingInfoTileService,
|
||||
R.drawable.ic_battery_discharge)
|
||||
}
|
||||
else -> {
|
||||
state = Tile.STATE_UNAVAILABLE
|
||||
label = "Not Charging"
|
||||
subtitle = "0W"
|
||||
contentDescription = "Battery not charging or discharging"
|
||||
icon = Icon.createWithResource(this@ChargingInfoTileService,
|
||||
R.drawable.ic_battery_unknown)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tile.updateTile()
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Error updating tile", e)
|
||||
|
||||
// Fallback tile state
|
||||
tile.apply {
|
||||
state = Tile.STATE_UNAVAILABLE
|
||||
label = "Error"
|
||||
subtitle = "N/A"
|
||||
contentDescription = "Unable to read charging information"
|
||||
icon = Icon.createWithResource(this@ChargingInfoTileService,
|
||||
R.drawable.ic_error)
|
||||
}
|
||||
tile.updateTile()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getChargingInfo(): ChargingInfo {
|
||||
val currentNow = readSysfsValue(CURRENT_NOW_PATH)
|
||||
val voltageNow = readSysfsValue(VOLTAGE_NOW_PATH)
|
||||
val status = readSysfsString(STATUS_PATH)
|
||||
|
||||
// Convert from milliamps to amps and microvolts to volts
|
||||
val currentA = currentNow / 1000.0 // mA → A
|
||||
val voltageV = voltageNow / 1000000.0 // µV → V
|
||||
|
||||
// Calculate power in watts
|
||||
val powerW = Math.abs(currentA * voltageV)
|
||||
|
||||
val isCharging = status.equals("Charging", ignoreCase = true) && currentNow > 0
|
||||
val isDischarging = currentNow < 0
|
||||
|
||||
return ChargingInfo(
|
||||
current = String.format("%.1f", Math.abs(currentA)),
|
||||
voltage = String.format("%.1f", voltageV),
|
||||
power = String.format("%.1f", powerW),
|
||||
isCharging = isCharging,
|
||||
isDischarging = isDischarging
|
||||
)
|
||||
}
|
||||
|
||||
private fun readSysfsValue(path: String): Long {
|
||||
return try {
|
||||
File(path).readText().trim().toLong()
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Failed to read $path", e)
|
||||
0L
|
||||
}
|
||||
}
|
||||
|
||||
private fun readSysfsString(path: String): String {
|
||||
return try {
|
||||
File(path).readText().trim()
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Failed to read $path", e)
|
||||
"Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
data class ChargingInfo(
|
||||
val current: String,
|
||||
val voltage: String,
|
||||
val power: String,
|
||||
val isCharging: Boolean,
|
||||
val isDischarging: Boolean
|
||||
)
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package org.lineageos.settings.charge;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import androidx.preference.SeekBarPreference;
|
||||
|
||||
public class MinMaxSeekBarPreference extends SeekBarPreference {
|
||||
private static final String TAG = "MinMaxSeekBarPreference";
|
||||
|
||||
private int mMinValue = 0;
|
||||
private int mMaxValue = 100;
|
||||
|
||||
public MinMaxSeekBarPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
// Get min/max values from XML attributes
|
||||
if (attrs != null) {
|
||||
for (int i = 0; i < attrs.getAttributeCount(); i++) {
|
||||
String attrName = attrs.getAttributeName(i);
|
||||
if ("min".equals(attrName)) {
|
||||
mMinValue = attrs.getAttributeIntValue(i, 0);
|
||||
} else if ("max".equals(attrName)) {
|
||||
mMaxValue = attrs.getAttributeIntValue(i, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the SeekBar to use full 0-100 range for UI, but map values internally
|
||||
setMin(0);
|
||||
setMax(100);
|
||||
|
||||
Log.d(TAG, "MinMaxSeekBarPreference initialized - Min: " + mMinValue + ", Max: " + mMaxValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetInitialValue(Object defaultValue) {
|
||||
int value = defaultValue == null ? 80 : (Integer) defaultValue;
|
||||
// Ensure value is within bounds
|
||||
value = Math.max(mMinValue, Math.min(mMaxValue, value));
|
||||
|
||||
// Convert the actual battery target value to slider position
|
||||
int sliderPosition = valueToSliderPosition(value);
|
||||
super.setValue(sliderPosition);
|
||||
|
||||
Log.i(TAG, "Battery target initial value set: " + value + "% (Slider position: " + sliderPosition + "%)");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object onGetDefaultValue(TypedArray a, int index) {
|
||||
int defaultValue = a.getInt(index, 80);
|
||||
Log.d(TAG, "Getting default battery target value: " + defaultValue + "%");
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(int seekBarValue) {
|
||||
// seekBarValue here is the slider position (0-100)
|
||||
// Just store it as-is since the slider represents the UI position
|
||||
super.setValue(seekBarValue);
|
||||
|
||||
// Calculate and log the actual mapped battery target
|
||||
int mappedValue = sliderPositionToValue(seekBarValue);
|
||||
Log.i(TAG, "Battery target changed - Slider: " + seekBarValue + "%, Actual target: " + mappedValue + "% (Range: " + mMinValue + "-" + mMaxValue + "%)");
|
||||
}
|
||||
|
||||
// Convert slider position (0-100) to actual battery target value
|
||||
private int sliderPositionToValue(int sliderPosition) {
|
||||
return mMinValue + ((sliderPosition * (mMaxValue - mMinValue)) / 100);
|
||||
}
|
||||
|
||||
// Convert actual battery target value to slider position (0-100)
|
||||
private int valueToSliderPosition(int value) {
|
||||
if (mMaxValue == mMinValue) return 0; // Avoid division by zero
|
||||
return ((value - mMinValue) * 100) / (mMaxValue - mMinValue);
|
||||
}
|
||||
|
||||
// Get the actual mapped battery target value
|
||||
public int getBatteryTarget() {
|
||||
int sliderValue = getValue();
|
||||
return sliderPositionToValue(sliderValue);
|
||||
}
|
||||
|
||||
// Set the battery target value (converts to appropriate slider position)
|
||||
public void setBatteryTarget(int targetValue) {
|
||||
targetValue = Math.max(mMinValue, Math.min(mMaxValue, targetValue));
|
||||
int sliderPosition = valueToSliderPosition(targetValue);
|
||||
setValue(sliderPosition);
|
||||
}
|
||||
|
||||
// Calculate battery target from a given slider position (used during preference change)
|
||||
public int calculateBatteryTargetFromSlider(int sliderPosition) {
|
||||
return sliderPositionToValue(sliderPosition);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
public class ForegroundAppDetector {
|
||||
|
||||
private static final String TAG = "ForegroundAppDetector";
|
||||
|
||||
public static String getForegroundPackageName(Context context) {
|
||||
|
||||
String pkg = tryGetRunningTasks(context);
|
||||
if (pkg != null) {
|
||||
return pkg;
|
||||
}
|
||||
pkg = tryReflectActivityTaskManager();
|
||||
if (pkg != null) {
|
||||
return pkg;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
private static String tryGetRunningTasks(Context context) {
|
||||
try {
|
||||
if (context.checkSelfPermission("android.permission.GET_TASKS")
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
|
||||
if (tasks != null && !tasks.isEmpty()) {
|
||||
ActivityManager.RunningTaskInfo top = tasks.get(0);
|
||||
if (top.topActivity != null) {
|
||||
return top.topActivity.getPackageName();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "GET_TASKS permission not granted to this system app?");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "tryGetRunningTasks error: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String tryReflectActivityTaskManager() {
|
||||
try {
|
||||
Class<?> atmClass = Class.forName("android.app.ActivityTaskManager");
|
||||
Method getServiceMethod = atmClass.getDeclaredMethod("getService");
|
||||
getServiceMethod.setAccessible(true);
|
||||
Object atmService = getServiceMethod.invoke(null);
|
||||
Method getTasksMethod = atmService.getClass().getMethod("getTasks", int.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<?> taskList = (List<?>) getTasksMethod.invoke(atmService, 1);
|
||||
if (taskList != null && !taskList.isEmpty()) {
|
||||
|
||||
Object firstTask = taskList.get(0);
|
||||
|
||||
Class<?> rtiClass = firstTask.getClass();
|
||||
Method getTopActivityMethod = rtiClass.getDeclaredMethod("getTopActivity");
|
||||
Object compName = getTopActivityMethod.invoke(firstTask);
|
||||
if (compName != null) {
|
||||
|
||||
Method getPackageNameMethod = compName.getClass().getMethod("getPackageName");
|
||||
String pkgName = (String) getPackageNameMethod.invoke(compName);
|
||||
return pkgName;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "tryReflectActivityTaskManager error: ", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,774 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.util.TypedValue;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class GameBar {
|
||||
|
||||
private static GameBar sInstance;
|
||||
public static synchronized GameBar getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new GameBar(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private static final String FPS_PATH = "/sys/class/drm/sde-crtc-0/measured_fps";
|
||||
private static final String BATTERY_TEMP_PATH= "/sys/class/thermal/thermal_zone78/temp";
|
||||
|
||||
private static final String PREF_KEY_X = "game_bar_x";
|
||||
private static final String PREF_KEY_Y = "game_bar_y";
|
||||
|
||||
private final Context mContext;
|
||||
private final WindowManager mWindowManager;
|
||||
private final Handler mHandler;
|
||||
|
||||
private View mOverlayView;
|
||||
private LinearLayout mRootLayout;
|
||||
private WindowManager.LayoutParams mLayoutParams;
|
||||
private boolean mIsShowing = false;
|
||||
|
||||
private int mTextSizeSp = 16;
|
||||
private int mBackgroundAlpha = 128;
|
||||
private int mCornerRadius = 16;
|
||||
private int mPaddingDp = 12;
|
||||
private String mTitleColorHex = "#FFFFFF";
|
||||
private String mValueColorHex = "#FFFFFF";
|
||||
private String mOverlayFormat = "full";
|
||||
private String mPosition = "top_left";
|
||||
private String mSplitMode = "stacked";
|
||||
private int mUpdateIntervalMs = 1000;
|
||||
private boolean mDraggable = false;
|
||||
|
||||
private boolean mShowBatteryTemp = false;
|
||||
private boolean mShowCpuUsage = false;
|
||||
private boolean mShowCpuClock = false;
|
||||
private boolean mShowCpuTemp = false;
|
||||
private boolean mShowRam = false;
|
||||
private boolean mShowFps = false;
|
||||
|
||||
private boolean mShowGpuUsage = false;
|
||||
private boolean mShowGpuClock = false;
|
||||
private boolean mShowGpuTemp = false;
|
||||
|
||||
private boolean mLongPressEnabled = false;
|
||||
private long mLongPressThresholdMs = 1000;
|
||||
private boolean mPressActive = false;
|
||||
private float mDownX, mDownY;
|
||||
private static final float TOUCH_SLOP = 20f;
|
||||
|
||||
private GestureDetector mGestureDetector;
|
||||
private boolean mDoubleTapCaptureEnabled = false;
|
||||
private boolean mSingleTapToggleEnabled = false;
|
||||
private GradientDrawable mBgDrawable;
|
||||
|
||||
private int mItemSpacingDp = 8;
|
||||
|
||||
private final Runnable mLongPressRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mPressActive) {
|
||||
openOverlaySettings();
|
||||
mPressActive = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mUpdateRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mIsShowing) {
|
||||
updateStats();
|
||||
mHandler.postDelayed(this, mUpdateIntervalMs);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private GameBar(Context context) {
|
||||
mContext = context;
|
||||
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
mBgDrawable = new GradientDrawable();
|
||||
applyBackgroundStyle();
|
||||
|
||||
mGestureDetector = new GestureDetector(mContext, new GestureDetector.SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onDoubleTap(MotionEvent e) {
|
||||
if (mDoubleTapCaptureEnabled) {
|
||||
if (GameDataExport.getInstance().isCapturing()) {
|
||||
GameDataExport.getInstance().stopCapture();
|
||||
Toast.makeText(mContext, "Capture Stopped", Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
GameDataExport.getInstance().startCapture();
|
||||
Toast.makeText(mContext, "Capture Started", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return super.onDoubleTap(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||
if (mSingleTapToggleEnabled) {
|
||||
mOverlayFormat = "full".equals(mOverlayFormat) ? "minimal" : "full";
|
||||
PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||
.edit()
|
||||
.putString("game_bar_format", mOverlayFormat)
|
||||
.apply();
|
||||
Toast.makeText(mContext, "Overlay Format: " + mOverlayFormat, Toast.LENGTH_SHORT).show();
|
||||
updateStats();
|
||||
return true;
|
||||
}
|
||||
return super.onSingleTapConfirmed(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void applyPreferences() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
|
||||
mShowFps = prefs.getBoolean("game_bar_fps_enable", false);
|
||||
mShowBatteryTemp = prefs.getBoolean("game_bar_temp_enable", false);
|
||||
mShowCpuUsage = prefs.getBoolean("game_bar_cpu_usage_enable", false);
|
||||
mShowCpuClock = prefs.getBoolean("game_bar_cpu_clock_enable", false);
|
||||
mShowCpuTemp = prefs.getBoolean("game_bar_cpu_temp_enable", false);
|
||||
mShowRam = prefs.getBoolean("game_bar_ram_enable", false);
|
||||
|
||||
mShowGpuUsage = prefs.getBoolean("game_bar_gpu_usage_enable", false);
|
||||
mShowGpuClock = prefs.getBoolean("game_bar_gpu_clock_enable", false);
|
||||
mShowGpuTemp = prefs.getBoolean("game_bar_gpu_temp_enable", false);
|
||||
|
||||
mDoubleTapCaptureEnabled = prefs.getBoolean("game_bar_doubletap_capture", false);
|
||||
mSingleTapToggleEnabled = prefs.getBoolean("game_bar_single_tap_toggle", false);
|
||||
|
||||
updateSplitMode(prefs.getString("game_bar_split_mode", "stacked"));
|
||||
updateTextSize(prefs.getInt("game_bar_text_size", 16));
|
||||
updateBackgroundAlpha(prefs.getInt("game_bar_background_alpha", 128));
|
||||
updateCornerRadius(prefs.getInt("game_bar_corner_radius", 16));
|
||||
updatePadding(prefs.getInt("game_bar_padding", 12));
|
||||
updateTitleColor(prefs.getString("game_bar_title_color", "#FFFFFF"));
|
||||
updateValueColor(prefs.getString("game_bar_value_color", "#4CAF50"));
|
||||
updateOverlayFormat(prefs.getString("game_bar_format", "full"));
|
||||
updateUpdateInterval(prefs.getString("game_bar_update_interval", "1000"));
|
||||
updatePosition(prefs.getString("game_bar_position", "top_left"));
|
||||
|
||||
int spacing = prefs.getInt("game_bar_item_spacing", 8);
|
||||
updateItemSpacing(spacing);
|
||||
|
||||
mLongPressEnabled = prefs.getBoolean("game_bar_longpress_enable", false);
|
||||
String lpTimeoutStr = prefs.getString("game_bar_longpress_timeout", "1000");
|
||||
try {
|
||||
long lpt = Long.parseLong(lpTimeoutStr);
|
||||
setLongPressThresholdMs(lpt);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (mIsShowing) return;
|
||||
|
||||
applyPreferences();
|
||||
|
||||
mLayoutParams = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||||
PixelFormat.TRANSLUCENT
|
||||
);
|
||||
|
||||
if ("draggable".equals(mPosition)) {
|
||||
mDraggable = true;
|
||||
loadSavedPosition(mLayoutParams);
|
||||
if (mLayoutParams.x == 0 && mLayoutParams.y == 0) {
|
||||
mLayoutParams.gravity = Gravity.TOP | Gravity.START;
|
||||
mLayoutParams.x = 0;
|
||||
mLayoutParams.y = 100;
|
||||
}
|
||||
} else {
|
||||
mDraggable = false;
|
||||
applyPosition(mLayoutParams, mPosition);
|
||||
}
|
||||
|
||||
mOverlayView = new LinearLayout(mContext);
|
||||
mOverlayView.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
));
|
||||
mRootLayout = (LinearLayout) mOverlayView;
|
||||
applySplitMode();
|
||||
applyBackgroundStyle();
|
||||
applyPadding();
|
||||
|
||||
mOverlayView.setOnTouchListener((v, event) -> {
|
||||
if (mGestureDetector != null && mGestureDetector.onTouchEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (mDraggable) {
|
||||
initialX = mLayoutParams.x;
|
||||
initialY = mLayoutParams.y;
|
||||
initialTouchX = event.getRawX();
|
||||
initialTouchY = event.getRawY();
|
||||
}
|
||||
if (mLongPressEnabled) {
|
||||
mPressActive = true;
|
||||
mDownX = event.getRawX();
|
||||
mDownY = event.getRawY();
|
||||
mHandler.postDelayed(mLongPressRunnable, mLongPressThresholdMs);
|
||||
}
|
||||
return true;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mLongPressEnabled && mPressActive) {
|
||||
float dx = Math.abs(event.getRawX() - mDownX);
|
||||
float dy = Math.abs(event.getRawY() - mDownY);
|
||||
if (dx > TOUCH_SLOP || dy > TOUCH_SLOP) {
|
||||
mPressActive = false;
|
||||
mHandler.removeCallbacks(mLongPressRunnable);
|
||||
}
|
||||
}
|
||||
if (mDraggable) {
|
||||
int deltaX = (int) (event.getRawX() - initialTouchX);
|
||||
int deltaY = (int) (event.getRawY() - initialTouchY);
|
||||
mLayoutParams.x = initialX + deltaX;
|
||||
mLayoutParams.y = initialY + deltaY;
|
||||
mWindowManager.updateViewLayout(mOverlayView, mLayoutParams);
|
||||
}
|
||||
return true;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (mLongPressEnabled && mPressActive) {
|
||||
mPressActive = false;
|
||||
mHandler.removeCallbacks(mLongPressRunnable);
|
||||
}
|
||||
if (mDraggable) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
prefs.edit()
|
||||
.putInt(PREF_KEY_X, mLayoutParams.x)
|
||||
.putInt(PREF_KEY_Y, mLayoutParams.y)
|
||||
.apply();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
mWindowManager.addView(mOverlayView, mLayoutParams);
|
||||
mIsShowing = true;
|
||||
startUpdates();
|
||||
|
||||
// Start the FPS meter if using the new API method.
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||
GameBarFpsMeter.getInstance(mContext).start();
|
||||
}
|
||||
}
|
||||
|
||||
private int initialX, initialY;
|
||||
private float initialTouchX, initialTouchY;
|
||||
|
||||
public void hide() {
|
||||
if (!mIsShowing) return;
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
if (mOverlayView != null) {
|
||||
mWindowManager.removeView(mOverlayView);
|
||||
mOverlayView = null;
|
||||
}
|
||||
mIsShowing = false;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||
GameBarFpsMeter.getInstance(mContext).stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateStats() {
|
||||
if (!mIsShowing || mRootLayout == null) return;
|
||||
|
||||
mRootLayout.removeAllViews();
|
||||
|
||||
List<View> statViews = new ArrayList<>();
|
||||
|
||||
// 1) FPS
|
||||
float fpsVal = GameBarFpsMeter.getInstance(mContext).getFps();
|
||||
String fpsStr = fpsVal >= 0 ? String.format(Locale.getDefault(), "%.0f", fpsVal) : "N/A";
|
||||
if (mShowFps) {
|
||||
statViews.add(createStatLine("FPS", fpsStr));
|
||||
}
|
||||
|
||||
// 2) Battery temp
|
||||
String batteryTempStr = "N/A";
|
||||
if (mShowBatteryTemp) {
|
||||
String tmp = readLine(BATTERY_TEMP_PATH);
|
||||
if (tmp != null && !tmp.isEmpty()) {
|
||||
try {
|
||||
int raw = Integer.parseInt(tmp.trim());
|
||||
float c = raw / 1000f;
|
||||
batteryTempStr = String.format(Locale.getDefault(), "%.1f", c);
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
statViews.add(createStatLine("Temp", batteryTempStr + "°C"));
|
||||
}
|
||||
|
||||
// 3) CPU usage
|
||||
String cpuUsageStr = "N/A";
|
||||
if (mShowCpuUsage) {
|
||||
cpuUsageStr = GameBarCpuInfo.getCpuUsage();
|
||||
String display = "N/A".equals(cpuUsageStr) ? "N/A" : cpuUsageStr + "%";
|
||||
statViews.add(createStatLine("CPU", display));
|
||||
}
|
||||
|
||||
// 4) CPU freq
|
||||
if (mShowCpuClock) {
|
||||
List<String> freqs = GameBarCpuInfo.getCpuFrequencies();
|
||||
if (!freqs.isEmpty()) {
|
||||
statViews.add(buildCpuFreqView(freqs));
|
||||
}
|
||||
}
|
||||
|
||||
// 5) CPU temp
|
||||
String cpuTempStr = "N/A";
|
||||
if (mShowCpuTemp) {
|
||||
cpuTempStr = GameBarCpuInfo.getCpuTemp();
|
||||
statViews.add(createStatLine("CPU Temp", "N/A".equals(cpuTempStr) ? "N/A" : cpuTempStr + "°C"));
|
||||
}
|
||||
|
||||
// 6) RAM usage
|
||||
String ramStr = "N/A";
|
||||
if (mShowRam) {
|
||||
ramStr = GameBarMemInfo.getRamUsage();
|
||||
statViews.add(createStatLine("RAM", "N/A".equals(ramStr) ? "N/A" : ramStr + " MB"));
|
||||
}
|
||||
|
||||
// 7) GPU usage
|
||||
String gpuUsageStr = "N/A";
|
||||
if (mShowGpuUsage) {
|
||||
gpuUsageStr = GameBarGpuInfo.getGpuUsage();
|
||||
statViews.add(createStatLine("GPU", "N/A".equals(gpuUsageStr) ? "N/A" : gpuUsageStr + "%"));
|
||||
}
|
||||
|
||||
// 8) GPU clock
|
||||
String gpuClockStr = "N/A";
|
||||
if (mShowGpuClock) {
|
||||
gpuClockStr = GameBarGpuInfo.getGpuClock();
|
||||
statViews.add(createStatLine("GPU Freq", "N/A".equals(gpuClockStr) ? "N/A" : gpuClockStr + "MHz"));
|
||||
}
|
||||
|
||||
// 9) GPU temp
|
||||
String gpuTempStr = "N/A";
|
||||
if (mShowGpuTemp) {
|
||||
gpuTempStr = GameBarGpuInfo.getGpuTemp();
|
||||
statViews.add(createStatLine("GPU Temp", "N/A".equals(gpuTempStr) ? "N/A" : gpuTempStr + "°C"));
|
||||
}
|
||||
|
||||
if ("side_by_side".equals(mSplitMode)) {
|
||||
mRootLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
if ("minimal".equals(mOverlayFormat)) {
|
||||
for (int i = 0; i < statViews.size(); i++) {
|
||||
mRootLayout.addView(statViews.get(i));
|
||||
if (i < statViews.size() - 1) {
|
||||
mRootLayout.addView(createDotView());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (View view : statViews) {
|
||||
mRootLayout.addView(view);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mRootLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
for (View view : statViews) {
|
||||
mRootLayout.addView(view);
|
||||
}
|
||||
}
|
||||
|
||||
if (GameDataExport.getInstance().isCapturing()) {
|
||||
String dateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date());
|
||||
String pkgName = ForegroundAppDetector.getForegroundPackageName(mContext);
|
||||
|
||||
GameDataExport.getInstance().addOverlayData(
|
||||
dateTime,
|
||||
pkgName,
|
||||
fpsStr,
|
||||
batteryTempStr,
|
||||
cpuUsageStr,
|
||||
cpuTempStr,
|
||||
gpuUsageStr,
|
||||
gpuClockStr,
|
||||
gpuTempStr
|
||||
);
|
||||
}
|
||||
|
||||
if (mLayoutParams != null) {
|
||||
mWindowManager.updateViewLayout(mOverlayView, mLayoutParams);
|
||||
}
|
||||
}
|
||||
|
||||
private View buildCpuFreqView(List<String> freqs) {
|
||||
LinearLayout freqContainer = new LinearLayout(mContext);
|
||||
freqContainer.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
int spacingPx = dpToPx(mContext, mItemSpacingDp);
|
||||
LinearLayout.LayoutParams outerLp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
outerLp.setMargins(spacingPx, spacingPx / 2, spacingPx, spacingPx / 2);
|
||||
freqContainer.setLayoutParams(outerLp);
|
||||
|
||||
if ("full".equals(mOverlayFormat)) {
|
||||
TextView labelTv = new TextView(mContext);
|
||||
labelTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||
try {
|
||||
labelTv.setTextColor(Color.parseColor(mTitleColorHex));
|
||||
} catch (Exception e) {
|
||||
labelTv.setTextColor(Color.WHITE);
|
||||
}
|
||||
labelTv.setText("CPU Freq ");
|
||||
freqContainer.addView(labelTv);
|
||||
}
|
||||
|
||||
LinearLayout verticalFreqs = new LinearLayout(mContext);
|
||||
verticalFreqs.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
for (String freqLine : freqs) {
|
||||
LinearLayout lineLayout = new LinearLayout(mContext);
|
||||
lineLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
TextView freqTv = new TextView(mContext);
|
||||
freqTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||
try {
|
||||
freqTv.setTextColor(Color.parseColor(mValueColorHex));
|
||||
} catch (Exception e) {
|
||||
freqTv.setTextColor(Color.WHITE);
|
||||
}
|
||||
freqTv.setText(freqLine);
|
||||
|
||||
lineLayout.addView(freqTv);
|
||||
|
||||
LinearLayout.LayoutParams lineLp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
lineLp.setMargins(spacingPx, spacingPx / 4, spacingPx, spacingPx / 4);
|
||||
lineLayout.setLayoutParams(lineLp);
|
||||
|
||||
verticalFreqs.addView(lineLayout);
|
||||
}
|
||||
|
||||
freqContainer.addView(verticalFreqs);
|
||||
return freqContainer;
|
||||
}
|
||||
|
||||
private LinearLayout createStatLine(String title, String rawValue) {
|
||||
LinearLayout lineLayout = new LinearLayout(mContext);
|
||||
lineLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
|
||||
if ("full".equals(mOverlayFormat)) {
|
||||
TextView tvTitle = new TextView(mContext);
|
||||
tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||
try {
|
||||
tvTitle.setTextColor(Color.parseColor(mTitleColorHex));
|
||||
} catch (Exception e) {
|
||||
tvTitle.setTextColor(Color.WHITE);
|
||||
}
|
||||
tvTitle.setText(title.isEmpty() ? "" : title + " ");
|
||||
|
||||
TextView tvValue = new TextView(mContext);
|
||||
tvValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||
try {
|
||||
tvValue.setTextColor(Color.parseColor(mValueColorHex));
|
||||
} catch (Exception e) {
|
||||
tvValue.setTextColor(Color.WHITE);
|
||||
}
|
||||
tvValue.setText(rawValue);
|
||||
|
||||
lineLayout.addView(tvTitle);
|
||||
lineLayout.addView(tvValue);
|
||||
} else {
|
||||
TextView tvMinimal = new TextView(mContext);
|
||||
tvMinimal.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||
try {
|
||||
tvMinimal.setTextColor(Color.parseColor(mValueColorHex));
|
||||
} catch (Exception e) {
|
||||
tvMinimal.setTextColor(Color.WHITE);
|
||||
}
|
||||
tvMinimal.setText(rawValue);
|
||||
lineLayout.addView(tvMinimal);
|
||||
}
|
||||
|
||||
int spacingPx = dpToPx(mContext, mItemSpacingDp);
|
||||
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
lp.setMargins(spacingPx, spacingPx / 2, spacingPx, spacingPx / 2);
|
||||
lineLayout.setLayoutParams(lp);
|
||||
|
||||
return lineLayout;
|
||||
}
|
||||
|
||||
private View createDotView() {
|
||||
TextView dotView = new TextView(mContext);
|
||||
dotView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||
try {
|
||||
dotView.setTextColor(Color.parseColor(mValueColorHex));
|
||||
} catch (Exception e) {
|
||||
dotView.setTextColor(Color.WHITE);
|
||||
}
|
||||
dotView.setText(" . ");
|
||||
return dotView;
|
||||
}
|
||||
|
||||
public void setShowBatteryTemp(boolean show) { mShowBatteryTemp = show; }
|
||||
public void setShowCpuUsage(boolean show) { mShowCpuUsage = show; }
|
||||
public void setShowCpuClock(boolean show) { mShowCpuClock = show; }
|
||||
public void setShowCpuTemp(boolean show) { mShowCpuTemp = show; }
|
||||
public void setShowRam(boolean show) { mShowRam = show; }
|
||||
public void setShowFps(boolean show) { mShowFps = show; }
|
||||
|
||||
public void setShowGpuUsage(boolean show) { mShowGpuUsage = show; }
|
||||
public void setShowGpuClock(boolean show) { mShowGpuClock = show; }
|
||||
public void setShowGpuTemp(boolean show) { mShowGpuTemp = show; }
|
||||
|
||||
public void updateTextSize(int sp) {
|
||||
mTextSizeSp = sp;
|
||||
}
|
||||
|
||||
public void updateCornerRadius(int radius) {
|
||||
mCornerRadius = radius;
|
||||
applyBackgroundStyle();
|
||||
}
|
||||
|
||||
public void updateBackgroundAlpha(int alpha) {
|
||||
mBackgroundAlpha = alpha;
|
||||
applyBackgroundStyle();
|
||||
}
|
||||
|
||||
public void updatePadding(int dp) {
|
||||
mPaddingDp = dp;
|
||||
applyPadding();
|
||||
}
|
||||
|
||||
public void updateTitleColor(String hex) {
|
||||
mTitleColorHex = hex;
|
||||
}
|
||||
|
||||
public void updateValueColor(String hex) {
|
||||
mValueColorHex = hex;
|
||||
}
|
||||
|
||||
public void updateOverlayFormat(String format) {
|
||||
mOverlayFormat = format;
|
||||
if (mIsShowing) {
|
||||
updateStats();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateItemSpacing(int dp) {
|
||||
mItemSpacingDp = dp;
|
||||
if (mIsShowing) {
|
||||
updateStats();
|
||||
}
|
||||
}
|
||||
|
||||
private void applyBackgroundStyle() {
|
||||
int color = Color.argb(mBackgroundAlpha, 0, 0, 0);
|
||||
mBgDrawable.setColor(color);
|
||||
mBgDrawable.setCornerRadius(mCornerRadius);
|
||||
|
||||
if (mOverlayView != null) {
|
||||
mOverlayView.setBackground(mBgDrawable);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPadding() {
|
||||
if (mRootLayout != null) {
|
||||
int px = dpToPx(mContext, mPaddingDp);
|
||||
mRootLayout.setPadding(px, px, px, px);
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePosition(String pos) {
|
||||
mPosition = pos;
|
||||
if (mIsShowing && mOverlayView != null && mLayoutParams != null) {
|
||||
if ("draggable".equals(mPosition)) {
|
||||
mDraggable = true;
|
||||
loadSavedPosition(mLayoutParams);
|
||||
if (mLayoutParams.x == 0 && mLayoutParams.y == 0) {
|
||||
mLayoutParams.gravity = Gravity.TOP | Gravity.START;
|
||||
mLayoutParams.x = 0;
|
||||
mLayoutParams.y = 100;
|
||||
}
|
||||
} else {
|
||||
mDraggable = false;
|
||||
applyPosition(mLayoutParams, mPosition);
|
||||
}
|
||||
mWindowManager.updateViewLayout(mOverlayView, mLayoutParams);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSplitMode(String mode) {
|
||||
mSplitMode = mode;
|
||||
if (mIsShowing && mOverlayView != null) {
|
||||
applySplitMode();
|
||||
updateStats();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateUpdateInterval(String intervalStr) {
|
||||
try {
|
||||
mUpdateIntervalMs = Integer.parseInt(intervalStr);
|
||||
} catch (NumberFormatException e) {
|
||||
mUpdateIntervalMs = 1000;
|
||||
}
|
||||
if (mIsShowing) {
|
||||
startUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
public void setLongPressEnabled(boolean enabled) {
|
||||
mLongPressEnabled = enabled;
|
||||
}
|
||||
public void setLongPressThresholdMs(long ms) {
|
||||
mLongPressThresholdMs = ms;
|
||||
}
|
||||
|
||||
public void setDoubleTapCaptureEnabled(boolean enabled) {
|
||||
mDoubleTapCaptureEnabled = enabled;
|
||||
}
|
||||
|
||||
public void setSingleTapToggleEnabled(boolean enabled) {
|
||||
mSingleTapToggleEnabled = enabled;
|
||||
}
|
||||
|
||||
private void startUpdates() {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
mHandler.post(mUpdateRunnable);
|
||||
}
|
||||
|
||||
private void applySplitMode() {
|
||||
if (mRootLayout == null) return;
|
||||
if ("side_by_side".equals(mSplitMode)) {
|
||||
mRootLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
} else {
|
||||
mRootLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSavedPosition(WindowManager.LayoutParams lp) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
int savedX = prefs.getInt(PREF_KEY_X, Integer.MIN_VALUE);
|
||||
int savedY = prefs.getInt(PREF_KEY_Y, Integer.MIN_VALUE);
|
||||
if (savedX != Integer.MIN_VALUE && savedY != Integer.MIN_VALUE) {
|
||||
lp.gravity = Gravity.TOP | Gravity.START;
|
||||
lp.x = savedX;
|
||||
lp.y = savedY;
|
||||
}
|
||||
}
|
||||
|
||||
private void applyPosition(WindowManager.LayoutParams lp, String pos) {
|
||||
switch (pos) {
|
||||
case "top_left":
|
||||
lp.gravity = Gravity.TOP | Gravity.START;
|
||||
lp.x = 0;
|
||||
lp.y = 100;
|
||||
break;
|
||||
case "top_center":
|
||||
lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
|
||||
lp.y = 100;
|
||||
break;
|
||||
case "top_right":
|
||||
lp.gravity = Gravity.TOP | Gravity.END;
|
||||
lp.x = 0;
|
||||
lp.y = 100;
|
||||
break;
|
||||
case "bottom_left":
|
||||
lp.gravity = Gravity.BOTTOM | Gravity.START;
|
||||
lp.x = 0;
|
||||
lp.y = 100;
|
||||
break;
|
||||
case "bottom_center":
|
||||
lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
|
||||
lp.y = 100;
|
||||
break;
|
||||
case "bottom_right":
|
||||
lp.gravity = Gravity.BOTTOM | Gravity.END;
|
||||
lp.x = 0;
|
||||
lp.y = 100;
|
||||
break;
|
||||
default:
|
||||
lp.gravity = Gravity.TOP | Gravity.START;
|
||||
lp.x = 0;
|
||||
lp.y = 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private String readLine(String path) {
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
|
||||
return br.readLine();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void openOverlaySettings() {
|
||||
try {
|
||||
Intent intent = new Intent(mContext, GameBarSettingsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
// Exception ignored
|
||||
}
|
||||
}
|
||||
|
||||
private static int dpToPx(Context context, int dp) {
|
||||
float scale = context.getResources().getDisplayMetrics().density;
|
||||
return Math.round(dp * scale);
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class GameBarAppRemoverActivity extends CollapsingToolbarBaseActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_game_bar_app_selector);
|
||||
setTitle("Remove Auto-Enable Apps");
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.content_frame, new GameBarAppRemoverFragment())
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
import org.lineageos.settings.R;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class GameBarAppRemoverFragment extends Fragment {
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
private GameBarAutoAppsAdapter adapter;
|
||||
private PackageManager packageManager;
|
||||
private List<ApplicationInfo> autoAppsList;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.game_bar_app_selector, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
recyclerView = view.findViewById(R.id.app_list);
|
||||
packageManager = getContext().getPackageManager();
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
loadAutoApps();
|
||||
}
|
||||
|
||||
private void loadAutoApps() {
|
||||
Set<String> autoAppsSet = getSavedAutoApps();
|
||||
autoAppsList = new ArrayList<>();
|
||||
for (String pkg : autoAppsSet) {
|
||||
try {
|
||||
ApplicationInfo info = packageManager.getApplicationInfo(pkg, 0);
|
||||
autoAppsList.add(info);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
}
|
||||
}
|
||||
adapter = new GameBarAutoAppsAdapter(packageManager, autoAppsList, new GameBarAutoAppsAdapter.OnAppRemoveListener() {
|
||||
@Override
|
||||
public void onAppRemove(ApplicationInfo appInfo) {
|
||||
removeAppFromAutoList(appInfo.packageName);
|
||||
Toast.makeText(getContext(), appInfo.loadLabel(packageManager) + " removed.", Toast.LENGTH_SHORT).show();
|
||||
autoAppsList.remove(appInfo);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private Set<String> getSavedAutoApps() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||
.getStringSet(GameBarAppSelectorFragment.PREF_AUTO_APPS, new HashSet<>());
|
||||
}
|
||||
|
||||
private void removeAppFromAutoList(String packageName) {
|
||||
Set<String> autoApps = new HashSet<>(getSavedAutoApps());
|
||||
autoApps.remove(packageName);
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||
.edit().putStringSet(GameBarAppSelectorFragment.PREF_AUTO_APPS, autoApps).apply();
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class GameBarAppSelectorActivity extends CollapsingToolbarBaseActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_game_bar_app_selector);
|
||||
setTitle("Select Apps for GameBar");
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.content_frame, new GameBarAppSelectorFragment())
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
import org.lineageos.settings.R;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class GameBarAppSelectorFragment extends Fragment {
|
||||
|
||||
public static final String PREF_AUTO_APPS = "game_bar_auto_apps";
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
private GameBarAppsAdapter adapter;
|
||||
private PackageManager packageManager;
|
||||
private List<ApplicationInfo> allApps;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.game_bar_app_selector, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
recyclerView = view.findViewById(R.id.app_list);
|
||||
packageManager = getContext().getPackageManager();
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
loadApps();
|
||||
}
|
||||
|
||||
private void loadApps() {
|
||||
allApps = new ArrayList<>();
|
||||
List<ApplicationInfo> installedApps = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||
Set<String> autoApps = getSavedAutoApps();
|
||||
for (ApplicationInfo appInfo : installedApps) {
|
||||
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 &&
|
||||
!appInfo.packageName.equals(getContext().getPackageName()) &&
|
||||
!autoApps.contains(appInfo.packageName)) {
|
||||
allApps.add(appInfo);
|
||||
}
|
||||
}
|
||||
adapter = new GameBarAppsAdapter(packageManager, allApps, new GameBarAppsAdapter.OnAppClickListener() {
|
||||
@Override
|
||||
public void onAppClick(ApplicationInfo appInfo) {
|
||||
addAppToAutoList(appInfo.packageName);
|
||||
Toast.makeText(getContext(), appInfo.loadLabel(packageManager) + " added.", Toast.LENGTH_SHORT).show();
|
||||
allApps.remove(appInfo);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private Set<String> getSavedAutoApps() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||
.getStringSet(PREF_AUTO_APPS, new HashSet<>());
|
||||
}
|
||||
|
||||
private void addAppToAutoList(String packageName) {
|
||||
Set<String> autoApps = new HashSet<>(getSavedAutoApps());
|
||||
autoApps.add(packageName);
|
||||
PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||
.edit().putStringSet(PREF_AUTO_APPS, autoApps).apply();
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import org.lineageos.settings.R;
|
||||
import java.util.List;
|
||||
|
||||
public class GameBarAppsAdapter extends RecyclerView.Adapter<GameBarAppsAdapter.ViewHolder> {
|
||||
|
||||
public interface OnAppClickListener {
|
||||
void onAppClick(ApplicationInfo appInfo);
|
||||
}
|
||||
|
||||
private PackageManager packageManager;
|
||||
private List<ApplicationInfo> apps;
|
||||
private OnAppClickListener listener;
|
||||
|
||||
public GameBarAppsAdapter(PackageManager packageManager, List<ApplicationInfo> apps, OnAppClickListener listener) {
|
||||
this.packageManager = packageManager;
|
||||
this.apps = apps;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public GameBarAppsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.game_bar_app_selector_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull GameBarAppsAdapter.ViewHolder holder, int position) {
|
||||
final ApplicationInfo appInfo = apps.get(position);
|
||||
holder.appName.setText(appInfo.loadLabel(packageManager));
|
||||
holder.appPackage.setText(appInfo.packageName);
|
||||
holder.appIcon.setImageDrawable(appInfo.loadIcon(packageManager));
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onAppClick(appInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return apps.size();
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView appName;
|
||||
TextView appPackage;
|
||||
ImageView appIcon;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
appName = itemView.findViewById(R.id.app_name);
|
||||
appPackage = itemView.findViewById(R.id.app_package);
|
||||
appIcon = itemView.findViewById(R.id.app_icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import org.lineageos.settings.R;
|
||||
import java.util.List;
|
||||
|
||||
public class GameBarAutoAppsAdapter extends RecyclerView.Adapter<GameBarAutoAppsAdapter.ViewHolder> {
|
||||
|
||||
public interface OnAppRemoveListener {
|
||||
void onAppRemove(ApplicationInfo appInfo);
|
||||
}
|
||||
|
||||
private PackageManager packageManager;
|
||||
private List<ApplicationInfo> apps;
|
||||
private OnAppRemoveListener listener;
|
||||
|
||||
public GameBarAutoAppsAdapter(PackageManager packageManager, List<ApplicationInfo> apps, OnAppRemoveListener listener) {
|
||||
this.packageManager = packageManager;
|
||||
this.apps = apps;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public GameBarAutoAppsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.game_bar_app_selector_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull GameBarAutoAppsAdapter.ViewHolder holder, int position) {
|
||||
final ApplicationInfo appInfo = apps.get(position);
|
||||
holder.appName.setText(appInfo.loadLabel(packageManager));
|
||||
holder.appPackage.setText(appInfo.packageName);
|
||||
holder.appIcon.setImageDrawable(appInfo.loadIcon(packageManager));
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
if (listener != null) {
|
||||
listener.onAppRemove(appInfo);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return apps.size();
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView appName;
|
||||
TextView appPackage;
|
||||
ImageView appIcon;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
appName = itemView.findViewById(R.id.app_name);
|
||||
appPackage = itemView.findViewById(R.id.app_package);
|
||||
appIcon = itemView.findViewById(R.id.app_icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class GameBarBootReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|
||||
|| Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
|
||||
restoreOverlayState(context);
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreOverlayState(Context context) {
|
||||
var prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
boolean mainEnabled = prefs.getBoolean("game_bar_enable", false);
|
||||
boolean autoEnabled = prefs.getBoolean("game_bar_auto_enable", false);
|
||||
if (mainEnabled) {
|
||||
GameBar.getInstance(context).applyPreferences();
|
||||
GameBar.getInstance(context).show();
|
||||
}
|
||||
if (autoEnabled) {
|
||||
Intent monitorIntent = new Intent(context, GameBarMonitorService.class);
|
||||
context.startService(monitorIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class GameBarCpuInfo {
|
||||
|
||||
private static long sPrevIdle = -1;
|
||||
private static long sPrevTotal = -1;
|
||||
|
||||
private static final String CPU_TEMP_PATH = "/sys/class/thermal/thermal_zone19/temp";
|
||||
|
||||
public static String getCpuUsage() {
|
||||
String line = readLine("/proc/stat");
|
||||
if (line == null || !line.startsWith("cpu ")) return "N/A";
|
||||
String[] parts = line.split("\\s+");
|
||||
if (parts.length < 8) return "N/A";
|
||||
|
||||
try {
|
||||
long user = Long.parseLong(parts[1]);
|
||||
long nice = Long.parseLong(parts[2]);
|
||||
long system = Long.parseLong(parts[3]);
|
||||
long idle = Long.parseLong(parts[4]);
|
||||
long iowait = Long.parseLong(parts[5]);
|
||||
long irq = Long.parseLong(parts[6]);
|
||||
long softirq = Long.parseLong(parts[7]);
|
||||
long steal = parts.length > 8 ? Long.parseLong(parts[8]) : 0;
|
||||
|
||||
long total = user + nice + system + idle + iowait + irq + softirq + steal;
|
||||
|
||||
if (sPrevTotal != -1 && total != sPrevTotal) {
|
||||
long diffTotal = total - sPrevTotal;
|
||||
long diffIdle = idle - sPrevIdle;
|
||||
long usage = 100 * (diffTotal - diffIdle) / diffTotal;
|
||||
sPrevTotal = total;
|
||||
sPrevIdle = idle;
|
||||
return String.valueOf(usage);
|
||||
} else {
|
||||
|
||||
sPrevTotal = total;
|
||||
sPrevIdle = idle;
|
||||
return "N/A";
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getCpuFrequencies() {
|
||||
List<String> result = new ArrayList<>();
|
||||
String cpuDirPath = "/sys/devices/system/cpu/";
|
||||
java.io.File cpuDir = new java.io.File(cpuDirPath);
|
||||
java.io.File[] files = cpuDir.listFiles((dir, name) -> name.matches("cpu\\d+"));
|
||||
if (files == null || files.length == 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
List<java.io.File> cpuFolders = new ArrayList<>();
|
||||
Collections.addAll(cpuFolders, files);
|
||||
cpuFolders.sort(Comparator.comparingInt(GameBarCpuInfo::extractCpuNumber));
|
||||
|
||||
for (java.io.File cpu : cpuFolders) {
|
||||
String freqPath = cpu.getAbsolutePath() + "/cpufreq/scaling_cur_freq";
|
||||
String freqStr = readLine(freqPath);
|
||||
if (freqStr != null && !freqStr.isEmpty()) {
|
||||
try {
|
||||
int khz = Integer.parseInt(freqStr.trim());
|
||||
int mhz = khz / 1000;
|
||||
result.add(cpu.getName() + ": " + mhz + " MHz");
|
||||
} catch (NumberFormatException e) {
|
||||
result.add(cpu.getName() + ": N/A");
|
||||
}
|
||||
} else {
|
||||
result.add(cpu.getName() + ": offline or frequency not available");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getCpuTemp() {
|
||||
String line = readLine(CPU_TEMP_PATH);
|
||||
if (line == null) return "N/A";
|
||||
line = line.trim();
|
||||
try {
|
||||
float raw = Float.parseFloat(line);
|
||||
float c = raw / 1000f;
|
||||
return String.format("%.1f", c);
|
||||
} catch (NumberFormatException e) {
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
private static int extractCpuNumber(java.io.File cpuFolder) {
|
||||
String name = cpuFolder.getName().replace("cpu", "");
|
||||
try {
|
||||
return Integer.parseInt(name);
|
||||
} catch (NumberFormatException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static String readLine(String path) {
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
|
||||
return br.readLine();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.view.WindowManager;
|
||||
import android.window.TaskFpsCallback;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class GameBarFpsMeter {
|
||||
|
||||
private static final float TOLERANCE = 0.1f;
|
||||
private static final long STALENESS_THRESHOLD_MS = 2000;
|
||||
private static final long TASK_CHECK_INTERVAL_MS = 1000;
|
||||
|
||||
private static GameBarFpsMeter sInstance;
|
||||
private final Context mContext;
|
||||
private final WindowManager mWindowManager;
|
||||
private final SharedPreferences mPrefs;
|
||||
private float mCurrentFps = 0f;
|
||||
private TaskFpsCallback mTaskFpsCallback;
|
||||
private boolean mCallbackRegistered = false;
|
||||
private int mCurrentTaskId = -1;
|
||||
private long mLastFpsUpdateTime = System.currentTimeMillis();
|
||||
private final android.os.Handler mHandler = new android.os.Handler();
|
||||
|
||||
public static synchronized GameBarFpsMeter getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new GameBarFpsMeter(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private GameBarFpsMeter(Context context) {
|
||||
mContext = context;
|
||||
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
mTaskFpsCallback = new TaskFpsCallback() {
|
||||
@Override
|
||||
public void onFpsReported(float fps) {
|
||||
if (fps > 0) {
|
||||
mCurrentFps = fps;
|
||||
mLastFpsUpdateTime = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void start() {
|
||||
String method = mPrefs.getString("game_bar_fps_method", "new");
|
||||
if (!"new".equals(method)) return;
|
||||
|
||||
stop();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
int taskId = getFocusedTaskId();
|
||||
if (taskId <= 0) {
|
||||
return;
|
||||
}
|
||||
mCurrentTaskId = taskId;
|
||||
try {
|
||||
mWindowManager.registerTaskFpsCallback(mCurrentTaskId, Runnable::run, mTaskFpsCallback);
|
||||
mCallbackRegistered = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
mLastFpsUpdateTime = System.currentTimeMillis();
|
||||
mHandler.postDelayed(mTaskCheckRunnable, TASK_CHECK_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
String method = mPrefs.getString("game_bar_fps_method", "new");
|
||||
if ("new".equals(method) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (mCallbackRegistered) {
|
||||
try {
|
||||
mWindowManager.unregisterTaskFpsCallback(mTaskFpsCallback);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
mCallbackRegistered = false;
|
||||
}
|
||||
mHandler.removeCallbacks(mTaskCheckRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
public float getFps() {
|
||||
String method = mPrefs.getString("game_bar_fps_method", "new");
|
||||
if ("legacy".equals(method)) {
|
||||
return readLegacyFps();
|
||||
} else {
|
||||
return mCurrentFps;
|
||||
}
|
||||
}
|
||||
|
||||
private float readLegacyFps() {
|
||||
try (BufferedReader br = new BufferedReader(new FileReader("/sys/class/drm/sde-crtc-0/measured_fps"))) {
|
||||
String line = br.readLine();
|
||||
if (line != null && line.startsWith("fps:")) {
|
||||
String[] parts = line.split("\\s+");
|
||||
if (parts.length >= 2) {
|
||||
return Float.parseFloat(parts[1].trim());
|
||||
}
|
||||
}
|
||||
} catch (IOException | NumberFormatException e) {
|
||||
}
|
||||
return -1f;
|
||||
}
|
||||
|
||||
private final Runnable mTaskCheckRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
int newTaskId = getFocusedTaskId();
|
||||
if (newTaskId > 0 && newTaskId != mCurrentTaskId) {
|
||||
reinitCallback();
|
||||
} else {
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - mLastFpsUpdateTime > STALENESS_THRESHOLD_MS) {
|
||||
reinitCallback();
|
||||
}
|
||||
}
|
||||
mHandler.postDelayed(this, TASK_CHECK_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private int getFocusedTaskId() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
return -1;
|
||||
}
|
||||
try {
|
||||
Class<?> atmClass = Class.forName("android.app.ActivityTaskManager");
|
||||
Method getServiceMethod = atmClass.getDeclaredMethod("getService");
|
||||
Object atmService = getServiceMethod.invoke(null);
|
||||
Method getFocusedRootTaskInfoMethod = atmService.getClass().getMethod("getFocusedRootTaskInfo");
|
||||
Object taskInfo = getFocusedRootTaskInfoMethod.invoke(atmService);
|
||||
if (taskInfo != null) {
|
||||
try {
|
||||
Field taskIdField = taskInfo.getClass().getField("taskId");
|
||||
return taskIdField.getInt(taskInfo);
|
||||
} catch (NoSuchFieldException nsfe) {
|
||||
try {
|
||||
Field taskIdField = taskInfo.getClass().getField("mTaskId");
|
||||
return taskIdField.getInt(taskInfo);
|
||||
} catch (NoSuchFieldException nsfe2) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void reinitCallback() {
|
||||
stop();
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
start();
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
@@ -1,394 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.SeekBarPreference;
|
||||
import androidx.preference.SwitchPreference;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
|
||||
import com.android.settingslib.widget.MainSwitchPreference;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class GameBarFragment extends PreferenceFragmentCompat {
|
||||
|
||||
private GameBar mGameBar;
|
||||
private MainSwitchPreference mMasterSwitch;
|
||||
private SwitchPreferenceCompat mAutoEnableSwitch;
|
||||
private SwitchPreferenceCompat mFpsSwitch;
|
||||
private SwitchPreferenceCompat mBatteryTempSwitch;
|
||||
private SwitchPreferenceCompat mCpuUsageSwitch;
|
||||
private SwitchPreferenceCompat mCpuClockSwitch;
|
||||
private SwitchPreferenceCompat mCpuTempSwitch;
|
||||
private SwitchPreferenceCompat mRamSwitch;
|
||||
private SwitchPreferenceCompat mGpuUsageSwitch;
|
||||
private SwitchPreferenceCompat mGpuClockSwitch;
|
||||
private SwitchPreferenceCompat mGpuTempSwitch;
|
||||
private Preference mCaptureStartPref;
|
||||
private Preference mCaptureStopPref;
|
||||
private Preference mCaptureExportPref;
|
||||
private SwitchPreferenceCompat mDoubleTapCapturePref;
|
||||
private SwitchPreferenceCompat mSingleTapTogglePref;
|
||||
private SwitchPreferenceCompat mLongPressEnablePref;
|
||||
private ListPreference mLongPressTimeoutPref;
|
||||
private SeekBarPreference mTextSizePref;
|
||||
private SeekBarPreference mBgAlphaPref;
|
||||
private SeekBarPreference mCornerRadiusPref;
|
||||
private SeekBarPreference mPaddingPref;
|
||||
private SeekBarPreference mItemSpacingPref;
|
||||
private ListPreference mUpdateIntervalPref;
|
||||
private ListPreference mTextColorPref;
|
||||
private ListPreference mTitleColorPref;
|
||||
private ListPreference mValueColorPref;
|
||||
private ListPreference mPositionPref;
|
||||
private ListPreference mSplitModePref;
|
||||
private ListPreference mOverlayFormatPref;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.game_bar_preferences, rootKey);
|
||||
|
||||
mGameBar = GameBar.getInstance(getContext());
|
||||
|
||||
// Initialize all preferences.
|
||||
mMasterSwitch = findPreference("game_bar_enable");
|
||||
mAutoEnableSwitch = findPreference("game_bar_auto_enable");
|
||||
mFpsSwitch = findPreference("game_bar_fps_enable");
|
||||
mBatteryTempSwitch = findPreference("game_bar_temp_enable");
|
||||
mCpuUsageSwitch = findPreference("game_bar_cpu_usage_enable");
|
||||
mCpuClockSwitch = findPreference("game_bar_cpu_clock_enable");
|
||||
mCpuTempSwitch = findPreference("game_bar_cpu_temp_enable");
|
||||
mRamSwitch = findPreference("game_bar_ram_enable");
|
||||
mGpuUsageSwitch = findPreference("game_bar_gpu_usage_enable");
|
||||
mGpuClockSwitch = findPreference("game_bar_gpu_clock_enable");
|
||||
mGpuTempSwitch = findPreference("game_bar_gpu_temp_enable");
|
||||
|
||||
mCaptureStartPref = findPreference("game_bar_capture_start");
|
||||
mCaptureStopPref = findPreference("game_bar_capture_stop");
|
||||
mCaptureExportPref = findPreference("game_bar_capture_export");
|
||||
|
||||
mDoubleTapCapturePref = findPreference("game_bar_doubletap_capture");
|
||||
mSingleTapTogglePref = findPreference("game_bar_single_tap_toggle");
|
||||
mLongPressEnablePref = findPreference("game_bar_longpress_enable");
|
||||
mLongPressTimeoutPref = findPreference("game_bar_longpress_timeout");
|
||||
|
||||
mTextSizePref = findPreference("game_bar_text_size");
|
||||
mBgAlphaPref = findPreference("game_bar_background_alpha");
|
||||
mCornerRadiusPref = findPreference("game_bar_corner_radius");
|
||||
mPaddingPref = findPreference("game_bar_padding");
|
||||
mItemSpacingPref = findPreference("game_bar_item_spacing");
|
||||
|
||||
mUpdateIntervalPref = findPreference("game_bar_update_interval");
|
||||
mTextColorPref = findPreference("game_bar_text_color");
|
||||
mTitleColorPref = findPreference("game_bar_title_color");
|
||||
mValueColorPref = findPreference("game_bar_value_color");
|
||||
mPositionPref = findPreference("game_bar_position");
|
||||
mSplitModePref = findPreference("game_bar_split_mode");
|
||||
mOverlayFormatPref = findPreference("game_bar_format");
|
||||
|
||||
Preference appSelectorPref = findPreference("game_bar_app_selector");
|
||||
if (appSelectorPref != null) {
|
||||
appSelectorPref.setOnPreferenceClickListener(pref -> {
|
||||
Intent intent = new Intent(getContext(), GameBarAppSelectorActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
Preference appRemoverPref = findPreference("game_bar_app_remover");
|
||||
if (appRemoverPref != null) {
|
||||
appRemoverPref.setOnPreferenceClickListener(pref -> {
|
||||
Intent intent = new Intent(getContext(), GameBarAppRemoverActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (mMasterSwitch != null) {
|
||||
mMasterSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
boolean enabled = (boolean) newValue;
|
||||
if (enabled) {
|
||||
if (Settings.canDrawOverlays(getContext())) {
|
||||
mGameBar.applyPreferences();
|
||||
mGameBar.show();
|
||||
getContext().startService(new Intent(getContext(), GameBarMonitorService.class));
|
||||
} else {
|
||||
Toast.makeText(getContext(), R.string.overlay_permission_required, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
mGameBar.hide();
|
||||
if (mAutoEnableSwitch == null || !mAutoEnableSwitch.isChecked()) {
|
||||
getContext().stopService(new Intent(getContext(), GameBarMonitorService.class));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (mAutoEnableSwitch != null) {
|
||||
mAutoEnableSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
boolean autoEnabled = (boolean) newValue;
|
||||
if (autoEnabled) {
|
||||
getContext().startService(new Intent(getContext(), GameBarMonitorService.class));
|
||||
} else {
|
||||
if (mMasterSwitch == null || !mMasterSwitch.isChecked()) {
|
||||
getContext().stopService(new Intent(getContext(), GameBarMonitorService.class));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (mFpsSwitch != null) {
|
||||
mFpsSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowFps((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mBatteryTempSwitch != null) {
|
||||
mBatteryTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowBatteryTemp((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCpuUsageSwitch != null) {
|
||||
mCpuUsageSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowCpuUsage((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCpuClockSwitch != null) {
|
||||
mCpuClockSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowCpuClock((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCpuTempSwitch != null) {
|
||||
mCpuTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowCpuTemp((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mRamSwitch != null) {
|
||||
mRamSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowRam((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mGpuUsageSwitch != null) {
|
||||
mGpuUsageSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowGpuUsage((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mGpuClockSwitch != null) {
|
||||
mGpuClockSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowGpuClock((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mGpuTempSwitch != null) {
|
||||
mGpuTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setShowGpuTemp((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCaptureStartPref != null) {
|
||||
mCaptureStartPref.setOnPreferenceClickListener(pref -> {
|
||||
GameDataExport.getInstance().startCapture();
|
||||
Toast.makeText(getContext(), "Started logging Data", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCaptureStopPref != null) {
|
||||
mCaptureStopPref.setOnPreferenceClickListener(pref -> {
|
||||
GameDataExport.getInstance().stopCapture();
|
||||
Toast.makeText(getContext(), "Stopped logging Data", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCaptureExportPref != null) {
|
||||
mCaptureExportPref.setOnPreferenceClickListener(pref -> {
|
||||
GameDataExport.getInstance().exportDataToCsv();
|
||||
Toast.makeText(getContext(), "Exported log data to file", Toast.LENGTH_SHORT).show();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mDoubleTapCapturePref != null) {
|
||||
mDoubleTapCapturePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setDoubleTapCaptureEnabled((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mSingleTapTogglePref != null) {
|
||||
mSingleTapTogglePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setSingleTapToggleEnabled((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mLongPressEnablePref != null) {
|
||||
mLongPressEnablePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mGameBar.setLongPressEnabled((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mLongPressTimeoutPref != null) {
|
||||
mLongPressTimeoutPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
long ms = Long.parseLong((String) newValue);
|
||||
mGameBar.setLongPressThresholdMs(ms);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mTextSizePref != null) {
|
||||
mTextSizePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mGameBar.updateTextSize((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mBgAlphaPref != null) {
|
||||
mBgAlphaPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mGameBar.updateBackgroundAlpha((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCornerRadiusPref != null) {
|
||||
mCornerRadiusPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mGameBar.updateCornerRadius((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mPaddingPref != null) {
|
||||
mPaddingPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mGameBar.updatePadding((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mItemSpacingPref != null) {
|
||||
mItemSpacingPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mGameBar.updateItemSpacing((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mUpdateIntervalPref != null) {
|
||||
mUpdateIntervalPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mGameBar.updateUpdateInterval((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mTextColorPref != null) {
|
||||
mTextColorPref.setOnPreferenceChangeListener((pref, newValue) -> true);
|
||||
}
|
||||
if (mTitleColorPref != null) {
|
||||
mTitleColorPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mGameBar.updateTitleColor((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mValueColorPref != null) {
|
||||
mValueColorPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mGameBar.updateValueColor((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mPositionPref != null) {
|
||||
mPositionPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mGameBar.updatePosition((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mSplitModePref != null) {
|
||||
mSplitModePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mGameBar.updateSplitMode((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mOverlayFormatPref != null) {
|
||||
mOverlayFormatPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mGameBar.updateOverlayFormat((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (!hasUsageStatsPermission(requireContext())) {
|
||||
requestUsageStatsPermission();
|
||||
}
|
||||
Context context = getContext();
|
||||
if (context != null) {
|
||||
if ((mMasterSwitch != null && mMasterSwitch.isChecked()) ||
|
||||
(mAutoEnableSwitch != null && mAutoEnableSwitch.isChecked())) {
|
||||
context.startService(new Intent(context, GameBarMonitorService.class));
|
||||
} else {
|
||||
context.stopService(new Intent(context, GameBarMonitorService.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasUsageStatsPermission(Context context) {
|
||||
android.app.AppOpsManager appOps = (android.app.AppOpsManager)
|
||||
context.getSystemService(Context.APP_OPS_SERVICE);
|
||||
if (appOps == null) return false;
|
||||
int mode = appOps.checkOpNoThrow(
|
||||
android.app.AppOpsManager.OPSTR_GET_USAGE_STATS,
|
||||
android.os.Process.myUid(),
|
||||
context.getPackageName()
|
||||
);
|
||||
return (mode == android.app.AppOpsManager.MODE_ALLOWED);
|
||||
}
|
||||
|
||||
private void requestUsageStatsPermission() {
|
||||
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class GameBarGpuInfo {
|
||||
|
||||
private static final String GPU_USAGE_PATH = "/sys/class/kgsl/kgsl-3d0/gpu_busy_percentage";
|
||||
private static final String GPU_CLOCK_PATH = "/sys/class/kgsl/kgsl-3d0/gpuclk";
|
||||
private static final String GPU_TEMP_PATH = "/sys/class/kgsl/kgsl-3d0/temp";
|
||||
|
||||
public static String getGpuUsage() {
|
||||
String line = readLine(GPU_USAGE_PATH);
|
||||
if (line == null) {
|
||||
return "N/A";
|
||||
}
|
||||
line = line.replace("%", "").trim();
|
||||
try {
|
||||
int val = Integer.parseInt(line);
|
||||
return String.valueOf(val);
|
||||
} catch (NumberFormatException e) {
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getGpuClock() {
|
||||
String line = readLine(GPU_CLOCK_PATH);
|
||||
if (line == null) {
|
||||
return "N/A";
|
||||
}
|
||||
line = line.trim();
|
||||
try {
|
||||
long hz = Long.parseLong(line);
|
||||
long mhz = hz / 1_000_000;
|
||||
return String.valueOf(mhz);
|
||||
} catch (NumberFormatException e) {
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
public static String getGpuTemp() {
|
||||
String line = readLine(GPU_TEMP_PATH);
|
||||
if (line == null) {
|
||||
return "N/A";
|
||||
}
|
||||
line = line.trim();
|
||||
try {
|
||||
float raw = Float.parseFloat(line);
|
||||
float c = raw / 1000f;
|
||||
return String.format("%.1f", c);
|
||||
} catch (NumberFormatException e) {
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
private static String readLine(String path) {
|
||||
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
|
||||
return br.readLine();
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class GameBarMemInfo {
|
||||
|
||||
public static String getRamUsage() {
|
||||
long memTotal = 0;
|
||||
long memAvailable = 0;
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new FileReader("/proc/meminfo"))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
if (line.startsWith("MemTotal:")) {
|
||||
memTotal = parseMemValue(line);
|
||||
} else if (line.startsWith("MemAvailable:")) {
|
||||
memAvailable = parseMemValue(line);
|
||||
}
|
||||
if (memTotal > 0 && memAvailable > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
if (memTotal == 0) {
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
long usedKb = (memTotal - memAvailable);
|
||||
long usedMb = usedKb / 1024;
|
||||
return String.valueOf(usedMb);
|
||||
}
|
||||
|
||||
private static long parseMemValue(String line) {
|
||||
String[] parts = line.split("\\s+");
|
||||
if (parts.length < 3) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(parts[1]);
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class GameBarMonitorService extends Service {
|
||||
|
||||
private Handler mHandler;
|
||||
private Runnable mMonitorRunnable;
|
||||
private static final long MONITOR_INTERVAL = 2000; // 2 seconds
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mHandler = new Handler();
|
||||
mMonitorRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
monitorForegroundApp();
|
||||
mHandler.postDelayed(this, MONITOR_INTERVAL);
|
||||
}
|
||||
};
|
||||
mHandler.post(mMonitorRunnable);
|
||||
}
|
||||
|
||||
private void monitorForegroundApp() {
|
||||
var prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean masterEnabled = prefs.getBoolean("game_bar_enable", false);
|
||||
if (masterEnabled) {
|
||||
GameBar.getInstance(this).applyPreferences();
|
||||
GameBar.getInstance(this).show();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean autoEnabled = prefs.getBoolean("game_bar_auto_enable", false);
|
||||
if (!autoEnabled) {
|
||||
GameBar.getInstance(this).hide();
|
||||
return;
|
||||
}
|
||||
|
||||
String foreground = ForegroundAppDetector.getForegroundPackageName(this);
|
||||
Set<String> autoApps = prefs.getStringSet(GameBarAppSelectorFragment.PREF_AUTO_APPS, new HashSet<>());
|
||||
if (autoApps.contains(foreground)) {
|
||||
GameBar.getInstance(this).applyPreferences();
|
||||
GameBar.getInstance(this).show();
|
||||
} else {
|
||||
GameBar.getInstance(this).hide();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mHandler.removeCallbacks(mMonitorRunnable);
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class GameBarSettingsActivity extends CollapsingToolbarBaseActivity {
|
||||
private static final int OVERLAY_PERMISSION_REQUEST_CODE = 1234;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_game_bar);
|
||||
setTitle(getString(R.string.game_bar_title));
|
||||
|
||||
if (!Settings.canDrawOverlays(this)) {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||
Uri.parse("package:" + getPackageName()));
|
||||
startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE) {
|
||||
if (Settings.canDrawOverlays(this)) {
|
||||
Toast.makeText(this, R.string.overlay_permission_granted, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
Toast.makeText(this, R.string.overlay_permission_denied, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class GameBarTileService extends TileService {
|
||||
private GameBar mGameBar;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mGameBar = GameBar.getInstance(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
boolean enabled = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getBoolean("game_bar_enable", false);
|
||||
updateTileState(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
boolean currentlyEnabled = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getBoolean("game_bar_enable", false);
|
||||
boolean newState = !currentlyEnabled;
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.edit()
|
||||
.putBoolean("game_bar_enable", newState)
|
||||
.commit();
|
||||
|
||||
updateTileState(newState);
|
||||
|
||||
if (newState) {
|
||||
mGameBar.applyPreferences();
|
||||
mGameBar.show();
|
||||
} else {
|
||||
mGameBar.hide();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTileState(boolean enabled) {
|
||||
Tile tile = getQsTile();
|
||||
if (tile == null) return;
|
||||
|
||||
tile.setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||
tile.setLabel(getString(R.string.game_bar_tile_label));
|
||||
tile.setContentDescription(getString(R.string.game_bar_tile_description));
|
||||
tile.updateTile();
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway214
|
||||
*
|
||||
* 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.gamebar;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class GameDataExport {
|
||||
|
||||
private static GameDataExport sInstance;
|
||||
public static synchronized GameDataExport getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new GameDataExport();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private boolean mCapturing = false;
|
||||
|
||||
private final List<String[]> mStatsRows = new ArrayList<>();
|
||||
|
||||
private static final String[] CSV_HEADER = {
|
||||
"DateTime",
|
||||
"PackageName",
|
||||
"FPS",
|
||||
"Battery_Temp",
|
||||
"CPU_Usage",
|
||||
"CPU_Temp",
|
||||
"GPU_Usage",
|
||||
"GPU_Clock",
|
||||
"GPU_Temp"
|
||||
};
|
||||
|
||||
private GameDataExport() {
|
||||
}
|
||||
|
||||
public void startCapture() {
|
||||
mCapturing = true;
|
||||
mStatsRows.clear();
|
||||
mStatsRows.add(CSV_HEADER);
|
||||
}
|
||||
|
||||
public void stopCapture() {
|
||||
mCapturing = false;
|
||||
}
|
||||
|
||||
public boolean isCapturing() {
|
||||
return mCapturing;
|
||||
}
|
||||
|
||||
public void addOverlayData(String dateTime,
|
||||
String packageName,
|
||||
String fps,
|
||||
String batteryTemp,
|
||||
String cpuUsage,
|
||||
String cpuTemp,
|
||||
String gpuUsage,
|
||||
String gpuClock,
|
||||
String gpuTemp) {
|
||||
if (!mCapturing) return;
|
||||
|
||||
String[] row = {
|
||||
dateTime,
|
||||
packageName,
|
||||
fps,
|
||||
batteryTemp,
|
||||
cpuUsage,
|
||||
cpuTemp,
|
||||
gpuUsage,
|
||||
gpuClock,
|
||||
gpuTemp
|
||||
};
|
||||
mStatsRows.add(row);
|
||||
}
|
||||
|
||||
public void exportDataToCsv() {
|
||||
if (mStatsRows.size() <= 1) {
|
||||
return;
|
||||
}
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||
File outFile = new File(Environment.getExternalStorageDirectory(), "GameBar_log_" + timeStamp + ".csv");
|
||||
|
||||
BufferedWriter bw = null;
|
||||
try {
|
||||
bw = new BufferedWriter(new FileWriter(outFile, true));
|
||||
for (String[] row : mStatsRows) {
|
||||
bw.write(toCsvLine(row));
|
||||
bw.newLine();
|
||||
}
|
||||
bw.flush();
|
||||
} catch (IOException ignored) {
|
||||
} finally {
|
||||
if (bw != null) {
|
||||
try { bw.close(); } catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String toCsvLine(String[] columns) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
sb.append(columns[i]);
|
||||
if (i < columns.length - 1) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.utils;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
|
||||
public class ComponentUtils {
|
||||
|
||||
/**
|
||||
* Enables or disables a specified Android component dynamically at runtime.
|
||||
*
|
||||
* @param context The context from which the component will be enabled or disabled.
|
||||
* @param componentClass The class of the component to be enabled or disabled.
|
||||
* @param enable If true, the component will be enabled; if false, it will be disabled.
|
||||
*/
|
||||
public static void toggleComponent(Context context, Class<?> componentClass, boolean enable) {
|
||||
ComponentName componentName = new ComponentName(context, componentClass);
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
int currentState = packageManager.getComponentEnabledSetting(componentName);
|
||||
int newState = enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
||||
|
||||
if (currentState != newState) {
|
||||
packageManager.setComponentEnabledSetting(
|
||||
componentName,
|
||||
newState,
|
||||
PackageManager.DONT_KILL_APP
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The CyanogenMod Project
|
||||
* 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.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);
|
||||
writer.flush();
|
||||
} 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given value into the given file.
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
public static boolean writeValue(String fileName, String value) {
|
||||
BufferedWriter writer = null;
|
||||
|
||||
try {
|
||||
writer = new BufferedWriter(new FileWriter(fileName));
|
||||
writer.write(value);
|
||||
writer.flush();
|
||||
} 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the value from the given file.
|
||||
* @return the value read from the file, or the default value if an error occurs
|
||||
*/
|
||||
public static String getFileValue(String fileName, String defaultValue) {
|
||||
String value = defaultValue;
|
||||
BufferedReader reader = null;
|
||||
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(fileName), 512);
|
||||
value = 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 value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.utils;
|
||||
|
||||
import android.app.StatusBarManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class TileUtils {
|
||||
|
||||
public static void requestAddTileService(Context context, Class<?> tileServiceClass, int labelResId, int iconResId) {
|
||||
ComponentName componentName = new ComponentName(context, tileServiceClass);
|
||||
String label = context.getString(labelResId);
|
||||
Icon icon = Icon.createWithResource(context, iconResId);
|
||||
|
||||
StatusBarManager sbm = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
|
||||
|
||||
if (sbm != null) {
|
||||
sbm.requestAddTileService(
|
||||
componentName,
|
||||
label,
|
||||
icon,
|
||||
context.getMainExecutor(),
|
||||
result -> handleResult(context, result)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleResult(Context context, Integer result) {
|
||||
if (result == null)
|
||||
return;
|
||||
switch (result) {
|
||||
case StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ADDED:
|
||||
Toast.makeText(context, R.string.tile_added, Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
case StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_NOT_ADDED:
|
||||
Toast.makeText(context, R.string.tile_not_added, Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
case StatusBarManager.TILE_ADD_REQUEST_RESULT_TILE_ALREADY_ADDED:
|
||||
Toast.makeText(context, R.string.tile_already_added, Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
product.prop
16
product.prop
@@ -19,6 +19,22 @@ vendor.display.disable_metadata_dynamic_fps=1
|
||||
|
||||
# LMKD
|
||||
ro.config.low_ram=false
|
||||
ro.lmk.log_stats=false
|
||||
ro.lmk.kill_heaviest_task=true
|
||||
ro.lmk.swap_free_low_percentage=100
|
||||
|
||||
# LMK tuning
|
||||
ro.lmk.filecache_min_kb=153600
|
||||
ro.lmk.stall_limit_critical=40
|
||||
ro.lmk.use_new_strategy=true
|
||||
ro.lmk.enable_watermark_check=true
|
||||
ro.lmk.enable_userspace_lmk=true
|
||||
ro.lmk.enhance_batch_kill=false
|
||||
ro.lmk.super_critical=701
|
||||
ro.lmk.kill_timeout_ms=50
|
||||
ro.lmk.psi_scrit_complete_stall_ms=150
|
||||
ro.lmk.direct_reclaim_pressure=45
|
||||
ro.lmk.reclaim_scan_threshold=0
|
||||
|
||||
# Incremental FS
|
||||
ro.incremental.enable=1
|
||||
|
||||
20
recovery/root/Android.bp
Normal file
20
recovery/root/Android.bp
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Copyright (C) 2026 The LineageOS Project
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
prebuilt_etc {
|
||||
name: "init.recovery.qcom.rc",
|
||||
src: "init.recovery.qcom.rc",
|
||||
sub_dir: "recovery/root",
|
||||
filename: "init.recovery.qcom.rc",
|
||||
installable: true,
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "init.recovery.usb.rc",
|
||||
src: "init.recovery.usb.rc",
|
||||
sub_dir: "recovery/root",
|
||||
filename: "init.recovery.usb.rc",
|
||||
installable: true,
|
||||
}
|
||||
@@ -4,15 +4,15 @@
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of The Linux Foundation nor
|
||||
# the names of its contributors may be used to endorse or promote
|
||||
# products derived from this software without specific prior written
|
||||
# permission.
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of The Linux Foundation nor
|
||||
# the names of its contributors may be used to endorse or promote
|
||||
# products derived from this software without specific prior written
|
||||
# permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -31,59 +31,148 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
#
|
||||
|
||||
function configure_zram_parameters() {
|
||||
swapoff /dev/block/zram0 2>/dev/null || true
|
||||
|
||||
# Reset zram device
|
||||
[ -w /sys/block/zram0/reset ] && echo 1 > /sys/block/zram0/reset
|
||||
|
||||
# Set compression algorithm (LZ4 optimized for ARM Cortex-A76/A55)
|
||||
echo lz4 > /sys/block/zram0/comp_algorithm 2>/dev/null || return 1
|
||||
|
||||
# Optimize compression streams for 8-core big.LITTLE (2x A76 + 6x A55)
|
||||
echo 4 > /sys/block/zram0/max_comp_streams 2>/dev/null || true
|
||||
|
||||
# Set 4GB zram size
|
||||
echo 4294967296 > /sys/block/zram0/disksize 2>/dev/null || return 1
|
||||
|
||||
# Initialize and enable swap
|
||||
mkswap /dev/block/zram0 2>/dev/null || return 1
|
||||
swapon /dev/block/zram0 -p 32758 2>/dev/null || return 1
|
||||
|
||||
# VM tuning - Optimized for Realme 6 Pro mobile workloads
|
||||
{
|
||||
# Swappiness: Slightly higher for 4GB zram to utilize it effectively
|
||||
echo 100 > /proc/sys/vm/swappiness
|
||||
|
||||
# Cache pressure: Aggressive reclaim for mobile RAM management
|
||||
echo 100 > /proc/sys/vm/vfs_cache_pressure
|
||||
|
||||
# Page-cluster: Small reads optimal for mobile flash + zram combo
|
||||
echo 1 > /proc/sys/vm/page-cluster
|
||||
|
||||
# Dirty ratios: Conservative for mobile storage longevity
|
||||
echo 20 > /proc/sys/vm/dirty_ratio
|
||||
echo 5 > /proc/sys/vm/dirty_background_ratio
|
||||
|
||||
# Extra free memory: Buffer for smooth operation
|
||||
echo 1024 > /proc/sys/vm/extra_free_kbytes
|
||||
|
||||
# Memory overcommit: Conservative for stability
|
||||
echo 1 > /proc/sys/vm/overcommit_memory
|
||||
echo 50 > /proc/sys/vm/overcommit_ratio
|
||||
|
||||
# Additional mobile optimizations for Snapdragon 720G
|
||||
echo 1 > /proc/sys/vm/compact_memory 2>/dev/null || true
|
||||
echo 0 > /proc/sys/vm/oom_kill_allocating_task 2>/dev/null || true
|
||||
|
||||
# Optimize readahead for mobile storage patterns
|
||||
echo 128 > /sys/block/*/queue/read_ahead_kb 2>/dev/null || true
|
||||
|
||||
} 2>/dev/null
|
||||
|
||||
return 0
|
||||
function configure_read_ahead_kb_values() {
|
||||
MemTotalStr=`cat /proc/meminfo | grep MemTotal`
|
||||
MemTotal=${MemTotalStr:16:8}
|
||||
|
||||
dmpts=$(ls /sys/block/*/queue/read_ahead_kb | grep -e dm -e mmc)
|
||||
|
||||
# Set 128 for <= 3GB &
|
||||
# set 512 for >= 4GB targets.
|
||||
if [ $MemTotal -le 3145728 ]; then
|
||||
echo 128 > /sys/block/mmcblk0/bdi/read_ahead_kb
|
||||
echo 128 > /sys/block/mmcblk0rpmb/bdi/read_ahead_kb
|
||||
for dm in $dmpts; do
|
||||
echo 128 > $dm
|
||||
done
|
||||
else
|
||||
echo 512 > /sys/block/mmcblk0/bdi/read_ahead_kb
|
||||
echo 512 > /sys/block/mmcblk0rpmb/bdi/read_ahead_kb
|
||||
for dm in $dmpts; do
|
||||
echo 512 > $dm
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
function enable_swap() {
|
||||
# Enable swap if not already enabled
|
||||
if [ ! -f /proc/swaps ] || [ -z "$(cat /proc/swaps | grep zram0)" ]; then
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
function configure_memory_parameters() {
|
||||
# Unified memory configuration for Atoll device (Realme 6 Pro: 6GB/8GB RAM)
|
||||
# Combines ZRAM setup and memory management parameters
|
||||
|
||||
ProductName=`getprop ro.product.name`
|
||||
arch_type=`uname -m`
|
||||
MemTotalStr=`cat /proc/meminfo | grep MemTotal`
|
||||
MemTotal=${MemTotalStr:16:8}
|
||||
|
||||
# Configure ZRAM parameters with LZ4 compression
|
||||
echo lz4 > /sys/block/zram0/comp_algorithm
|
||||
echo 100 > /proc/sys/vm/swappiness
|
||||
echo 60 > /proc/sys/vm/direct_swappiness
|
||||
echo 0 > /proc/sys/vm/page-cluster
|
||||
|
||||
if [ -f /sys/block/zram0/disksize ]; then
|
||||
# Enable deduplication if available
|
||||
if [ -f /sys/block/zram0/use_dedup ]; then
|
||||
echo 1 > /sys/block/zram0/use_dedup
|
||||
fi
|
||||
|
||||
# Configure ZRAM size based on total RAM
|
||||
if [ $MemTotal -le 4194304 ]; then
|
||||
# 4GB RAM: 2.5GB ZRAM
|
||||
echo 2684354560 > /sys/block/zram0/disksize
|
||||
echo 4 > /sys/module/lowmemorykiller/parameters/almk_totalram_ratio
|
||||
elif [ $MemTotal -le 6291456 ]; then
|
||||
# 6GB RAM: 3GB ZRAM
|
||||
echo 3221225472 > /sys/block/zram0/disksize
|
||||
echo 6 > /sys/module/lowmemorykiller/parameters/almk_totalram_ratio
|
||||
elif [ $MemTotal -le 8388608 ]; then
|
||||
# 8GB RAM: 4GB ZRAM
|
||||
echo 4294967296 > /sys/block/zram0/disksize
|
||||
echo 8 > /sys/module/lowmemorykiller/parameters/almk_totalram_ratio
|
||||
else
|
||||
# 12GB+ RAM: 5GB ZRAM
|
||||
echo 5368709120 > /sys/block/zram0/disksize
|
||||
echo 10 > /sys/module/lowmemorykiller/parameters/almk_totalram_ratio
|
||||
fi
|
||||
|
||||
# Initialize and enable ZRAM swap
|
||||
mkswap /dev/block/zram0
|
||||
swapon /dev/block/zram0 -p 32758
|
||||
fi
|
||||
|
||||
# Configure Low Memory Killer parameters
|
||||
# Read adj series and set adj threshold for PPR and ALMK
|
||||
adj_series=`cat /sys/module/lowmemorykiller/parameters/adj`
|
||||
adj_1="${adj_series#*,}"
|
||||
set_almk_ppr_adj="${adj_1%%,*}"
|
||||
|
||||
# Calculate PPR adj threshold (HOME adj and below should not be affected)
|
||||
set_almk_ppr_adj=$(((set_almk_ppr_adj * 6) + 6))
|
||||
echo $set_almk_ppr_adj > /sys/module/lowmemorykiller/parameters/adj_max_shift
|
||||
|
||||
# Calculate vmpressure_file_min for 64-bit architecture
|
||||
if [ "$arch_type" == "aarch64" ]; then
|
||||
minfree_series=`cat /sys/module/lowmemorykiller/parameters/minfree`
|
||||
minfree_1="${minfree_series#*,}"
|
||||
rem_minfree_1="${minfree_1%%,*}"
|
||||
minfree_2="${minfree_1#*,}"
|
||||
rem_minfree_2="${minfree_2%%,*}"
|
||||
minfree_3="${minfree_2#*,}"
|
||||
rem_minfree_3="${minfree_3%%,*}"
|
||||
minfree_4="${minfree_3#*,}"
|
||||
rem_minfree_4="${minfree_4%%,*}"
|
||||
minfree_5="${minfree_4#*,}"
|
||||
|
||||
vmpres_file_min=$((minfree_5 + (minfree_5 - rem_minfree_4)))
|
||||
echo $vmpres_file_min > /sys/module/lowmemorykiller/parameters/vmpressure_file_min
|
||||
fi
|
||||
|
||||
# Enable Adaptive LMK
|
||||
echo 1 > /sys/module/lowmemorykiller/parameters/enable_adaptive_lmk
|
||||
|
||||
# Enable OOM reaper
|
||||
if [ -f /sys/module/lowmemorykiller/parameters/oom_reaper ]; then
|
||||
echo 1 > /sys/module/lowmemorykiller/parameters/oom_reaper
|
||||
fi
|
||||
|
||||
# Configure Process Reclaim parameters
|
||||
if [ -f /sys/devices/soc0/soc_id ]; then
|
||||
soc_id=`cat /sys/devices/soc0/soc_id`
|
||||
else
|
||||
soc_id=`cat /sys/devices/system/soc/soc0/id`
|
||||
fi
|
||||
|
||||
# Set PPR parameters (excluding premium SoCs)
|
||||
case "$soc_id" in
|
||||
"321" | "341" | "292" | "319" | "246" | "291" | "305" | "312")
|
||||
# Skip PPR for premium targets
|
||||
;;
|
||||
*)
|
||||
echo $set_almk_ppr_adj > /sys/module/process_reclaim/parameters/min_score_adj
|
||||
echo 1 > /sys/module/process_reclaim/parameters/enable_process_reclaim
|
||||
echo 50 > /sys/module/process_reclaim/parameters/pressure_min
|
||||
echo 70 > /sys/module/process_reclaim/parameters/pressure_max
|
||||
echo 30 > /sys/module/process_reclaim/parameters/swap_opt_eff
|
||||
echo 512 > /sys/module/process_reclaim/parameters/per_swap_size
|
||||
;;
|
||||
esac
|
||||
|
||||
# Set global VM parameters
|
||||
echo 0 > /sys/module/vmpressure/parameters/allocstall_threshold
|
||||
echo 1 > /proc/sys/vm/watermark_scale_factor
|
||||
|
||||
# Configure read-ahead values
|
||||
configure_read_ahead_kb_values
|
||||
|
||||
# Enable swap
|
||||
enable_swap
|
||||
}
|
||||
|
||||
# Core control parameters on silver
|
||||
echo 0 0 0 0 1 1 > /sys/devices/system/cpu/cpu0/core_ctl/not_preferred
|
||||
@@ -103,109 +192,94 @@ echo 85 > /proc/sys/kernel/sched_group_downmigrate
|
||||
echo 100 > /proc/sys/kernel/sched_group_upmigrate
|
||||
echo 1 > /proc/sys/kernel/sched_walt_rotate_big_tasks
|
||||
|
||||
#colocation v3 settings
|
||||
# Colocation v3 settings
|
||||
echo 740000 > /proc/sys/kernel/sched_little_cluster_coloc_fmin_khz
|
||||
|
||||
# configure governor settings for little cluster
|
||||
# Configure governor settings for little cluster
|
||||
echo "schedutil" > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
|
||||
echo 0 > /sys/devices/system/cpu/cpu0/cpufreq/schedutil/up_rate_limit_us
|
||||
echo 0 > /sys/devices/system/cpu/cpu0/cpufreq/schedutil/down_rate_limit_us
|
||||
echo 500 > /sys/devices/system/cpu/cpu0/cpufreq/schedutil/up_rate_limit_us
|
||||
echo 20000 > /sys/devices/system/cpu/cpu0/cpufreq/schedutil/down_rate_limit_us
|
||||
echo 1248000 > /sys/devices/system/cpu/cpu0/cpufreq/schedutil/hispeed_freq
|
||||
echo 576000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq
|
||||
|
||||
# configure governor settings for big cluster
|
||||
# Configure governor settings for big cluster
|
||||
echo "schedutil" > /sys/devices/system/cpu/cpu6/cpufreq/scaling_governor
|
||||
echo 0 > /sys/devices/system/cpu/cpu6/cpufreq/schedutil/up_rate_limit_us
|
||||
echo 0 > /sys/devices/system/cpu/cpu6/cpufreq/schedutil/down_rate_limit_us
|
||||
echo 500 > /sys/devices/system/cpu/cpu6/cpufreq/schedutil/up_rate_limit_us
|
||||
echo 20000 > /sys/devices/system/cpu/cpu6/cpufreq/schedutil/down_rate_limit_us
|
||||
echo 1267200 > /sys/devices/system/cpu/cpu6/cpufreq/schedutil/hispeed_freq
|
||||
echo 652800 > /sys/devices/system/cpu/cpu6/cpufreq/scaling_min_freq
|
||||
|
||||
# sched_load_boost as -6 is equivalent to target load as 85. It is per cpu tunable.
|
||||
echo -6 > /sys/devices/system/cpu/cpu6/sched_load_boost
|
||||
echo -6 > /sys/devices/system/cpu/cpu7/sched_load_boost
|
||||
echo -6 > /sys/devices/system/cpu/cpu6/sched_load_boost
|
||||
echo -6 > /sys/devices/system/cpu/cpu7/sched_load_boost
|
||||
echo 85 > /sys/devices/system/cpu/cpu6/cpufreq/schedutil/hispeed_load
|
||||
|
||||
# Enable conservative pl for power save
|
||||
echo 1 > /proc/sys/kernel/sched_conservative_pl
|
||||
|
||||
echo "0:1248000" > /sys/module/cpu_boost/parameters/input_boost_freq
|
||||
echo 40 > /sys/module/cpu_boost/parameters/input_boost_ms
|
||||
|
||||
# Set Memory parameters
|
||||
configure_memory_parameters
|
||||
|
||||
# Enable bus-dcvs
|
||||
for device in /sys/devices/platform/soc
|
||||
do
|
||||
for cpubw in $device/*cpu-cpu-llcc-bw/devfreq/*cpu-cpu-llcc-bw
|
||||
do
|
||||
echo "bw_hwmon" > $cpubw/governor
|
||||
echo "2288 4577 7110 9155 12298 14236" > $cpubw/bw_hwmon/mbps_zones
|
||||
echo 4 > $cpubw/bw_hwmon/sample_ms
|
||||
echo 68 > $cpubw/bw_hwmon/io_percent
|
||||
echo 20 > $cpubw/bw_hwmon/hist_memory
|
||||
echo 0 > $cpubw/bw_hwmon/hyst_length
|
||||
echo 80 > $cpubw/bw_hwmon/down_thres
|
||||
echo 0 > $cpubw/bw_hwmon/guard_band_mbps
|
||||
echo 250 > $cpubw/bw_hwmon/up_scale
|
||||
echo 1600 > $cpubw/bw_hwmon/idle_mbps
|
||||
echo 50 > $cpubw/polling_interval
|
||||
done
|
||||
for cpubw in $device/*cpu-cpu-llcc-bw/devfreq/*cpu-cpu-llcc-bw
|
||||
do
|
||||
echo "bw_hwmon" > $cpubw/governor
|
||||
echo "2288 4577 7110 9155 12298 14236" > $cpubw/bw_hwmon/mbps_zones
|
||||
echo 4 > $cpubw/bw_hwmon/sample_ms
|
||||
echo 68 > $cpubw/bw_hwmon/io_percent
|
||||
echo 20 > $cpubw/bw_hwmon/hist_memory
|
||||
echo 0 > $cpubw/bw_hwmon/hyst_length
|
||||
echo 80 > $cpubw/bw_hwmon/down_thres
|
||||
echo 0 > $cpubw/bw_hwmon/guard_band_mbps
|
||||
echo 250 > $cpubw/bw_hwmon/up_scale
|
||||
echo 1600 > $cpubw/bw_hwmon/idle_mbps
|
||||
echo 50 > $cpubw/polling_interval
|
||||
done
|
||||
|
||||
for llccbw in $device/*cpu-llcc-ddr-bw/devfreq/*cpu-llcc-ddr-bw
|
||||
do
|
||||
echo "bw_hwmon" > $llccbw/governor
|
||||
echo "1144 1720 2086 2929 3879 5931 6881 8137" > $llccbw/bw_hwmon/mbps_zones
|
||||
echo 4 > $llccbw/bw_hwmon/sample_ms
|
||||
echo 68 > $llccbw/bw_hwmon/io_percent
|
||||
echo 20 > $llccbw/bw_hwmon/hist_memory
|
||||
echo 0 > $llccbw/bw_hwmon/hyst_length
|
||||
echo 80 > $llccbw/bw_hwmon/down_thres
|
||||
echo 0 > $llccbw/bw_hwmon/guard_band_mbps
|
||||
echo 250 > $llccbw/bw_hwmon/up_scale
|
||||
echo 1600 > $llccbw/bw_hwmon/idle_mbps
|
||||
echo 40 > $llccbw/polling_interval
|
||||
done
|
||||
|
||||
for npubw in $device/*npu*-npu-ddr-bw/devfreq/*npu*-npu-ddr-bw
|
||||
do
|
||||
echo 1 > /sys/devices/virtual/npu/msm_npu/pwr
|
||||
echo "bw_hwmon" > $npubw/governor
|
||||
echo "1144 1720 2086 2929 3879 5931 6881 8137" > $npubw/bw_hwmon/mbps_zones
|
||||
echo 4 > $npubw/bw_hwmon/sample_ms
|
||||
echo 80 > $npubw/bw_hwmon/io_percent
|
||||
echo 20 > $npubw/bw_hwmon/hist_memory
|
||||
echo 10 > $npubw/bw_hwmon/hyst_length
|
||||
echo 30 > $npubw/bw_hwmon/down_thres
|
||||
echo 0 > $npubw/bw_hwmon/guard_band_mbps
|
||||
echo 250 > $npubw/bw_hwmon/up_scale
|
||||
echo 0 > $npubw/bw_hwmon/idle_mbps
|
||||
echo 40 > $npubw/polling_interval
|
||||
echo 0 > /sys/devices/virtual/npu/msm_npu/pwr
|
||||
done
|
||||
|
||||
#Enable mem_latency governor for L3, LLCC, and DDR scaling
|
||||
for memlat in $device/*cpu*-lat/devfreq/*cpu*-lat
|
||||
do
|
||||
echo "mem_latency" > $memlat/governor
|
||||
echo 10 > $memlat/polling_interval
|
||||
echo 400 > $memlat/mem_latency/ratio_ceil
|
||||
done
|
||||
|
||||
#Enable cdspl3 governor for L3 cdsp nodes
|
||||
for l3cdsp in $device/*cdsp-cdsp-l3-lat/devfreq/*cdsp-cdsp-l3-lat
|
||||
do
|
||||
echo "cdspl3" > $l3cdsp/governor
|
||||
done
|
||||
|
||||
#Gold L3 ratio ceil
|
||||
echo 4000 > /sys/class/devfreq/soc:qcom,cpu6-cpu-l3-lat/mem_latency/ratio_ceil
|
||||
|
||||
#Enable compute governor for gold latfloor
|
||||
for latfloor in $device/*cpu*-ddr-latfloor*/devfreq/*cpu-ddr-latfloor*
|
||||
do
|
||||
echo "compute" > $latfloor/governor
|
||||
echo 10 > $latfloor/polling_interval
|
||||
done
|
||||
for llccbw in $device/*cpu-llcc-ddr-bw/devfreq/*cpu-llcc-ddr-bw
|
||||
do
|
||||
echo "bw_hwmon" > $llccbw/governor
|
||||
echo "1144 1720 2086 2929 3879 5931 6881 8137" > $llccbw/bw_hwmon/mbps_zones
|
||||
echo 4 > $llccbw/bw_hwmon/sample_ms
|
||||
echo 68 > $llccbw/bw_hwmon/io_percent
|
||||
echo 20 > $llccbw/bw_hwmon/hist_memory
|
||||
echo 0 > $llccbw/bw_hwmon/hyst_length
|
||||
echo 80 > $llccbw/bw_hwmon/down_thres
|
||||
echo 0 > $llccbw/bw_hwmon/guard_band_mbps
|
||||
echo 250 > $llccbw/bw_hwmon/up_scale
|
||||
echo 1600 > $llccbw/bw_hwmon/idle_mbps
|
||||
echo 40 > $llccbw/polling_interval
|
||||
done
|
||||
|
||||
for npubw in $device/*npu*-npu-ddr-bw/devfreq/*npu*-npu-ddr-bw
|
||||
do
|
||||
echo 1 > /sys/devices/virtual/npu/msm_npu/pwr
|
||||
echo "bw_hwmon" > $npubw/governor
|
||||
echo "1144 1720 2086 2929 3879 5931 6881 8137" > $npubw/bw_hwmon/mbps_zones
|
||||
echo 4 > $npubw/bw_hwmon/sample_ms
|
||||
echo 80 > $npubw/bw_hwmon/io_percent
|
||||
echo 20 > $npubw/bw_hwmon/hist_memory
|
||||
echo 10 > $npubw/bw_hwmon/hyst_length
|
||||
echo 30 > $npubw/bw_hwmon/down_thres
|
||||
echo 0 > $npubw/bw_hwmon/guard_band_mbps
|
||||
echo 250 > $npubw/bw_hwmon/up_scale
|
||||
echo 0 > $npubw/bw_hwmon/idle_mbps
|
||||
echo 40 > $npubw/polling_interval
|
||||
echo 0 > /sys/devices/virtual/npu/msm_npu/pwr
|
||||
done
|
||||
done
|
||||
|
||||
# cpuset parameters
|
||||
echo 0-5 > /dev/cpuset/background/cpus
|
||||
# memlat specific settings are moved to separate file under
|
||||
# device/target specific folder
|
||||
setprop vendor.dcvs.prop 1
|
||||
|
||||
# cpuset parameters for power save
|
||||
echo 0-3 > /dev/cpuset/background/cpus
|
||||
echo 0-5 > /dev/cpuset/system-background/cpus
|
||||
|
||||
# Turn off scheduler boost at the end
|
||||
@@ -214,8 +288,8 @@ echo 0 > /proc/sys/kernel/sched_boost
|
||||
# Turn on sleep modes
|
||||
echo 0 > /sys/module/lpm_levels/parameters/sleep_disabled
|
||||
|
||||
# configure zram
|
||||
configure_zram_parameters
|
||||
# Change IO scheduler to noop for better performance
|
||||
echo noop > /sys/block/sda/queue/scheduler
|
||||
|
||||
# Post-setup services
|
||||
setprop vendor.post_boot.parsed 1
|
||||
# Create 1 kswapd thread
|
||||
echo 1 > /proc/sys/vm/kswapd_threads
|
||||
5
rootdir/etc/vendor/init.qcom.rc
vendored
5
rootdir/etc/vendor/init.qcom.rc
vendored
@@ -568,11 +568,6 @@ on property:ro.crypto.state=unsupported
|
||||
on property:persist.env.fastdorm.enabled=true
|
||||
setprop persist.radio.data_no_toggle 1
|
||||
|
||||
on post-fs-data
|
||||
# Charge Bypass
|
||||
chown system system /sys/class/power_supply/battery
|
||||
chmod 0660 /sys/class/power_supply/battery
|
||||
|
||||
service vendor.qrtr-ns /vendor/bin/qrtr-ns -f
|
||||
class core
|
||||
user vendor_qrtr
|
||||
|
||||
6
rootdir/etc/vendor/init.sm7125.rc
vendored
6
rootdir/etc/vendor/init.sm7125.rc
vendored
@@ -29,12 +29,6 @@ on boot
|
||||
chown system system /sys/class/leds/vibrator/vmax_mv
|
||||
chmod 0644 /sys/class/leds/vibrator/vmax_mv
|
||||
|
||||
chown system graphics /sys/class/drm/sde-crtc-0/measured_fps
|
||||
chmod 0660 /sys/class/drm/sde-crtc-0/measured_fps
|
||||
|
||||
chown system system /sys/class/thermal/thermal_zone78/temp
|
||||
chmod 0660 /sys/class/thermal/thermal_zone78/temp
|
||||
|
||||
on property:ro.boot.product.hardware.sku=nfc
|
||||
start secure_element_hal_service
|
||||
start vendor.nfc_hal_service
|
||||
|
||||
6
sepolicy/vendor/devicesettings_app.te
vendored
6
sepolicy/vendor/devicesettings_app.te
vendored
@@ -1,6 +0,0 @@
|
||||
type devicesettings_app, domain;
|
||||
app_domain(devicesettings_app)
|
||||
|
||||
# Allow charging bypass to overwrite
|
||||
allow devicesettings_app sysfs_battery_writable:dir r_dir_perms;
|
||||
allow devicesettings_app sysfs_battery_writable:file { open read write getattr ioctl };
|
||||
3
sepolicy/vendor/file.te
vendored
3
sepolicy/vendor/file.te
vendored
@@ -13,9 +13,6 @@ type proc_oppo_fp, fs_type, proc_type;
|
||||
# Camera
|
||||
type vendor_persist_camera_file, file_type;
|
||||
|
||||
# Bypass Charging
|
||||
type sysfs_battery_writable, sysfs_type, fs_type;
|
||||
|
||||
# Devinfo
|
||||
type proc_devinfo, fs_type, proc_type;
|
||||
|
||||
|
||||
3
sepolicy/vendor/file_contexts
vendored
3
sepolicy/vendor/file_contexts
vendored
@@ -19,9 +19,6 @@
|
||||
# Cust
|
||||
/dev/block/platform/soc/4744000.sdhci/by-name/cust u:object_r:vendor_custom_block_device:s0
|
||||
|
||||
# Charging Bypass
|
||||
/sys/class/power_supply/battery/input_suspend u:object_r:sysfs_battery_writable:s0
|
||||
|
||||
# Oppo Partitions
|
||||
/dev/block/platform/soc/1d84000.ufshc/by-name/oppodycnvbk u:object_r:vendor_modem_efs_partition_device:s0
|
||||
/dev/block/platform/soc/1d84000.ufshc/by-name/oppostanvbk u:object_r:vendor_modem_efs_partition_device:s0
|
||||
|
||||
1
sepolicy/vendor/hal_power_default.te
vendored
1
sepolicy/vendor/hal_power_default.te
vendored
@@ -1,5 +1,4 @@
|
||||
allow hal_power_default proc_touchpanel:dir search;
|
||||
allow hal_power_default proc_touchpanel:file rw_file_perms;
|
||||
allow init sysfs_battery_supply:file rw_file_perms;
|
||||
|
||||
get_prop(hal_power_default, vendor_mpctl_prop);
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
allow hal_secure_element_default nfc_hwservice:hwservice_manager { find add };
|
||||
binder_call(hal_secure_element_default, nfc_hwservice)
|
||||
5
sepolicy/vendor/system_app.te
vendored
5
sepolicy/vendor/system_app.te
vendored
@@ -7,8 +7,5 @@ r_dir_file(system_app, proc_touchpanel);
|
||||
r_dir_file(system_app, vendor_sysfs_usb_supply);
|
||||
allow system_app vendor_sysfs_usb_supply:file rw_file_perms;
|
||||
allow system_app vendor_sysfs_battery_supply:dir search;
|
||||
allow system_app vendor_sysfs_battery_supply:file read;
|
||||
allow system_app vendor_sysfs_battery_supply:file getattr;
|
||||
|
||||
# Allow Settings app to control input_suspend (bypass charging)
|
||||
allow system_app vendor_sysfs_battery_supply:file rw_file_perms;
|
||||
|
||||
|
||||
11
system.prop
11
system.prop
@@ -25,9 +25,10 @@ persist.vendor.camera.oissr.debug=1
|
||||
vendor.debug.camera.eisv2enable=1
|
||||
vendor.debug.camera.eisv3enable=1
|
||||
# Allow privileged camera apps
|
||||
persist.vendor.camera.privapp.list=com.android.camera,com.google.camera,org.lineageos.aperture
|
||||
persist.vendor.camera.privapp.list=org.lineageos.aperture,org.codeaurora.snapcam,com.android.camera,com.google.camera
|
||||
# Allow aux cameras
|
||||
vendor.camera.aux.packagelist=com.android.camera,com.google.camera,org.lineageos.aperture
|
||||
vendor.camera.aux.packagelist=org.lineageos.aperture,org.codeaurora.snapcam,com.android.camera,com.google.camera
|
||||
persist.vendor.camera.expose.aux=1
|
||||
|
||||
# CNE
|
||||
persist.vendor.cne.feature=1
|
||||
@@ -110,7 +111,6 @@ persist.sys.radio.force_lte_ca=true
|
||||
persist.vendor.data.iwlan.enable=true
|
||||
persist.vendor.data.mode=concurrent
|
||||
ril.subscription.types=NV,RUIM
|
||||
ro.telephony.default_network=22,22
|
||||
ro.vendor.use_data_netmgrd=true
|
||||
telephony.lteOnCdmaDevice=1
|
||||
persist.sys.fflag.override.settings_network_and_internet_v2=true
|
||||
@@ -123,11 +123,6 @@ persist.vendor.ssr.restart_level=ALL_ENABLE
|
||||
persist.debug.wfd.enable=1
|
||||
persist.sys.wfd.virtual=0
|
||||
|
||||
# ZRAM
|
||||
ro.zram.mark_idle_delay_mins=60
|
||||
ro.zram.first_wb_delay_mins=180
|
||||
ro.zram.periodic_wb_delay_hours=24
|
||||
|
||||
#SkiaGL
|
||||
debug.renderengine.backend=skiaglthreaded
|
||||
renderthread.skia.reduceopstasksplitting=true
|
||||
|
||||
25
vendor.prop
25
vendor.prop
@@ -112,6 +112,7 @@ ro.hardware.egl=adreno
|
||||
ro.hardware.vulkan=adreno
|
||||
ro.opengles.version=196610
|
||||
ro.vendor.cabc.enable=true
|
||||
ro.surface_flinger.blur_disabled_by_default=true
|
||||
vendor.display.comp_mask=0
|
||||
vendor.display.disable_decimation=1
|
||||
vendor.display.disable_excl_rect=0
|
||||
@@ -151,19 +152,22 @@ ro.qcom.adreno.qgl.ShaderStorageImageExtendedFormats=0
|
||||
# FM
|
||||
vendor.hw.fm.init=0
|
||||
|
||||
# FRP
|
||||
ro.frp.pst=/dev/block/bootdevice/by-name/frp
|
||||
|
||||
#Graphics
|
||||
debug.hwui.use_hint_manager=true
|
||||
debug.hwui.target_cpu_time_percent=30
|
||||
debug.sf.disable_client_composition_cache=0
|
||||
debug.sf.enable_adpf_cpu_hint=true
|
||||
|
||||
# Keyguard
|
||||
keyguard.no_require_sim=true
|
||||
debug.sf.enable_gl_backpressure=0
|
||||
|
||||
# Keystore
|
||||
ro.hardware.keystore_desede=true
|
||||
|
||||
# Game FrameRate
|
||||
debug.graphics.game_default_frame_rate.disabled=true
|
||||
|
||||
# Media
|
||||
debug.media.codec2=2
|
||||
debug.stagefright.c2inputsurface=-1
|
||||
@@ -194,6 +198,21 @@ persist.vendor.radio.rat_on=combine
|
||||
ro.telephony.default_network=22,20
|
||||
ro.vendor.use_data_netmgrd=true
|
||||
telephony.lteOnCdmaDevice=1
|
||||
persist.vendor.radio.add_power_save=1
|
||||
persist.vendor.radio.force_on_dc=1
|
||||
persist.vendor.radio.lte_vrte_ltd=1
|
||||
persist.vendor.radio.snrt_max_layer=3
|
||||
persist.vendor.radio.data_con_rprt=1
|
||||
persist.vendor.radio.ignore_dom_time=10
|
||||
persist.vendor.radio.oppo.signal.adapt=1
|
||||
ro.vendor.radio.oppo.signal.adapt=true
|
||||
persist.vendor.radio.enable_temp_dds=true
|
||||
persist.vendor.radio.custom_ecc=1
|
||||
persist.vendor.radio.data_ltd_sys_ind=1
|
||||
|
||||
# ScrollOptimizer
|
||||
persist.sys.perf.scroll_opt=true
|
||||
persist.sys.perf.scroll_opt.heavy_app=1
|
||||
|
||||
# Sensors
|
||||
persist.vendor.sensors.odl.adsp=true
|
||||
|
||||
Reference in New Issue
Block a user