[SQUASH] sapphire: parts: Import XiaomiParts
e261035d91/parts
Change-Id: I442f48780ca020f3e420ee4ccaf8ac07b05457cb
Signed-off-by: Anush02198 <anush.4376@gmail.com>
Signed-off-by: Ramadhani <ramadhanifals@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garnet: parts: Fix cannot find symbol error for UQPR2
Signed-off-by: Ramadhani <ramadhanifals@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garnet: parts: Migrate to CompoundButton.OnCheckedChangeListener
This fixes compilation error for UQPR2.
Signed-off-by: Ramadhani <ramadhanifals@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garnet: parts: Checkout thermal profiles to xiaomi-sm8250 implementation
Signed-off-by: Ramadhani <ramadhanifals@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garnet: parts: Fix thermal profile screen state handling
Signed-off-by: Ramadhani <ramadhanifals@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garnet: Remove order preference for Thermal Profiles
- In Infinity X rom this tab at top spoils the look of Battery section
Signed-off-by: Ramadhani <ramadhanifals@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garnet: parts: Drop doze settings
Signed-off-by: kleidione <kleidione@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garnet: parts: Refactor ClearSpeakerFragment code
- Removed unused imports
- Proper resource release by using try-finally block
- Added null checks for MediaPlayer methods
- Remove audio parameter as its unused
Change-Id: I7dc2ba7baf6e0193e13583a7454da296254d7333
Signed-off-by: Jyotiraditya Panda <jyotiraditya@aospa.co>
Signed-off-by: Adithya R <gh0strider.2k18.reborn@gmail.com>
Signed-off-by: Coptan99 <omarcoptan9@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garent: parts: Get rid of proguard flags
This is obsolete.
Change-Id: I1b692d3e1a96c49ac6efd54907ea23c4b4494f7e
Signed-off-by: Ramadhani <ramadhanifals@gmail.com>
Signed-off-by: Drenzzz <naufalnazya@gmail.com>
garnet: parts: Supports 90hz refresh rate
Co-Authored-By: Arian <39061882+ArianK16a@users.noreply.github.com>
sapphire: parts: Remove unused HDR override in BootCompletedReceiver for
non-HDR devices
Removed the `overrideHdrTypes` method and its call in
`BootCompletedReceiver`
since the target device does not support HDR10, Dolby Vision, HLG, or
HDR10+.
Also removed unused imports (`DisplayManager`, `Display`,
`HdrCapabilities`,
`IntentFilter`, `IBinder`) to clean up the code. This prevents the
system from
falsely advertising HDR capabilities, avoiding potential app
compatibility issues.
The `ThermalUtils` and `RefreshUtils` service startups remain unchanged.
Signed-off-by: Saroj-Tajpuriya
<80759612+saroj-nokia@users.noreply.github.com>
garnet: parts: Start parts services as early as possible on bootup
BOOT_COMPLETED intent is broadcast only after the device is unlocked and
user data (encrypted storage) is available.
Use LOCKED_BOOT_COMPLETED intent for services that don't require
accessing data.
Change-Id: I800df08f9c61925ac394f3e6d4861ba68a157797
Signed-off-by: kenway214 <kenway214@outlook.com>
Co-Authored-By: Adithya R <gh0strider.2k18.reborn@gmail.com>
Signed-off-by: UnmoveD <unmoved2121@gmail.com>
sapphire: Remove HDR type override from BootCompletedReceiver
sapphire: parts: Add permissions and whitelist for Xiaomi parts
- Added `privapp_whitelist_org.lineageos.settings.xml
- Updated AndroidManifest.xml with required permissions:
- `android.permission.INTERACT_ACROSS_USERS_FULL` for cross-user
interactions.
- `android.permission.WRITE_SETTINGS` for modifying system settings.
- Whitelisted `android.permission.WRITE_SECURE_SETTINGS` for the
`org.lineageos.settings`
package to ensure functionality requiring secure settings
modification.
Signed-off-by: kenway214 <kenway214@outlook.com>
Signed-off-by: UnmoveD <unmoved2121@gmail.com>
sapphire: parts: Introduce Display Satutaion Service and TileUtils
* Adjust Saturation Value Handling for Device Color Mode Compatibility
This update refines the saturation adjustment mechanism. When the seek
bar progress is set, the method executes
the command "service call SurfaceFlinger 1022 f [saturation]" via
Runtime.getRuntime().exec() to apply the saturation changes.
However, it was observed that when the device's color mode is set to
"saturated," a saturation value of 1.0 does not trigger any visual
changes.
To address this, the code now sets a value of 1.001 for a seek bar value
of 100, ensuring the desired effect is consistently applied.
* TileUtils Implementation: Implemented TileUtils to handle the addition
of Quick Settings tiles, specifically for the saturation feature.
This is done with reference to the guidelines provided by Google
https://developer.android.com/develop/ui/views/quicksettings-tiles#prompt-user
this ensuring a seamless integration and user experience when creating
new tiles.
Signed-off-by: Pabloescobar-reborn <pabloescobarreborn77@gmail.com>
Co-Authored-By: kenway214 <kenway214@outlook.com>
Co-Authored-By: AnierinB <anierin@evolution-x.org>
Co-Authored-By: SKULSHADY <anushekprasal@gmail.com>
Co-Authored-By: jhenrique09 <jhenrique09.mcz@hotmail.com>
Signed-off-by: UnmoveD <unmoved2121@gmail.com>
sapphire: parts: Remove unused import for DisplayManager in
BootCompletedReceiver
sapphire: parts: Introduce High Brightness Mode (HBM) and Auto HBM QS
tile
* Before anyone bullies me for this, I know this is very dumb way, but
it works.....
( its just a haxx not actual hbm)
* Also introduce TileHandlerActivity to add support for long-press
actions on QS tiles
- AutoHbmTileService → AutoHbmActivity
Signed-off-by: pabloescobar-reborn <pabloescobarreborn77@gmail.com>
Signed-off-by: kenway214 <kenway214@outlook.com>
Co-Authored-By: AnierinB <anierin@evolution-x.org>
Signed-off-by: UnmoveD <unmoved2121@gmail.com>
Signed-off-by: Saroj-Tajpuriya
<80759612+saroj-nokia@users.noreply.github.com>
sapphire: parts: Switch back to thermal profiles
nuked thermal tile service
Signed-off-by: UnmoveD <unmoved2121@gmail.com>
sapphire: parts: Introduce GameBar v4.0
Signed-off-by: kenway214 <kenway214@outlook.com>
peridot: parts: Add FPS meter support with selectable method for GameBar
- Introduced `GameBarFpsMeter` class to support FPS overlay using the
new Android 13+ TaskFpsCallback API.
- Added fallback legacy sysfs method
(`/sys/class/drm/sde-crtc-0/measured_fps`) for older devices.
- Updated GameBar to show FPS using selected method.
Signed-off-by: kenway214 <kenway214@outlook.com>
bump to v4
4
Signed-off-by: UnmoveD <unmoved2121@gmail.com>
sapphire: parts: Fix compilation error in BootCompletedReceiver for
DozeUtils
Signed-off-by: Saroj-Tajpuriya
<80759612+saroj-nokia@users.noreply.github.com>
Update BootCompletedReceiver.java
Signed-off-by: Saroj-Tajpuriya
<80759612+saroj-nokia@users.noreply.github.com>
sapphire: parts: remove duplicate TileHandlerActivity
Signed-off-by: Saroj-Tajpuriya
<80759612+saroj-nokia@users.noreply.github.com>
Co-Authored-By: AspectPower <AspectPower@proton.me>
Co-Authored-By: kenway214 <kenway214@outlook.com>
Co-Authored-By: AnierinB <anierin@evolution-x.org>
Co-Authored-By: SKULSHADY <anushekprasal@gmail.com>
Co-Authored-By: jhenrique09 <jhenrique09.mcz@hotmail.com>
Co-Authored-By: Arian <39061882+ArianK16a@users.noreply.github.com>
Co-Authored-By: Jyotiraditya Panda <jyotiraditya@aospa.co>
Co-Authored-By: Adithya R <gh0strider.2k18.reborn@gmail.com>
Co-Authored-By: Coptan99 <omarcoptan9@gmail.com>
Co-Authored-By: Drenzzz <naufalnazya@gmail.com>
Co-Authored-By: Ramadhani <ramadhanifals@gmail.com>
Co-Authored-By: Anush02198 <anush.4376@gmail.com>
Co-Authored-By: UnmoveD <unmoved2121@gmail.com>
This commit is contained in:
@@ -452,6 +452,10 @@ endif
|
||||
DEVICE_PACKAGE_OVERLAYS += \
|
||||
$(LOCAL_PATH)/overlay-lineage
|
||||
|
||||
# Device-specific settings
|
||||
PRODUCT_PACKAGES += \
|
||||
XiaomiParts
|
||||
|
||||
# Partitions
|
||||
PRODUCT_USE_DYNAMIC_PARTITIONS := true
|
||||
|
||||
|
||||
32
parts/Android.bp
Normal file
32
parts/Android.bp
Normal file
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Copyright (C) 2017-2020 The LineageOS Project
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
android_app {
|
||||
name: "XiaomiParts",
|
||||
|
||||
srcs: ["src/**/*.java"],
|
||||
|
||||
certificate: "platform",
|
||||
platform_apis: true,
|
||||
system_ext_specific: true,
|
||||
privileged: true,
|
||||
|
||||
static_libs: [
|
||||
"org.lineageos.settings.resources",
|
||||
],
|
||||
|
||||
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,
|
||||
}
|
||||
268
parts/AndroidManifest.xml
Normal file
268
parts/AndroidManifest.xml
Normal file
@@ -0,0 +1,268 @@
|
||||
<?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.INTERACT_ACROSS_USERS_FULL" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
|
||||
<uses-sdk
|
||||
android:minSdkVersion="24"
|
||||
android:targetSdkVersion="30"/>
|
||||
|
||||
<application
|
||||
android:label="@string/device_settings_app_name"
|
||||
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>
|
||||
|
||||
<activity
|
||||
android:name=".thermal.ThermalActivity"
|
||||
android:label="@string/thermal_title">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.settings.action.IA_SETTINGS" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="com.android.settings.category"
|
||||
android:value="com.android.settings.category.ia.battery" />
|
||||
<meta-data
|
||||
android:name="com.android.settings.summary"
|
||||
android:resource="@string/thermal_summary" />
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".thermal.ThermalService"
|
||||
android:permission="ThermalService">
|
||||
</service>
|
||||
|
||||
<activity
|
||||
android:name=".speaker.ClearSpeakerActivity"
|
||||
android:label="@string/clear_speaker_title">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.settings.action.IA_SETTINGS" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="com.android.settings.category"
|
||||
android:value="com.android.settings.category.ia.sound" />
|
||||
<meta-data
|
||||
android:name="com.android.settings.summary"
|
||||
android:resource="@string/clear_speaker_summary" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".refreshrate.RefreshActivity"
|
||||
android:label="@string/refresh_title"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.settings.action.IA_SETTINGS" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="com.android.settings.category"
|
||||
android:value="com.android.settings.category.ia.display" />
|
||||
<meta-data
|
||||
android:name="com.android.settings.summary"
|
||||
android:resource="@string/refresh_summary" />
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".refreshrate.RefreshService"
|
||||
android:exported="true"
|
||||
android:permission="RefreshService">
|
||||
</service>
|
||||
|
||||
<!-- Display Saturation activity -->
|
||||
<activity
|
||||
android:name=".saturation.SaturationActivity"
|
||||
android:label="@string/saturation_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.display" />
|
||||
<meta-data
|
||||
android:name="com.android.settings.summary"
|
||||
android:resource="@string/saturation_summary" />
|
||||
</activity>
|
||||
|
||||
<!-- Display Saturation tile service -->
|
||||
<service
|
||||
android:name=".saturation.SaturationTileService"
|
||||
android:label="@string/saturation_title"
|
||||
android:icon="@drawable/ic_saturation_tile"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Auto HBM activity -->
|
||||
<activity
|
||||
android:name=".autohbm.AutoHbmActivity"
|
||||
android:label="@string/auto_hbm_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.display" />
|
||||
<meta-data
|
||||
android:name="com.android.settings.summary"
|
||||
android:resource="@string/auto_hbm_summary" />
|
||||
</activity>
|
||||
|
||||
<!-- Auto HBM service -->
|
||||
<service
|
||||
android:name=".autohbm.AutoHbmService"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- Auto HBM tile service -->
|
||||
<service
|
||||
android:name=".autohbm.AutoHbmTileService"
|
||||
android:label="@string/auto_hbm_title"
|
||||
android:icon="@drawable/ic_auto_hbm_tile"
|
||||
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="true" />
|
||||
</service>
|
||||
|
||||
<!--HBM tile service -->
|
||||
<service
|
||||
android:name=".autohbm.HbmTileService"
|
||||
android:label="@string/tile_hbm"
|
||||
android:icon="@drawable/ic_hbm_tile"
|
||||
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="true" />
|
||||
</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>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023 Paranoid Android
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<permissions>
|
||||
<privapp-permissions package="org.lineageos.settings">
|
||||
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
</privapp-permissions>
|
||||
</permissions>
|
||||
BIN
parts/res/drawable-nodpi/image_preview1.jpg
Normal file
BIN
parts/res/drawable-nodpi/image_preview1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
parts/res/drawable-nodpi/image_preview1.webp
Normal file
BIN
parts/res/drawable-nodpi/image_preview1.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 215 KiB |
BIN
parts/res/drawable-nodpi/image_preview2.jpg
Normal file
BIN
parts/res/drawable-nodpi/image_preview2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
parts/res/drawable-nodpi/image_preview2.webp
Normal file
BIN
parts/res/drawable-nodpi/image_preview2.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 75 KiB |
BIN
parts/res/drawable-nodpi/image_preview3.jpg
Normal file
BIN
parts/res/drawable-nodpi/image_preview3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 240 KiB |
BIN
parts/res/drawable-nodpi/image_preview3.webp
Normal file
BIN
parts/res/drawable-nodpi/image_preview3.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 187 KiB |
11
parts/res/drawable/ic_auto_hbm_tile.xml
Normal file
11
parts/res/drawable/ic_auto_hbm_tile.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<!-- drawable/ic_auto_hbm_tile.xml -->
|
||||
<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/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M11,4V1H13V4ZM11,23V20H13V23ZM20,13V11H23V13ZM1,13V11H4V13ZM18.7,6.7 L17.3,5.3 19.05,3.5 20.5,4.95ZM4.95,20.5 L3.5,19.05 5.3,17.3 6.7,18.7ZM19.05,20.5 L17.3,18.7 18.7,17.3 20.5,19.05ZM5.3,6.7 L3.5,4.95 4.95,3.5 6.7,5.3ZM12,18Q9.5,18 7.75,16.25Q6,14.5 6,12Q6,9.5 7.75,7.75Q9.5,6 12,6Q14.5,6 16.25,7.75Q18,9.5 18,12Q18,14.5 16.25,16.25Q14.5,18 12,18ZM12,16Q13.675,16 14.838,14.837Q16,13.675 16,12Q16,10.325 14.838,9.162Q13.675,8 12,8Q10.325,8 9.163,9.162Q8,10.325 8,12Q8,13.675 9.163,14.837Q10.325,16 12,16ZM12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Z"/>
|
||||
</vector>
|
||||
13
parts/res/drawable/ic_clear_speaker.xml
Normal file
13
parts/res/drawable/ic_clear_speaker.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M20 4H4C2.9 4 2 4.9 2 6v12c0 1.1 0.9 2 2 2h16c1.1 0 2-0.9 2-2V6c0-1.1-0.9-2-2-2zm0 14H4V6h16v12z"/>
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M8.29 15.71c-0.49-0.49-0.88-1.06-1.14-1.7c-0.26-0.64-0.4-1.32-0.4-2.01c0-1.35 0.52-2.69 1.53-3.72L7.05 7.05C5.68 8.41 5 10.21 5 12s0.68 3.59 2.06 4.94l1.23-1.23zM12 15.5c1.93 0 3.5-1.57 3.5-3.5S13.93 8.5 12 8.5S8.5 10.07 8.5 12s1.57 3.5 3.5 3.5zm0-5c0.83 0 1.5 0.67 1.5 1.5s-0.67 1.5-1.5 1.5s-1.5-0.67-1.5-1.5s0.67-1.5 1.5-1.5zm3.72 5.22l1.23 1.23C18.32 15.59 19 13.79 19 12s-0.68-3.59-2.06-4.94l-1.23 1.23c0.49 0.49 0.88 1.06 1.14 1.7c0.26 0.64 0.4 1.32 0.4 2.01c0 1.35-0.52 2.69-1.53 3.72z"/>
|
||||
</vector>
|
||||
14
parts/res/drawable/ic_custom_seekbar_minus.xml
Normal file
14
parts/res/drawable/ic_custom_seekbar_minus.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018-2022 crDroid Android Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0" >
|
||||
<path
|
||||
android:fillColor="?android:attr/colorControlNormal"
|
||||
android:pathData="M24 4C12.972 4 4 12.972 4 24s8.972 20 20 20s20 -8.972 20 -20S35.028 4 24 4zM32.5 25.5h-17c-0.829 0 -1.5 -0.671 -1.5 -1.5s0.671 -1.5 1.5 -1.5h17c0.829 0 1.5 0.671 1.5 1.5S33.329 25.5 32.5 25.5z" />
|
||||
</vector>
|
||||
14
parts/res/drawable/ic_custom_seekbar_plus.xml
Normal file
14
parts/res/drawable/ic_custom_seekbar_plus.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018-2022 crDroid Android Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="48.0"
|
||||
android:viewportHeight="48.0" >
|
||||
<path
|
||||
android:fillColor="?android:attr/colorControlNormal"
|
||||
android:pathData="M24 4C12.972 4 4 12.972 4 24s8.972 20 20 20s20 -8.972 20 -20S35.028 4 24 4zM32.5 25.5h-7v7c0 0.829 -0.672 1.5 -1.5 1.5s-1.5 -0.671 -1.5 -1.5v-7h-7c-0.828 0 -1.5 -0.671 -1.5 -1.5s0.672 -1.5 1.5 -1.5h7v-7c0 -0.829 0.672 -1.5 1.5 -1.5s1.5 0.671 1.5 1.5v7h7c0.828 0 1.5 0.671 1.5 1.5S33.328 25.5 32.5 25.5z" />
|
||||
</vector>
|
||||
15
parts/res/drawable/ic_custom_seekbar_reset.xml
Normal file
15
parts/res/drawable/ic_custom_seekbar_reset.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2019 Havoc-OS
|
||||
2022 DerpFest
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24.0dp"
|
||||
android:height="24.0dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0" >
|
||||
<path
|
||||
android:fillColor="?android:attr/colorControlNormal"
|
||||
android:pathData="M14.123456746339798,12.042328000068665 c0,-0.7430335164070133 -0.6079365134239197,-1.3509700298309326 -1.3509700298309326,-1.3509700298309326 s-1.3509700298309326,0.6079365134239197 -1.3509700298309326,1.3509700298309326 s0.6079365134239197,1.3509700298309326 1.3509700298309326,1.3509700298309326 s1.3509700298309326,-0.6079365134239197 1.3509700298309326,-1.3509700298309326 zM12.772486716508865,5.962962865829468 c-3.3571605241298674,0 -6.079365134239197,2.7222046101093293 -6.079365134239197,6.079365134239197 L4.66666653752327,12.042328000068665 l2.7019400596618652,2.7019400596618652 l2.7019400596618652,-2.7019400596618652 L8.044091612100601,12.042328000068665 c0,-2.6141270077228547 2.1142680966854095,-4.728395104408264 4.728395104408264,-4.728395104408264 s4.728395104408264,2.1142680966854095 4.728395104408264,4.728395104408264 s-2.1142680966854095,4.728395104408264 -4.728395104408264,4.728395104408264 c-1.0199823725223542,0 -1.965661393404007,-0.3309876573085789 -2.742469160556793,-0.8781305193901066 l-0.9591887211799618,0.9726984214782719 C10.097566057443618,17.648853623867033 11.380987585783004,18.12169313430786 12.772486716508865,18.12169313430786 c3.3571605241298674,0 6.079365134239197,-2.7222046101093293 6.079365134239197,-6.079365134239197 s-2.7222046101093293,-6.079365134239197 -6.079365134239197,-6.079365134239197 z" />
|
||||
</vector>
|
||||
11
parts/res/drawable/ic_gamebar.xml
Normal file
11
parts/res/drawable/ic_gamebar.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?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>
|
||||
10
parts/res/drawable/ic_hbm_tile.xml
Normal file
10
parts/res/drawable/ic_hbm_tile.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,680Q397,680 338.5,621.5Q280,563 280,480Q280,397 338.5,338.5Q397,280 480,280Q563,280 621.5,338.5Q680,397 680,480Q680,563 621.5,621.5Q563,680 480,680ZM73.33,517.88Q57.33,517.88 46.39,506.9Q35.46,495.93 35.46,479.88Q35.46,463.83 46.39,452.98Q57.33,442.12 73.33,442.12L166.67,442.12Q182.67,442.12 193.61,453.1Q204.54,464.07 204.54,480.12Q204.54,496.17 193.61,507.02Q182.67,517.88 166.67,517.88L73.33,517.88ZM793.33,517.88Q777.33,517.88 766.39,506.9Q755.46,495.93 755.46,479.88Q755.46,463.83 766.39,452.98Q777.33,442.12 793.33,442.12L886.67,442.12Q902.67,442.12 913.61,453.1Q924.54,464.07 924.54,480.12Q924.54,496.17 913.61,507.02Q902.67,517.88 886.67,517.88L793.33,517.88ZM479.88,204.54Q463.83,204.54 452.98,193.61Q442.12,182.67 442.12,166.67L442.12,73.33Q442.12,57.33 453.1,46.39Q464.07,35.46 480.12,35.46Q496.17,35.46 507.02,46.39Q517.88,57.33 517.88,73.33L517.88,166.67Q517.88,182.67 506.9,193.61Q495.93,204.54 479.88,204.54ZM479.88,924.54Q463.83,924.54 452.98,913.61Q442.12,902.67 442.12,886.67L442.12,793.33Q442.12,777.33 453.1,766.39Q464.07,755.46 480.12,755.46Q496.17,755.46 507.02,766.39Q517.88,777.33 517.88,793.33L517.88,886.67Q517.88,902.67 506.9,913.61Q495.93,924.54 479.88,924.54ZM232.15,285.43L179.81,234.09Q168.46,223.07 168.87,207.17Q169.28,191.27 179.74,179.74Q190.95,168.46 206.77,168.46Q222.59,168.46 233.85,179.81L285.43,232.15Q295.78,243.42 295.74,258.63Q295.7,273.83 285.43,284.86Q274.91,295.88 259.21,295.95Q243.5,296.02 232.15,285.43ZM726.15,780.19L674.57,727.85Q664.22,716.58 664.22,701.08Q664.22,685.57 674.91,674.81Q685.59,663.46 701.05,663.62Q716.5,663.79 727.85,674.81L780.19,725.91Q791.54,736.93 791.13,752.83Q790.72,768.73 780.26,780.26Q769.05,791.54 753.23,791.54Q737.41,791.54 726.15,780.19ZM674.81,285.43Q663.46,274.41 663.62,258.95Q663.79,243.5 674.81,232.15L725.91,179.81Q736.93,168.46 752.83,168.87Q768.73,169.28 780.26,179.74Q791.54,190.95 791.54,206.77Q791.54,222.59 780.19,233.85L727.85,285.43Q717.25,295.78 701.8,295.74Q686.35,295.7 674.81,285.43ZM179.74,780.26Q168.46,769.05 168.46,753.23Q168.46,737.41 179.81,726.15L232.15,674.57Q243.29,663.55 258.61,663.55Q273.93,663.55 284.93,674.57Q296.54,685.59 296.38,701.05Q296.21,716.5 285.19,727.85L234.09,780.19Q223.07,791.54 207.17,791.13Q191.27,790.72 179.74,780.26Z"/>
|
||||
</vector>
|
||||
18
parts/res/drawable/ic_image_preview_arrow_left.xml
Normal file
18
parts/res/drawable/ic_image_preview_arrow_left.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M0,0h24v24h-24z"/>
|
||||
<path
|
||||
android:pathData="M16.41,18.59L15,20L7,12L15,4L16.41,5.41L9.83,12"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
18
parts/res/drawable/ic_image_preview_arrow_right.xml
Normal file
18
parts/res/drawable/ic_image_preview_arrow_right.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M0,0h24v24h-24z"/>
|
||||
<path
|
||||
android:pathData="M7.59,5.41L9,4L17,12L9,20L7.59,18.59L14.17,12"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="6dp"
|
||||
android:height="6dp"
|
||||
android:viewportWidth="6"
|
||||
android:viewportHeight="6">
|
||||
<path
|
||||
android:pathData="M3,0C4.65686,0 6,1.34315 6,3C6,4.65686 4.65685,6 3,6C1.34315,6 0,4.65685 0,3C0,1.34315 1.34315,0 3,0Z"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="6dp"
|
||||
android:height="6dp"
|
||||
android:viewportWidth="6"
|
||||
android:viewportHeight="6">
|
||||
<path
|
||||
android:pathData="M3,0C4.65686,0 6,1.34315 6,3C6,4.65686 4.65685,6 3,6C1.34315,6 0,4.65685 0,3C0,1.34315 1.34315,0 3,0Z"
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillAlpha="0.24"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
22
parts/res/drawable/ic_refresh_120.xml
Normal file
22
parts/res/drawable/ic_refresh_120.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M17 1.01L7 1C5.9 1 5 1.9 5 3v4h2V3h10v18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M1 8v1.56h1.56v6.22H4.1V8H1Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M4.89 8v1.56H8v1.55H6.44c-0.4 0-0.8 0.17-1.1 0.46-0.29 0.29-0.45 0.68-0.45 1.1v3.1h4.67v-1.55H6.44v-1.55H8c0.41 0 0.8-0.17 1.1-0.46 0.3-0.3 0.46-0.69 0.46-1.1V9.56c0-0.42-0.17-0.81-0.46-1.1C8.8 8.16 8.41 8 8 8H4.89Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:strokeColor="#ff000000"
|
||||
android:strokeWidth="1"
|
||||
android:pathData="M11.89 9.06h-0.5v0.5 4.66 0.5h0.5 1.55 0.5v-0.5-4.66-0.5h-0.5-1.55ZM11.14 8.8c0.2-0.2 0.47-0.31 0.75-0.31h1.55c0.28 0 0.55 0.11 0.75 0.3 0.2 0.2 0.31 0.48 0.31 0.76v4.66c0 0.28-0.11 0.55-0.3 0.75-0.2 0.2-0.48 0.3-0.76 0.3H11.9c-0.28 0-0.55-0.1-0.75-0.3-0.2-0.2-0.3-0.47-0.3-0.75V9.56c0-0.28 0.1-0.55 0.3-0.75Z"/>
|
||||
</vector>
|
||||
17
parts/res/drawable/ic_refresh_60.xml
Normal file
17
parts/res/drawable/ic_refresh_60.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M6.55 8c-0.4 0-0.8 0.16-1.1 0.46C5.17 8.75 5 9.14 5 9.56v4.66c0 0.4 0.16 0.8 0.46 1.1 0.29 0.29 0.68 0.45 1.1 0.45H8.1c0.41 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1v-1.55c0-0.41-0.16-0.8-0.45-1.1-0.3-0.29-0.69-0.45-1.1-0.45H6.55V9.55h3.11V8h-3.1Zm0 4.66h1.56v1.56H6.55v-1.56Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M12 8c-0.42 0-0.81 0.16-1.1 0.46-0.3 0.29-0.46 0.68-0.46 1.1v4.66c0 0.4 0.16 0.8 0.45 1.1 0.3 0.29 0.69 0.45 1.1 0.45h1.56c0.4 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1V9.56c0-0.4-0.16-0.8-0.46-1.1C14.35 8.17 13.96 8 13.54 8H12Zm0 1.55h1.55v4.67h-1.56V9.55Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M17 1.01L7 1C5.9 1 5 1.9 5 3v4h2V3h10v18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99Z"/>
|
||||
</vector>
|
||||
17
parts/res/drawable/ic_refresh_90.xml
Normal file
17
parts/res/drawable/ic_refresh_90.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M17 1.01L7 1C5.9 1 5 1.9 5 3v4h2V3h10v18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M8.1 15.77c0.42 0 0.82-0.16 1.1-0.46 0.3-0.29 0.46-0.68 0.46-1.1V9.56c0-0.4-0.16-0.8-0.45-1.1C8.9 8.17 8.52 8 8.1 8H6.55c-0.4 0-0.8 0.16-1.1 0.46C5.17 8.75 5 9.14 5 9.56v1.55c0 0.41 0.16 0.8 0.46 1.1 0.29 0.29 0.68 0.45 1.1 0.45H8.1v1.56H5v1.55h3.1Zm0-4.66H6.56V9.55h1.56v1.56Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M12 8c-0.42 0-0.81 0.16-1.1 0.46-0.3 0.29-0.46 0.68-0.46 1.1v4.66c0 0.4 0.16 0.8 0.45 1.1 0.3 0.29 0.69 0.45 1.1 0.45h1.56c0.4 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1V9.56c0-0.4-0.16-0.8-0.46-1.1C14.35 8.17 13.96 8 13.54 8H12Zm0 1.55h1.55v4.67h-1.56V9.55Z"/>
|
||||
</vector>
|
||||
11
parts/res/drawable/ic_refresh_default.xml
Normal file
11
parts/res/drawable/ic_refresh_default.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M17 3.01V15l2 2V3.01c0-1.1-0.9-1.99-2-1.99L7 1C6 0.99 5 1.99 5 2.99L7 5V3.01h10Zm4.2 18.19L19 19.01l-2-2-10-10-2-2-2.19-2.19L1.4 4.23 5 7.84v13.17c0 1.1 0.9 2 2 2h10c0.85 0 1.58-0.55 1.87-1.3l0.91 0.91 1.41-1.42ZM17 21.01H7L17 21v-0.99 1Zm-10 0V9.84l10 10.17V21L7 21.01Z"/>
|
||||
</vector>
|
||||
11
parts/res/drawable/ic_saturation_tile.xml
Normal file
11
parts/res/drawable/ic_saturation_tile.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<!-- drawable/ic_saturation_tile -->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M17.5,12A1.5,1.5 0 0,1 16,10.5A1.5,1.5 0 0,1 17.5,9A1.5,1.5 0 0,1 19,10.5A1.5,1.5 0 0,1 17.5,12M14.5,8A1.5,1.5 0 0,1 13,6.5A1.5,1.5 0 0,1 14.5,5A1.5,1.5 0 0,1 16,6.5A1.5,1.5 0 0,1 14.5,8M9.5,8A1.5,1.5 0 0,1 8,6.5A1.5,1.5 0 0,1 9.5,5A1.5,1.5 0 0,1 11,6.5A1.5,1.5 0 0,1 9.5,8M6.5,12A1.5,1.5 0 0,1 5,10.5A1.5,1.5 0 0,1 6.5,9A1.5,1.5 0 0,1 8,10.5A1.5,1.5 0 0,1 6.5,12M12,3A9,9 0 0,0 3,12A9,9 0 0,0 12,21A1.5,1.5 0 0,0 13.5,19.5C13.5,19.11 13.35,18.76 13.11,18.5C12.88,18.23 12.73,17.88 12.73,17.5A1.5,1.5 0 0,1 14.23,16H16A5,5 0 0,0 21,11C21,6.58 16.97,3 12,3Z" />
|
||||
</vector>
|
||||
9
parts/res/drawable/ic_scenes.xml
Normal file
9
parts/res/drawable/ic_scenes.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<!-- 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>
|
||||
19
parts/res/drawable/ic_thermal_benchmark.xml
Normal file
19
parts/res/drawable/ic_thermal_benchmark.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group
|
||||
android:scaleX="5.50297"
|
||||
android:scaleY="5.52411"
|
||||
android:translateX="-59.0634"
|
||||
android:translateY="-57.934">
|
||||
<path
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M10.961 13.514c0 -1.078 0.874 -1.952 1.953 -1.952 0.555 0 1.057 0.232 1.412 0.604l-0.583 0.141c-0.236 -0.162 -0.522 -0.257 -0.829 -0.257 -0.809 0 -1.465 0.655 -1.465 1.464l0 0c0 0.135 -0.109 0.244 -0.244 0.244 -0.134 0 -0.244 -0.109 -0.244 -0.244l0 0zm3.417 0c0 -0.094 -0.009 -0.185 -0.026 -0.274l0.429 -0.297c0.055 0.181 0.085 0.373 0.085 0.571 0 0.135 -0.109 0.244 -0.244 0.244 -0.135 0 -0.244 -0.109 -0.244 -0.244l0 0zm-0.02 -1.097c0.102 -0.028 0.212 0.022 0.256 0.121 0.045 0.101 0.007 0.219 -0.085 0.275l0 0 -1.313 0.833c-0.011 0.008 -0.023 0.016 -0.035 0.023l-0.001 0 0 0c-0.013 0.008 -0.025 0.014 -0.039 0.02 -0.226 0.101 -0.491 0 -0.592 -0.226 -0.101 -0.225 0 -0.491 0.226 -0.592 0.026 -0.012 0.052 -0.021 0.079 -0.027l1.504 -0.427 0 0z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeMiterLimit="1.41421" />
|
||||
</group>
|
||||
</vector>
|
||||
11
parts/res/drawable/ic_thermal_browser.xml
Normal file
11
parts/res/drawable/ic_thermal_browser.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
|
||||
<path
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M2.546,5.862C4.557,2.772 8.042,0.727 12,0.727C15.958,0.727 19.443,2.772 21.454,5.862C21.584,5.947 21.674,6.086 21.694,6.246C22.697,7.931 23.273,9.899 23.273,12C23.273,18.222 18.222,23.273 12,23.273C5.778,23.273 0.727,18.222 0.727,12C0.727,9.899 1.303,7.931 2.306,6.246C2.326,6.086 2.416,5.947 2.546,5.862ZM7.784,18.049L5.229,18.049C6.602,19.585 8.49,20.651 10.62,20.977C9.503,20.219 8.537,19.221 7.784,18.049ZM18.771,18.049L16.31,18.049C15.564,19.211 14.608,20.202 13.503,20.957C15.583,20.61 17.424,19.555 18.771,18.049ZM13.235,18.049L10.86,18.049C11.207,18.703 11.606,19.307 12.047,19.852C12.488,19.307 12.888,18.703 13.235,18.049ZM6.086,13.083L2.983,13.083C3.101,14.074 3.379,15.016 3.79,15.882L6.713,15.882C6.393,15.001 6.178,14.062 6.086,13.083ZM21.017,13.083L18.008,13.083C17.916,14.062 17.702,15.001 17.382,15.882L20.21,15.882C20.621,15.016 20.899,14.074 21.017,13.083ZM14.67,13.083L9.424,13.083C9.503,14.057 9.689,14.997 9.962,15.882L14.132,15.882C14.406,14.997 14.591,14.057 14.67,13.083ZM6.78,7.939L3.877,7.939C3.418,8.854 3.109,9.858 2.983,10.917L6.086,10.917C6.184,9.872 6.422,8.871 6.78,7.939ZM20.123,7.939L17.315,7.939C17.672,8.871 17.91,9.872 18.008,10.917L21.017,10.917C20.891,9.858 20.582,8.854 20.123,7.939ZM14.076,7.939L10.019,7.939C9.714,8.877 9.509,9.877 9.424,10.917L14.67,10.917C14.585,9.877 14.38,8.877 14.076,7.939ZM10.62,3.023C8.574,3.336 6.751,4.333 5.393,5.772L7.901,5.772C8.637,4.677 9.56,3.742 10.62,3.023ZM13.503,3.043C14.551,3.759 15.465,4.687 16.193,5.772L18.607,5.772C17.276,4.361 15.499,3.376 13.503,3.043ZM12.047,4.148C11.647,4.643 11.281,5.187 10.957,5.772L13.138,5.772C12.814,5.187 12.448,4.643 12.047,4.148Z" />
|
||||
</vector>
|
||||
19
parts/res/drawable/ic_thermal_camera.xml
Normal file
19
parts/res/drawable/ic_thermal_camera.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group
|
||||
android:scaleX="0.879929"
|
||||
android:scaleY="0.883309"
|
||||
android:translateX="1.44085"
|
||||
android:translateY="0.746289">
|
||||
<path
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M20.764 21.26l-17.528 0c-1.07 0 -1.939 -0.868 -1.939 -1.939l0 -11.324c0 -1.07 0.869 -1.939 1.939 -1.939l4.534 0C7.982 5.01 8.91 4.22 10.02 4.22l3.96 0c1.11 0 2.037 0.79 2.25 1.838l4.534 0c1.07 0 1.939 0.869 1.939 1.939l0 11.324c0 1.071 -0.869 1.939 -1.939 1.939zM12 8.646c2.767 0 5.013 2.246 5.013 5.013 0 2.767 -2.246 5.013 -5.013 5.013 -2.767 0 -5.013 -2.246 -5.013 -5.013 0 -2.767 2.246 -5.013 5.013 -5.013zM3.674 7.257c0.624 0 1.131 0.507 1.131 1.131 0 0.624 -0.507 1.131 -1.131 1.131 -0.624 0 -1.131 -0.507 -1.131 -1.131 0 -0.624 0.507 -1.131 1.131 -1.131z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeMiterLimit="1.41421" />
|
||||
</group>
|
||||
</vector>
|
||||
19
parts/res/drawable/ic_thermal_default.xml
Normal file
19
parts/res/drawable/ic_thermal_default.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group
|
||||
android:scaleX="1.05866"
|
||||
android:scaleY="1.05866"
|
||||
android:translateX="-0.652026"
|
||||
android:translateY="-0.703971">
|
||||
<path
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M11.066 10.383l0 -2.773 -2.033 -2.033c-0.364 -0.365 -0.364 -0.956 0 -1.321 0.365 -0.364 0.956 -0.364 1.321 0l0.712 0.713 0 -1.111c0 -0.515 0.419 -0.934 0.934 -0.934 0.515 0 0.934 0.419 0.934 0.934l0 1.111 0.712 -0.713c0.365 -0.364 0.956 -0.364 1.321 0 0.364 0.365 0.364 0.956 0 1.321l-2.033 2.033 0 2.773 2.401 -1.387 0.744 -2.777c0.134 -0.498 0.646 -0.794 1.144 -0.66 0.498 0.133 0.794 0.646 0.66 1.143L17.622 7.676 18.584 7.12c0.447 -0.257 1.018 -0.104 1.276 0.342 0.258 0.446 0.104 1.018 -0.342 1.276l-0.962 0.555 0.973 0.261c0.498 0.133 0.794 0.646 0.661 1.144 -0.134 0.497 -0.646 0.793 -1.144 0.66L16.269 10.614 13.868 12l2.401 1.386 2.777 -0.744c0.498 -0.133 1.01 0.163 1.144 0.66 0.133 0.498 -0.163 1.011 -0.661 1.144l-0.973 0.261 0.962 0.555c0.446 0.258 0.6 0.83 0.342 1.276 -0.258 0.446 -0.829 0.599 -1.276 0.342l-0.962 -0.556 0.261 0.974c0.134 0.497 -0.162 1.01 -0.66 1.143 -0.498 0.134 -1.01 -0.162 -1.144 -0.66l-0.744 -2.777 -2.401 -1.387 0 2.886 2.033 2.034c0.364 0.364 0.364 0.956 0 1.32 -0.365 0.365 -0.956 0.365 -1.321 0l-0.712 -0.712 0 0.997c0 0.515 -0.419 0.934 -0.934 0.934 -0.515 0 -0.934 -0.419 -0.934 -0.934l0 -0.997 -0.712 0.712c-0.365 0.365 -0.956 0.365 -1.321 0 -0.364 -0.364 -0.364 -0.956 0 -1.32l2.033 -2.034 0 -2.886 -2.499 1.443 -0.744 2.778C7.689 18.335 7.177 18.631 6.679 18.498 6.181 18.365 5.885 17.852 6.019 17.354L6.28 16.381 5.416 16.88C4.969 17.137 4.398 16.984 4.14 16.538 3.882 16.092 4.036 15.52 4.482 15.262L5.346 14.764 4.372 14.503C3.875 14.369 3.579 13.857 3.712 13.359 3.846 12.861 4.358 12.565 4.856 12.699L7.633 13.443 10.132 12 7.633 10.557 4.856 11.301C4.358 11.435 3.846 11.139 3.712 10.641 3.579 10.143 3.875 9.631 4.372 9.497L5.346 9.236 4.482 8.738C4.036 8.48 3.882 7.908 4.14 7.462 4.398 7.016 4.969 6.863 5.416 7.12L6.28 7.619 6.019 6.646C5.885 6.148 6.181 5.635 6.679 5.502 7.177 5.369 7.689 5.665 7.823 6.162l0.744 2.778 2.499 1.443z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeMiterLimit="1.41421" />
|
||||
</group>
|
||||
</vector>
|
||||
18
parts/res/drawable/ic_thermal_dialer.xml
Normal file
18
parts/res/drawable/ic_thermal_dialer.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group
|
||||
android:scaleX="0.0930942"
|
||||
android:scaleY="0.0934518"
|
||||
android:translateX="19.4408"
|
||||
android:translateY="9.49012">
|
||||
<path
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:pathData="M0 57.121c-22.463 -12.601 -36.159 -9.862 -42.734 0 -6.574 9.862 -20.819 24.106 -42.186 6.574 -10.987 -9.015 -22.91 -21.121 -31.769 -31.918 -17.532 -21.367 -3.287 -35.612 6.575 -42.186 9.861 -6.575 12.601 -20.272 0 -42.734 -12.601 -22.463 -33.421 -16.437 -33.421 -16.437 0 0 -22.462 6.575 -32.324 48.213 -8.889 37.534 35.637 88.416 44.502 98.083 0 0 57.942 56.011 99.581 46.149 41.638 -9.861 48.212 -32.324 48.212 -32.324 0 0 6.027 -20.819 -16.436 -33.42"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeMiterLimit="1.41421" />
|
||||
</group>
|
||||
</vector>
|
||||
19
parts/res/drawable/ic_thermal_gaming.xml
Normal file
19
parts/res/drawable/ic_thermal_gaming.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group
|
||||
android:scaleX="0.921041"
|
||||
android:scaleY="0.924579"
|
||||
android:translateX="0.752324"
|
||||
android:translateY="0.893459">
|
||||
<path
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M10.228 14.833c-0.006 0 -0.894 0.008 -1.83 1.069 -0.716 0.812 -1.981 2.473 -3.218 3.16 -0.07 0.041 -0.143 0.078 -0.218 0.111 -0.311 0.143 -0.619 0.217 -0.913 0.192l-0.015 0C3.63 19.362 3.252 19.254 2.924 19.066 1.702 18.44 1.782 17.099 1.782 17.099c0 -0.07 0.004 -0.139 0.01 -0.206C1.847 15.696 2.143 9.661 2.563 8.549 3.102 6.316 5.114 4.656 7.51 4.656l9.423 0c2.478 0 4.545 1.775 4.997 4.123 0.383 1.539 0.65 6.984 0.702 8.114 0.006 0.067 0.009 0.136 0.009 0.206 0 0 0.081 1.341 -1.142 1.967 -0.327 0.188 -0.706 0.296 -1.109 0.299l-0.015 0c-0.294 0.025 -0.602 -0.049 -0.914 -0.192 -0.074 -0.033 -0.147 -0.07 -0.218 -0.111 -1.236 -0.687 -2.502 -2.348 -3.217 -3.16 -0.936 -1.061 -1.824 -1.069 -1.83 -1.069l-3.968 0zM8.247 6.379c1.935 0 3.507 1.571 3.507 3.507 0 1.935 -1.572 3.507 -3.507 3.507 -1.936 0 -3.507 -1.572 -3.507 -3.507 0 -1.936 1.571 -3.507 3.507 -3.507zm9.138 4.16c0.454 0 0.823 0.369 0.823 0.823 0 0.454 -0.369 0.823 -0.823 0.823 -0.454 0 -0.823 -0.369 -0.823 -0.823 0 -0.454 0.369 -0.823 0.823 -0.823zm-8.421 0.07l0 0.814c0 0.399 -0.324 0.723 -0.723 0.723 -0.399 0 -0.723 -0.324 -0.723 -0.723l0 -0.814 -0.815 0C6.304 10.609 5.98 10.285 5.98 9.886 5.98 9.487 6.304 9.163 6.703 9.163l0.815 0 0 -0.815c0 -0.399 0.324 -0.723 0.723 -0.723 0.399 0 0.723 0.324 0.723 0.723l0 0.815 0.815 0c0.399 0 0.723 0.324 0.723 0.723 0 0.399 -0.324 0.722 -0.723 0.723l-0.815 0zm10.72 -0.723c0 0.454 -0.369 0.823 -0.823 0.823 -0.454 0 -0.823 -0.369 -0.823 -0.823 0 -0.455 0.369 -0.823 0.823 -0.823 0.454 0 0.823 0.368 0.823 0.823zm-2.952 0c0 0.454 -0.369 0.823 -0.823 0.823 -0.455 0 -0.823 -0.369 -0.823 -0.823 0 -0.455 0.368 -0.823 0.823 -0.823 0.454 0 0.823 0.368 0.823 0.823zm0.653 -2.3c0.454 0 0.823 0.369 0.823 0.824 0 0.454 -0.369 0.823 -0.823 0.823 -0.454 0 -0.823 -0.369 -0.823 -0.823 0 -0.455 0.369 -0.824 0.823 -0.824z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeMiterLimit="1.41421" />
|
||||
</group>
|
||||
</vector>
|
||||
19
parts/res/drawable/ic_thermal_streaming.xml
Normal file
19
parts/res/drawable/ic_thermal_streaming.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24"
|
||||
android:viewportWidth="24">
|
||||
<group
|
||||
android:scaleX="1.20862"
|
||||
android:scaleY="1.21327"
|
||||
android:translateX="-0.686496"
|
||||
android:translateY="-0.544151">
|
||||
<path
|
||||
android:fillColor="?android:attr/colorAccent"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M13.29 18.046l-8.091 0c-1.277 0 -2.315 -1.037 -2.315 -2.315l0 -4.631c0 -1.277 1.038 -2.315 2.315 -2.315l8.091 0c1.272 0 2.305 1.027 2.315 2.296l1.307 -0.754c0.065 -0.038 0.135 -0.067 0.21 -0.086l0.002 0 0 0 0 0 0 0c0.062 -0.015 0.126 -0.023 0.188 -0.023l0.001 0 0.003 0c0.146 0.001 0.283 0.041 0.401 0.11 0.11 0.065 0.205 0.156 0.276 0.272 0.043 0.071 0.076 0.15 0.096 0.233l0 0.002c0.014 0.059 0.02 0.119 0.02 0.178l0 0.001 0 4.803 0 0.001c0 0.059 -0.006 0.119 -0.02 0.178l0 0.001 0 0 0 0 0 0.001c-0.02 0.084 -0.053 0.162 -0.096 0.233 -0.071 0.116 -0.166 0.208 -0.276 0.272 -0.118 0.07 -0.255 0.11 -0.401 0.11l0 0 0 0 -0.003 0 -0.001 0c-0.062 0 -0.126 -0.007 -0.188 -0.023l0 0 0 0 0 0 -0.002 0c-0.075 -0.018 -0.145 -0.047 -0.21 -0.085L15.605 15.75c-0.01 1.269 -1.043 2.296 -2.315 2.296zm-1.773 -4.63c0 -0.107 -0.027 -0.214 -0.083 -0.313l0 0 0 0 -0.001 -0.002 -0.001 0C11.409 13.06 11.381 13.023 11.349 12.988 11.305 12.94 11.254 12.9 11.198 12.869L7.919 10.975C7.867 10.945 7.811 10.922 7.752 10.908l-0.001 -0.001 0 0 0 0 0 0C7.702 10.895 7.652 10.889 7.602 10.889l0 0 -0.002 0 -0.001 0 0 0C7.484 10.89 7.376 10.921 7.283 10.976 7.196 11.027 7.12 11.099 7.064 11.191 7.03 11.247 7.004 11.309 6.989 11.375l0 0.001 0 0 0 0 0 0.001c-0.011 0.046 -0.016 0.094 -0.016 0.141l0 0 0 3.795 0 0.001c0 0.047 0.005 0.094 0.016 0.141l0 0.001c0.015 0.066 0.041 0.128 0.075 0.185 0.056 0.091 0.132 0.163 0.219 0.214 0.093 0.055 0.201 0.087 0.316 0.087l0.003 0 0 0c0.05 0 0.1 -0.006 0.149 -0.018l0 0 0 0 0 0 0.001 0c0.059 -0.015 0.115 -0.038 0.167 -0.068l3.279 -1.893c0.056 -0.032 0.107 -0.072 0.151 -0.119 0.032 -0.035 0.06 -0.073 0.083 -0.113l0.001 -0.001 0.001 -0.001 0 -0.001 0 0c0.056 -0.098 0.083 -0.206 0.083 -0.312zM6.026 4.848c0.955 0 1.731 0.776 1.731 1.731C7.757 7.535 6.981 8.31 6.026 8.31 5.07 8.31 4.295 7.535 4.295 6.579 4.295 5.624 5.07 4.848 6.026 4.848Zm4.986 -2.216c1.567 0 2.839 1.272 2.839 2.839 0 1.567 -1.272 2.839 -2.839 2.839 -1.567 0 -2.839 -1.272 -2.839 -2.839 0 -1.567 1.272 -2.839 2.839 -2.839z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeMiterLimit="1.41421" />
|
||||
</group>
|
||||
</vector>
|
||||
11
parts/res/drawable/ic_thermal_tile.xml
Normal file
11
parts/res/drawable/ic_thermal_tile.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M19.58 9.42l1.54-1.54C21.68 9.14 22 10.53 22 12c0 5.52-4.48 10-10 10S2 17.52 2 12 6.48 2 12 2c1.46 0 2.85 0.32 4.11 0.89l-1.53 1.53C13.77 4.15 12.9 4 12 4c-4.41 0-8 3.59-8 8s3.59 8 8 8 8-3.59 8-8c0-0.9-0.15-1.77-0.42-2.58Zm-8.35 4.43c-0.25-0.1-0.46-0.25-0.65-0.43-0.18-0.19-0.33-0.4-0.43-0.65-0.1-0.24-0.15-0.5-0.15-0.75 0-0.27 0.05-0.52 0.15-0.76 0.1-0.24 0.25-0.46 0.43-0.65L19 5l-5.61 8.42c-0.19 0.18-0.4 0.33-0.65 0.43-0.24 0.1-0.5 0.15-0.76 0.15s-0.51-0.05-0.75-0.15Z"/>
|
||||
</vector>
|
||||
12
parts/res/layout/activity_game_bar.xml
Normal file
12
parts/res/layout/activity_game_bar.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?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>
|
||||
5
parts/res/layout/activity_game_bar_app_selector.xml
Normal file
5
parts/res/layout/activity_game_bar_app_selector.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?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" />
|
||||
10
parts/res/layout/game_bar.xml
Normal file
10
parts/res/layout/game_bar.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?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>
|
||||
6
parts/res/layout/game_bar_app_selector.xml
Normal file
6
parts/res/layout/game_bar_app_selector.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?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"/>
|
||||
34
parts/res/layout/game_bar_app_selector_item.xml
Normal file
34
parts/res/layout/game_bar_app_selector_item.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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>
|
||||
28
parts/res/layout/image_layout.xml
Normal file
28
parts/res/layout/image_layout.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:foregroundGravity="center_horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="320dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:cropToPadding="true"
|
||||
android:contentDescription="@null" />
|
||||
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
58
parts/res/layout/image_preview_layout.xml
Normal file
58
parts/res/layout/image_preview_layout.xml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="320dp"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/arrow_previous"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:paddingLeft="24dp"
|
||||
android:layout_gravity="center_vertical|left"
|
||||
android:contentDescription="@string/image_preview_previous_page_content_description">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_image_preview_arrow_left"/>
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/viewGroup"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="48dp"
|
||||
android:gravity="center"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/arrow_next"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:paddingRight="24dp"
|
||||
android:layout_gravity="center_vertical|right"
|
||||
android:contentDescription="@string/image_preview_next_page_content_description">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_image_preview_arrow_right"/>
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
131
parts/res/layout/preference_custom_seekbar.xml
Normal file
131
parts/res/layout/preference_custom_seekbar.xml
Normal file
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2017-2022 crDroid Android Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:background="?android:attr/activatedBackgroundIndicator"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@android:id/icon_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="-4dp"
|
||||
android:minWidth="60dp"
|
||||
android:gravity="start|center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
<com.android.internal.widget.PreferenceImageView
|
||||
android:id="@android:id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxWidth="48dp"
|
||||
android:maxHeight="48dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
android:ellipsize="marquee" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/summary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@android:id/title"
|
||||
android:layout_alignStart="@android:id/title"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:maxLines="10"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/value_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@android:id/summary"
|
||||
android:layout_alignStart="@android:id/title" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/value"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/reset"
|
||||
android:src="@drawable/ic_custom_seekbar_reset"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_toEndOf="@id/value"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/seekbar_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/value_frame"
|
||||
android:layout_alignStart="@android:id/title" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/minus"
|
||||
android:src="@drawable/ic_custom_seekbar_minus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/plus"
|
||||
android:src="@drawable/ic_custom_seekbar_plus"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/seekbar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_toEndOf="@id/minus"
|
||||
android:layout_toStartOf="@id/plus"
|
||||
android:layout_centerVertical="true" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<!-- Preference should place its actual preference widget here. -->
|
||||
<LinearLayout android:id="@android:id/widget_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="end|center_vertical"
|
||||
android:paddingStart="16dp"
|
||||
android:orientation="vertical" />
|
||||
</LinearLayout>
|
||||
18
parts/res/layout/refresh_layout.xml
Normal file
18
parts/res/layout/refresh_layout.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/refresh_rv_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
64
parts/res/layout/refresh_list_item.xml
Normal file
64
parts/res/layout/refresh_list_item.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingTop="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="@android:dimen/app_icon_size"
|
||||
android:layout_height="@android:dimen/app_icon_size"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="@null"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/app_mode"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/state"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_refresh_default" />
|
||||
</LinearLayout>
|
||||
18
parts/res/layout/thermal_layout.xml
Normal file
18
parts/res/layout/thermal_layout.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/thermal_rv_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
64
parts/res/layout/thermal_list_item.xml
Normal file
64
parts/res/layout/thermal_list_item.xml
Normal file
@@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingTop="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="@android:dimen/app_icon_size"
|
||||
android:layout_height="@android:dimen/app_icon_size"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:contentDescription="@null"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@android:style/TextAppearance.Material.Medium"
|
||||
android:textColor="?android:attr/textColorPrimary" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/app_mode"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/state"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_thermal_default" />
|
||||
</LinearLayout>
|
||||
13
parts/res/menu/auto_hbm_menu.xml
Normal file
13
parts/res/menu/auto_hbm_menu.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2025 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/add_tile"
|
||||
android:title="@string/tile_add" />
|
||||
</menu>
|
||||
14
parts/res/menu/saturation_menu.xml
Normal file
14
parts/res/menu/saturation_menu.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/add_tile"
|
||||
android:title="@string/tile_add" />
|
||||
</menu>
|
||||
BIN
parts/res/raw/clear_speaker_sound.mp3
Normal file
BIN
parts/res/raw/clear_speaker_sound.mp3
Normal file
Binary file not shown.
119
parts/res/values/arrays.xml
Normal file
119
parts/res/values/arrays.xml
Normal file
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 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>
|
||||
<!-- 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>
|
||||
17
parts/res/values/attrs.xml
Normal file
17
parts/res/values/attrs.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018-2022 crDroid Android Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!-- Base attributes available to CustomSeekBarPreference. -->
|
||||
<declare-styleable name="CustomSeekBarPreference">
|
||||
<attr name="defaultValueText" format="string" />
|
||||
<attr name="interval" format="integer" />
|
||||
<attr name="showSign" format="boolean" />
|
||||
<attr name="units" format="string|reference" />
|
||||
<attr name="continuousUpdates" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
95
parts/res/values/strings.xml
Normal file
95
parts/res/values/strings.xml
Normal file
@@ -0,0 +1,95 @@
|
||||
<?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">
|
||||
|
||||
<!-- Xiaomi Settings -->
|
||||
<string name="app_title">Xiaomi 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>
|
||||
|
||||
<!-- Thermal profiles -->
|
||||
<string name="thermal_title">Thermal profiles</string>
|
||||
<string name="thermal_summary">Adjust per-app thermal profiles for optimum performance</string>
|
||||
<string name="thermal_default">No optimization</string>
|
||||
<string name="thermal_benchmark">Performance</string>
|
||||
<string name="thermal_browser">Browser</string>
|
||||
<string name="thermal_camera">Camera</string>
|
||||
<string name="thermal_dialer">Dialer</string>
|
||||
<string name="thermal_gaming">Gaming</string>
|
||||
<string name="thermal_streaming">Streaming</string>
|
||||
|
||||
<!-- Per-app refresh rate -->
|
||||
<string name="refresh_title">Per-app refresh rate</string>
|
||||
<string name="refresh_summary">Set the maximum refresh rate for a specific application</string>
|
||||
<string name="refresh_default">Default</string>
|
||||
<string name="refresh_standard">60 Hz</string>
|
||||
<string name="refresh_high">90 Hz</string>
|
||||
<string name="refresh_extreme">120 Hz</string>
|
||||
|
||||
<!-- Clear Speaker -->
|
||||
<string name="clear_speaker_title">Clear speaker</string>
|
||||
<string name="clear_speaker_summary">Play a 30-second audio to clear the speaker</string>
|
||||
<string name="clear_speaker_description">Run this feature once or twice if you find that your speaker is lightly blocked by dust. Set media volume to maximum.\n\nIf the speaker is blocked heavily, run this feature 2-5 times while shaking your device with the speaker facing downwards.</string>
|
||||
|
||||
<!-- Saturation -->
|
||||
<string name="saturation_title">Display Saturation</string>
|
||||
<string name="saturation_summary">Control the saturation level of the display</string>
|
||||
<string name="saturation_footer_summary">Changing the color mode in display settings will override the saturation level, requiring it to be reapplied.</string>
|
||||
|
||||
<!-- Image preview -->
|
||||
<string name="image_preview_content_description">Preview</string>
|
||||
<string name="image_preview_next_page_content_description">Next</string>
|
||||
<string name="image_preview_previous_page_content_description">Previous</string>
|
||||
|
||||
<!-- Custom seekbar -->
|
||||
<string name="custom_seekbar_value">Value: <xliff:g id="v">%s</xliff:g></string>
|
||||
<string name="custom_seekbar_default_value">by default</string>
|
||||
<string name="custom_seekbar_default_value_to_set">Default value: <xliff:g id="v">%s</xliff:g>\nLong tap to set</string>
|
||||
<string name="custom_seekbar_default_value_is_set">Default value is set</string>
|
||||
|
||||
<!-- Auto HBM -->
|
||||
<string name="auto_hbm_title">Automatic High Brightness Mode (HBM)</string>
|
||||
<string name="auto_hbm_main_switch_title">Use automatic HBM</string>
|
||||
<string name="tile_auto_hbm">Auto HBM</string>
|
||||
<string name="tile_hbm_on">Enabled</string>
|
||||
<string name="tile_hbm_off">Disabled</string>
|
||||
<string name="tile_hbm">HBM</string>
|
||||
<string name="tile_hbm_unavailable">HBM Unavailable</string>
|
||||
<string name="tile_auto_hbm_or_brightness_enabled">Auto HBM or Auto Brightness is enabled</string>
|
||||
<string name="hbm_mode_title">High Brightness Mode</string>
|
||||
<string name="hbm_mode_notification">High Brightness Mode is now activated. Long time usage may damage your display.</string>
|
||||
<string name="auto_hbm_summary">Automatically enable high brightness mode based on sunlight intensity (lux)</string>
|
||||
<string name="auto_hbm_threshold_title">Light threshold</string>
|
||||
<string name="auto_hbm_threshold_summary">Define the light intensity threshold in lux units at which HBM is activated</string>
|
||||
<string name="auto_hbm_enable_time_title">Enable time</string>
|
||||
<string name="auto_hbm_enable_time_summary">Duration in seconds that the light threshold must be continuously met to activate HBM</string>
|
||||
<string name="auto_hbm_disable_time_title">Disable time</string>
|
||||
<string name="auto_hbm_disable_time_summary">Duration in seconds for which HBM is deactivated if the light threshold falls below the set level</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>
|
||||
</resources>
|
||||
51
parts/res/xml/auto_hbm.xml
Normal file
51
parts/res/xml/auto_hbm.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.android.settingslib.widget.TopIntroPreference
|
||||
android:key="auto_hbm_intro"
|
||||
android:title="@string/auto_hbm_summary" />
|
||||
|
||||
<com.android.settingslib.widget.MainSwitchPreference
|
||||
android:key="auto_hbm"
|
||||
android:title="@string/auto_hbm_main_switch_title"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<com.android.settingslib.widget.UsageProgressBarPreference
|
||||
android:key="current_lux_level"
|
||||
android:selectable="false" />
|
||||
|
||||
<org.lineageos.settings.CustomSeekBarPreference
|
||||
android:key="auto_hbm_threshold"
|
||||
android:title="@string/auto_hbm_threshold_title"
|
||||
android:summary="@string/auto_hbm_threshold_summary"
|
||||
android:max="60000"
|
||||
android:min="2000"
|
||||
settings:units=""
|
||||
android:defaultValue="20000" />
|
||||
|
||||
<org.lineageos.settings.CustomSeekBarPreference
|
||||
android:key="auto_hbm_enable_time"
|
||||
android:title="@string/auto_hbm_enable_time_title"
|
||||
android:summary="@string/auto_hbm_enable_time_summary"
|
||||
android:max="10"
|
||||
android:min="0"
|
||||
settings:units=""
|
||||
android:defaultValue="0" />
|
||||
|
||||
<org.lineageos.settings.CustomSeekBarPreference
|
||||
android:key="auto_hbm_disable_time"
|
||||
android:title="@string/auto_hbm_disable_time_title"
|
||||
android:summary="@string/auto_hbm_disable_time_summary"
|
||||
android:max="10"
|
||||
android:min="0"
|
||||
settings:units=""
|
||||
android:defaultValue="1" />
|
||||
</PreferenceScreen>
|
||||
17
parts/res/xml/clear_speaker_settings.xml
Normal file
17
parts/res/xml/clear_speaker_settings.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:title="@string/clear_speaker_title">
|
||||
|
||||
<SwitchPreference
|
||||
android:key="clear_speaker_pref"
|
||||
android:title="@string/clear_speaker_title"
|
||||
android:icon="@drawable/ic_clear_speaker"
|
||||
android:summary="@string/clear_speaker_summary"/>
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="footer_preference"
|
||||
android:title="@string/clear_speaker_description"
|
||||
android:selectable="false" />
|
||||
|
||||
</PreferenceScreen>
|
||||
252
parts/res/xml/game_bar_preferences.xml
Normal file
252
parts/res/xml/game_bar_preferences.xml
Normal file
@@ -0,0 +1,252 @@
|
||||
<?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>
|
||||
38
parts/res/xml/saturation.xml
Normal file
38
parts/res/xml/saturation.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018-2014 The LineageOS Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<com.android.settingslib.widget.LayoutPreference
|
||||
android:key="saturation_preview"
|
||||
android:layout="@layout/image_preview_layout"
|
||||
android:selectable="false" />
|
||||
|
||||
<org.lineageos.settings.CustomSeekBarPreference
|
||||
android:key="saturation"
|
||||
android:max="200"
|
||||
android:min="0"
|
||||
android:defaultValue="100"
|
||||
settings:continuousUpdates="true" />
|
||||
|
||||
<com.android.settingslib.widget.FooterPreference
|
||||
android:key="saturation_footer"
|
||||
android:title="@string/saturation_footer_summary"
|
||||
android:selectable="false" />
|
||||
</PreferenceScreen>
|
||||
59
parts/src/org/lineageos/settings/BootCompletedReceiver.java
Normal file
59
parts/src/org/lineageos/settings/BootCompletedReceiver.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The CyanogenMod Project
|
||||
* 2017-2019 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import org.lineageos.settings.thermal.ThermalUtils;
|
||||
import org.lineageos.settings.refreshrate.RefreshUtils;
|
||||
|
||||
public class BootCompletedReceiver extends BroadcastReceiver {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "XiaomiParts";
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
if (DEBUG) Log.i(TAG, "Received intent: " + intent.getAction());
|
||||
switch (intent.getAction()) {
|
||||
case Intent.ACTION_LOCKED_BOOT_COMPLETED:
|
||||
onLockedBootCompleted(context);
|
||||
break;
|
||||
case Intent.ACTION_BOOT_COMPLETED:
|
||||
onBootCompleted(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void onLockedBootCompleted(Context context) {
|
||||
ThermalUtils.startService(context);
|
||||
RefreshUtils.startService(context);
|
||||
}
|
||||
|
||||
private static void onBootCompleted(Context context) {
|
||||
}
|
||||
}
|
||||
32
parts/src/org/lineageos/settings/Constants.java
Normal file
32
parts/src/org/lineageos/settings/Constants.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public class Constants {
|
||||
|
||||
// AutoHbm
|
||||
public static final String KEY_AUTO_HBM = "auto_hbm";
|
||||
public static final String KEY_AUTO_HBM_THRESHOLD = "auto_hbm_threshold";
|
||||
public static final String KEY_AUTO_HBM_ENABLE_TIME = "auto_hbm_enable_time";
|
||||
public static final String KEY_AUTO_HBM_DISABLE_TIME = "auto_hbm_disable_time";
|
||||
public static final String KEY_CURRENT_LUX_LEVEL = "current_lux_level";
|
||||
public static final String NODE_BRIGHTNESS = "/sys/class/backlight/panel0-backlight/brightness";
|
||||
|
||||
// Saturation
|
||||
public static final String KEY_SATURATION = "saturation";
|
||||
public static final String KEY_SATURATION_PREVIEW = "saturation_preview";
|
||||
}
|
||||
368
parts/src/org/lineageos/settings/CustomSeekBarPreference.java
Normal file
368
parts/src/org/lineageos/settings/CustomSeekBarPreference.java
Normal file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.PorterDuff;
|
||||
import androidx.core.content.res.TypedArrayUtils;
|
||||
import androidx.preference.*;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class CustomSeekBarPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
|
||||
protected final String TAG = getClass().getName();
|
||||
private static final String SETTINGS_NS = "http://schemas.android.com/apk/res/com.android.settings";
|
||||
protected static final String ANDROIDNS = "http://schemas.android.com/apk/res/android";
|
||||
|
||||
protected int mInterval = 1;
|
||||
protected boolean mShowSign = false;
|
||||
protected String mUnits = "";
|
||||
protected boolean mContinuousUpdates = false;
|
||||
|
||||
protected int mMinValue = 0;
|
||||
protected int mMaxValue = 100;
|
||||
protected boolean mDefaultValueExists = false;
|
||||
protected int mDefaultValue;
|
||||
protected boolean mDefaultValueTextExists = false;
|
||||
protected String mDefaultValueText;
|
||||
|
||||
protected int mValue;
|
||||
|
||||
protected TextView mValueTextView;
|
||||
protected ImageView mResetImageView;
|
||||
protected ImageView mMinusImageView;
|
||||
protected ImageView mPlusImageView;
|
||||
protected SeekBar mSeekBar;
|
||||
|
||||
protected boolean mTrackingTouch = false;
|
||||
protected int mTrackingValue;
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekBarPreference);
|
||||
try {
|
||||
mShowSign = a.getBoolean(R.styleable.CustomSeekBarPreference_showSign, mShowSign);
|
||||
String units = a.getString(R.styleable.CustomSeekBarPreference_units);
|
||||
if (units != null)
|
||||
mUnits = " " + units;
|
||||
mContinuousUpdates = a.getBoolean(R.styleable.CustomSeekBarPreference_continuousUpdates, mContinuousUpdates);
|
||||
String defaultValueText = a.getString(R.styleable.CustomSeekBarPreference_defaultValueText);
|
||||
mDefaultValueTextExists = defaultValueText != null && !defaultValueText.isEmpty();
|
||||
if (mDefaultValueTextExists) {
|
||||
mDefaultValueText = defaultValueText;
|
||||
}
|
||||
} finally {
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
try {
|
||||
String newInterval = attrs.getAttributeValue(SETTINGS_NS, "interval");
|
||||
if (newInterval != null)
|
||||
mInterval = Integer.parseInt(newInterval);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Invalid interval value", e);
|
||||
}
|
||||
mMinValue = attrs.getAttributeIntValue(SETTINGS_NS, "min", mMinValue);
|
||||
mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, "max", mMaxValue);
|
||||
if (mMaxValue < mMinValue)
|
||||
mMaxValue = mMinValue;
|
||||
String defaultValue = attrs.getAttributeValue(ANDROIDNS, "defaultValue");
|
||||
mDefaultValueExists = defaultValue != null && !defaultValue.isEmpty();
|
||||
if (mDefaultValueExists) {
|
||||
mDefaultValue = getLimitedValue(Integer.parseInt(defaultValue));
|
||||
mValue = mDefaultValue;
|
||||
} else {
|
||||
mValue = mMinValue;
|
||||
}
|
||||
|
||||
mSeekBar = new SeekBar(context, attrs);
|
||||
setLayoutResource(R.layout.preference_custom_seekbar);
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, TypedArrayUtils.getAttr(context,
|
||||
androidx.preference.R.attr.preferenceStyle,
|
||||
android.R.attr.preferenceStyle));
|
||||
}
|
||||
|
||||
public CustomSeekBarPreference(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDependencyChanged(Preference dependency, boolean disableDependent) {
|
||||
super.onDependencyChanged(dependency, disableDependent);
|
||||
this.setShouldDisableView(true);
|
||||
if (mSeekBar != null)
|
||||
mSeekBar.setEnabled(!disableDependent);
|
||||
if (mResetImageView != null)
|
||||
mResetImageView.setEnabled(!disableDependent);
|
||||
if (mPlusImageView != null)
|
||||
mPlusImageView.setEnabled(!disableDependent);
|
||||
if (mMinusImageView != null)
|
||||
mMinusImageView.setEnabled(!disableDependent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(PreferenceViewHolder holder) {
|
||||
super.onBindViewHolder(holder);
|
||||
try
|
||||
{
|
||||
// move our seekbar to the new view we've been given
|
||||
ViewParent oldContainer = mSeekBar.getParent();
|
||||
ViewGroup newContainer = (ViewGroup) holder.findViewById(R.id.seekbar);
|
||||
if (oldContainer != newContainer) {
|
||||
// remove the seekbar from the old view
|
||||
if (oldContainer != null) {
|
||||
((ViewGroup) oldContainer).removeView(mSeekBar);
|
||||
}
|
||||
// remove the existing seekbar (there may not be one) and add ours
|
||||
newContainer.removeAllViews();
|
||||
newContainer.addView(mSeekBar, ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "Error binding view: " + ex.toString());
|
||||
}
|
||||
|
||||
mSeekBar.setMax(getSeekValue(mMaxValue));
|
||||
mSeekBar.setProgress(getSeekValue(mValue));
|
||||
mSeekBar.setEnabled(isEnabled());
|
||||
|
||||
mValueTextView = (TextView) holder.findViewById(R.id.value);
|
||||
mResetImageView = (ImageView) holder.findViewById(R.id.reset);
|
||||
mMinusImageView = (ImageView) holder.findViewById(R.id.minus);
|
||||
mPlusImageView = (ImageView) holder.findViewById(R.id.plus);
|
||||
|
||||
updateValueViews();
|
||||
|
||||
mSeekBar.setOnSeekBarChangeListener(this);
|
||||
mResetImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Toast.makeText(getContext(), getContext().getString(R.string.custom_seekbar_default_value_to_set, getTextValue(mDefaultValue)),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
mResetImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mDefaultValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mMinusImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setValue(mValue - mInterval, true);
|
||||
}
|
||||
});
|
||||
mMinusImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mMaxValue - mMinValue > mInterval * 2 && mMaxValue + mMinValue < mValue * 2 ? Math.floorDiv(mMaxValue + mMinValue, 2) : mMinValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
mPlusImageView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setValue(mValue + mInterval, true);
|
||||
}
|
||||
});
|
||||
mPlusImageView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
setValue(mMaxValue - mMinValue > mInterval * 2 && mMaxValue + mMinValue > mValue * 2 ? -1 * Math.floorDiv(-1 * (mMaxValue + mMinValue), 2) : mMaxValue, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected int getLimitedValue(int v) {
|
||||
return v < mMinValue ? mMinValue : (v > mMaxValue ? mMaxValue : v);
|
||||
}
|
||||
|
||||
protected int getSeekValue(int v) {
|
||||
return 0 - Math.floorDiv(mMinValue - v, mInterval);
|
||||
}
|
||||
|
||||
protected String getTextValue(int v) {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && v == mDefaultValue) {
|
||||
return mDefaultValueText;
|
||||
}
|
||||
return (mShowSign && v > 0 ? "+" : "") + String.valueOf(v) + mUnits;
|
||||
}
|
||||
|
||||
protected void updateValueViews() {
|
||||
if (mValueTextView != null) {
|
||||
if (!mTrackingTouch || mContinuousUpdates) {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && mValue == mDefaultValue) {
|
||||
mValueTextView.setText(mDefaultValueText + " (" +
|
||||
getContext().getString(R.string.custom_seekbar_default_value) + ")");
|
||||
} else {
|
||||
mValueTextView.setText(getContext().getString(R.string.custom_seekbar_value, getTextValue(mValue)) +
|
||||
(mDefaultValueExists && mValue == mDefaultValue ? " (" +
|
||||
getContext().getString(R.string.custom_seekbar_default_value) + ")" : ""));
|
||||
}
|
||||
} else {
|
||||
if (mDefaultValueTextExists && mDefaultValueExists && mTrackingValue == mDefaultValue) {
|
||||
mValueTextView.setText("[" + mDefaultValueText + "]");
|
||||
} else {
|
||||
mValueTextView.setText(getContext().getString(R.string.custom_seekbar_value, "[" + getTextValue(mTrackingValue) + "]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mResetImageView != null) {
|
||||
if (!mDefaultValueExists || mValue == mDefaultValue || mTrackingTouch)
|
||||
mResetImageView.setVisibility(View.INVISIBLE);
|
||||
else
|
||||
mResetImageView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (mMinusImageView != null) {
|
||||
if (mValue == mMinValue || mTrackingTouch) {
|
||||
mMinusImageView.setClickable(false);
|
||||
mMinusImageView.setColorFilter(getContext().getColor(R.color.disabled_text_color),
|
||||
PorterDuff.Mode.MULTIPLY);
|
||||
} else {
|
||||
mMinusImageView.setClickable(true);
|
||||
mMinusImageView.clearColorFilter();
|
||||
}
|
||||
}
|
||||
if (mPlusImageView != null) {
|
||||
if (mValue == mMaxValue || mTrackingTouch) {
|
||||
mPlusImageView.setClickable(false);
|
||||
mPlusImageView.setColorFilter(getContext().getColor(R.color.disabled_text_color), PorterDuff.Mode.MULTIPLY);
|
||||
} else {
|
||||
mPlusImageView.setClickable(true);
|
||||
mPlusImageView.clearColorFilter();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void changeValue(int newValue) {
|
||||
// for subclasses
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
int newValue = getLimitedValue(mMinValue + (progress * mInterval));
|
||||
if (mTrackingTouch && !mContinuousUpdates) {
|
||||
mTrackingValue = newValue;
|
||||
updateValueViews();
|
||||
} else if (mValue != newValue) {
|
||||
// change rejected, revert to the previous value
|
||||
if (!callChangeListener(newValue)) {
|
||||
mSeekBar.setProgress(getSeekValue(mValue));
|
||||
return;
|
||||
}
|
||||
// change accepted, store it
|
||||
changeValue(newValue);
|
||||
persistInt(newValue);
|
||||
|
||||
mValue = newValue;
|
||||
updateValueViews();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
mTrackingValue = mValue;
|
||||
mTrackingTouch = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
mTrackingTouch = false;
|
||||
if (!mContinuousUpdates)
|
||||
onProgressChanged(mSeekBar, getSeekValue(mTrackingValue), false);
|
||||
notifyChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
|
||||
if (restoreValue)
|
||||
mValue = getPersistedInt(mValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultValue(Object defaultValue) {
|
||||
if (defaultValue instanceof Integer)
|
||||
setDefaultValue((Integer) defaultValue, mSeekBar != null);
|
||||
else
|
||||
setDefaultValue(defaultValue == null ? (String) null : defaultValue.toString(), mSeekBar != null);
|
||||
}
|
||||
|
||||
public void setDefaultValue(int newValue, boolean update) {
|
||||
newValue = getLimitedValue(newValue);
|
||||
if (!mDefaultValueExists || mDefaultValue != newValue) {
|
||||
mDefaultValueExists = true;
|
||||
mDefaultValue = newValue;
|
||||
if (update)
|
||||
updateValueViews();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultValue(String newValue, boolean update) {
|
||||
if (mDefaultValueExists && (newValue == null || newValue.isEmpty())) {
|
||||
mDefaultValueExists = false;
|
||||
if (update)
|
||||
updateValueViews();
|
||||
} else if (newValue != null && !newValue.isEmpty()) {
|
||||
setDefaultValue(Integer.parseInt(newValue), update);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValue(int newValue) {
|
||||
mValue = getLimitedValue(newValue);
|
||||
if (mSeekBar != null) mSeekBar.setProgress(getSeekValue(mValue));
|
||||
}
|
||||
|
||||
public void setValue(int newValue, boolean update) {
|
||||
newValue = getLimitedValue(newValue);
|
||||
if (mValue != newValue) {
|
||||
if (update)
|
||||
mSeekBar.setProgress(getSeekValue(newValue));
|
||||
else
|
||||
mValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void refresh(int newValue) {
|
||||
// this will ...
|
||||
setValue(newValue, mSeekBar != null);
|
||||
}
|
||||
}
|
||||
113
parts/src/org/lineageos/settings/Startup.java
Normal file
113
parts/src/org/lineageos/settings/Startup.java
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.lineageos.settings.Constants;
|
||||
import org.lineageos.settings.autohbm.AutoHbmActivity;
|
||||
import org.lineageos.settings.autohbm.AutoHbmFragment;
|
||||
import org.lineageos.settings.autohbm.AutoHbmTileService;
|
||||
import org.lineageos.settings.saturation.SaturationFragment;
|
||||
import org.lineageos.settings.utils.ComponentUtils;
|
||||
import org.lineageos.settings.utils.FileUtils;
|
||||
|
||||
public class Startup extends BroadcastReceiver {
|
||||
|
||||
private static final String TAG = "Startup";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
Log.d(TAG, "onReceive called with action: " + action);
|
||||
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(action) ||
|
||||
Intent.ACTION_REBOOT.equals(action)) {
|
||||
|
||||
// Adding a delay before applying the settings
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
Log.d(TAG, "Applying saved settings...");
|
||||
applySavedSaturation(context);
|
||||
applyAutoHbmSettings(context);
|
||||
}, 5000); // Delay of 5 seconds
|
||||
}
|
||||
}
|
||||
|
||||
private void applySavedSaturation(Context context) {
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
int seekBarValue = sharedPrefs.getInt(Constants.KEY_SATURATION, 100);
|
||||
Log.d(TAG, "Retrieved seekBarValue: " + seekBarValue);
|
||||
|
||||
// Apply the saved saturation value
|
||||
applySaturation(seekBarValue);
|
||||
}
|
||||
|
||||
private void applySaturation(int seekBarValue) {
|
||||
Log.d(TAG, "Applying saturation: " + seekBarValue);
|
||||
|
||||
float saturation;
|
||||
if (seekBarValue == 100) {
|
||||
saturation = 1.001f;
|
||||
} else {
|
||||
saturation = seekBarValue / 100.0f;
|
||||
}
|
||||
|
||||
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
|
||||
if (surfaceFlinger != null) {
|
||||
try {
|
||||
Parcel data = Parcel.obtain();
|
||||
data.writeInterfaceToken("android.ui.ISurfaceComposer");
|
||||
data.writeFloat(saturation);
|
||||
surfaceFlinger.transact(1022, data, null, 0);
|
||||
data.recycle();
|
||||
Log.d(TAG, "Saturation applied successfully");
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to apply saturation", e);
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "SurfaceFlinger service not found");
|
||||
}
|
||||
}
|
||||
|
||||
private void applyAutoHbmSettings(Context context) {
|
||||
Log.d(TAG, "Applying Auto HBM settings...");
|
||||
AutoHbmFragment.toggleAutoHbmService(context);
|
||||
|
||||
ComponentUtils.toggleComponent(
|
||||
context,
|
||||
AutoHbmActivity.class,
|
||||
true
|
||||
);
|
||||
|
||||
ComponentUtils.toggleComponent(
|
||||
context,
|
||||
AutoHbmTileService.class,
|
||||
true
|
||||
);
|
||||
Log.d(TAG, "Auto HBM settings applied");
|
||||
}
|
||||
}
|
||||
90
parts/src/org/lineageos/settings/TileHandlerActivity.java
Normal file
90
parts/src/org/lineageos/settings/TileHandlerActivity.java
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2025 kenway215
|
||||
*
|
||||
* 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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
|
||||
/*
|
||||
* 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.autohbm;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
|
||||
public class AutoHbmActivity extends CollapsingToolbarBaseActivity {
|
||||
|
||||
private static final String TAG = "AutoHbm";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getSupportFragmentManager().beginTransaction().replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
||||
new AutoHbmFragment(), TAG).commit();
|
||||
}
|
||||
}
|
||||
210
parts/src/org/lineageos/settings/autohbm/AutoHbmFragment.java
Normal file
210
parts/src/org/lineageos/settings/autohbm/AutoHbmFragment.java
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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.autohbm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.android.settingslib.widget.MainSwitchPreference;
|
||||
import com.android.settingslib.widget.UsageProgressBarPreference;
|
||||
|
||||
import org.lineageos.settings.Constants;
|
||||
import org.lineageos.settings.CustomSeekBarPreference;
|
||||
import org.lineageos.settings.R;
|
||||
import org.lineageos.settings.utils.TileUtils;
|
||||
|
||||
public class AutoHbmFragment extends PreferenceFragmentCompat
|
||||
implements OnCheckedChangeListener, SensorEventListener, Preference.OnPreferenceChangeListener {
|
||||
|
||||
private static final String[] AUTO_HBM_PREFERENCES = {
|
||||
Constants.KEY_AUTO_HBM_THRESHOLD,
|
||||
Constants.KEY_AUTO_HBM_ENABLE_TIME,
|
||||
Constants.KEY_AUTO_HBM_DISABLE_TIME,
|
||||
Constants.KEY_CURRENT_LUX_LEVEL
|
||||
};
|
||||
|
||||
private CustomSeekBarPreference mAutoHbmThresholdPreference;
|
||||
private MainSwitchPreference mAutoHbmSwitch;
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mLightSensor;
|
||||
private UsageProgressBarPreference mCurrentLuxLevelPreference;
|
||||
private int mCurrentLux;
|
||||
|
||||
private static boolean mAutoHbmServiceEnabled = false;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.auto_hbm, rootKey);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
Context context = getContext();
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
mAutoHbmSwitch = findPreference(Constants.KEY_AUTO_HBM);
|
||||
mAutoHbmSwitch.setChecked(sharedPrefs.getBoolean(Constants.KEY_AUTO_HBM, false));
|
||||
mAutoHbmSwitch.addOnSwitchChangeListener(this);
|
||||
|
||||
mAutoHbmThresholdPreference = findPreference(Constants.KEY_AUTO_HBM_THRESHOLD);
|
||||
mAutoHbmThresholdPreference.setOnPreferenceChangeListener(this);
|
||||
|
||||
mCurrentLuxLevelPreference = findPreference(Constants.KEY_CURRENT_LUX_LEVEL);
|
||||
|
||||
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
|
||||
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
|
||||
|
||||
toggleAutoHbmPreferencesVisibility(mAutoHbmSwitch.isChecked());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.auto_hbm_menu, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.add_tile) {
|
||||
TileUtils.requestAddTileService(
|
||||
getContext(),
|
||||
AutoHbmTileService.class,
|
||||
R.string.auto_hbm_title,
|
||||
R.drawable.ic_auto_hbm_tile
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (mAutoHbmSwitch.isChecked()) {
|
||||
mSensorManager.registerListener(this, mLightSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
if (mAutoHbmSwitch.isChecked()) {
|
||||
mSensorManager.unregisterListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
sharedPrefs.edit().putBoolean(Constants.KEY_AUTO_HBM, isChecked).apply();
|
||||
toggleAutoHbmService(getContext());
|
||||
toggleAutoHbmPreferencesVisibility(isChecked);
|
||||
|
||||
if (isChecked) {
|
||||
mSensorManager.registerListener(this, mLightSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
} else {
|
||||
mSensorManager.unregisterListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (preference == mAutoHbmThresholdPreference && mCurrentLuxLevelPreference != null) {
|
||||
int threshold = (int) newValue;
|
||||
updateCurrentLuxLevelPreference(mCurrentLux, threshold);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
if (event.sensor.getType() == Sensor.TYPE_LIGHT && mCurrentLuxLevelPreference != null) {
|
||||
float luxValue = event.values[0];
|
||||
mCurrentLux = (int) luxValue;
|
||||
int threshold = sharedPrefs.getInt(Constants.KEY_AUTO_HBM_THRESHOLD, 20000);
|
||||
updateCurrentLuxLevelPreference(mCurrentLux, threshold);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
private void updateCurrentLuxLevelPreference(int currentLux, int threshold) {
|
||||
if (mCurrentLuxLevelPreference != null) {
|
||||
mCurrentLuxLevelPreference.setUsageSummary(String.valueOf(currentLux));
|
||||
mCurrentLuxLevelPreference.setTotalSummary(String.valueOf(threshold));
|
||||
|
||||
if (currentLux >= threshold) {
|
||||
mCurrentLuxLevelPreference.setPercent(100, 100);
|
||||
} else {
|
||||
mCurrentLuxLevelPreference.setPercent(currentLux, threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleAutoHbmPreferencesVisibility(boolean show) {
|
||||
for (String prefKey : AUTO_HBM_PREFERENCES) {
|
||||
Preference pref = findPreference(prefKey);
|
||||
if (pref != null) {
|
||||
pref.setVisible(show);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void toggleAutoHbmService(Context context) {
|
||||
boolean isAutoHbmEnabled = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.getBoolean(Constants.KEY_AUTO_HBM, false);
|
||||
|
||||
if (isAutoHbmEnabled && !mAutoHbmServiceEnabled) {
|
||||
startAutoHbmService(context);
|
||||
} else if (!isAutoHbmEnabled && mAutoHbmServiceEnabled) {
|
||||
stopAutoHbmService(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static void startAutoHbmService(Context context) {
|
||||
context.startServiceAsUser(new Intent(context, AutoHbmService.class),
|
||||
UserHandle.CURRENT);
|
||||
mAutoHbmServiceEnabled = true;
|
||||
}
|
||||
|
||||
private static void stopAutoHbmService(Context context) {
|
||||
mAutoHbmServiceEnabled = false;
|
||||
context.stopServiceAsUser(new Intent(context, AutoHbmService.class),
|
||||
UserHandle.CURRENT);
|
||||
}
|
||||
}
|
||||
191
parts/src/org/lineageos/settings/autohbm/AutoHbmService.java
Normal file
191
parts/src/org/lineageos/settings/autohbm/AutoHbmService.java
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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.autohbm;
|
||||
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.lineageos.settings.Constants;
|
||||
import org.lineageos.settings.utils.FileUtils;
|
||||
|
||||
public class AutoHbmService extends Service {
|
||||
|
||||
private static final int MAX_BRIGHTNESS = 4000;
|
||||
private static final int FALLBACK_BRIGHTNESS = 200;
|
||||
private static boolean mAutoHbmActive = false;
|
||||
private ExecutorService mExecutorService;
|
||||
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mLightSensor;
|
||||
|
||||
private SharedPreferences mSharedPrefs;
|
||||
private int mLastManualBrightness = FALLBACK_BRIGHTNESS;
|
||||
private boolean mIsAutoBrightnessEnabled = false;
|
||||
|
||||
public void activateLightSensorRead() {
|
||||
submit(() -> {
|
||||
mSensorManager = (SensorManager) getApplicationContext().getSystemService(Context.SENSOR_SERVICE);
|
||||
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
|
||||
mSensorManager.registerListener(mSensorEventListener, mLightSensor, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
});
|
||||
}
|
||||
|
||||
public void deactivateLightSensorRead() {
|
||||
submit(() -> {
|
||||
mSensorManager.unregisterListener(mSensorEventListener);
|
||||
mAutoHbmActive = false;
|
||||
restoreBrightness();
|
||||
});
|
||||
}
|
||||
|
||||
private void setBrightnessDirectly(int brightness) {
|
||||
FileUtils.writeValue(Constants.NODE_BRIGHTNESS, String.valueOf(brightness));
|
||||
}
|
||||
|
||||
private void restoreBrightness() {
|
||||
if (mIsAutoBrightnessEnabled) {
|
||||
// Auto-brightness will handle the adjustment
|
||||
} else {
|
||||
setBrightnessDirectly(mLastManualBrightness > 0 ? mLastManualBrightness : FALLBACK_BRIGHTNESS);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCurrentlyEnabled() {
|
||||
String fileValue = FileUtils.getFileValue(Constants.NODE_BRIGHTNESS, "0");
|
||||
return Integer.parseInt(fileValue) == MAX_BRIGHTNESS;
|
||||
}
|
||||
|
||||
SensorEventListener mSensorEventListener = new SensorEventListener() {
|
||||
private boolean mCrossedThreshold = false;
|
||||
private long mCrossedThresholdTime = 0;
|
||||
private long mLastTriggerTime = 0;
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
float lux = event.values[0];
|
||||
KeyguardManager km = (KeyguardManager) getSystemService(getApplicationContext().KEYGUARD_SERVICE);
|
||||
boolean keyguardShowing = km.inKeyguardRestrictedInputMode();
|
||||
int luxThreshold = mSharedPrefs.getInt(Constants.KEY_AUTO_HBM_THRESHOLD, 20000);
|
||||
int timeToEnableHbm = mSharedPrefs.getInt(Constants.KEY_AUTO_HBM_ENABLE_TIME, 0);
|
||||
int timeToDisableHbm = mSharedPrefs.getInt(Constants.KEY_AUTO_HBM_DISABLE_TIME, 1);
|
||||
|
||||
if (lux > luxThreshold) {
|
||||
if (!mCrossedThreshold) {
|
||||
mCrossedThreshold = true;
|
||||
mCrossedThresholdTime = System.currentTimeMillis();
|
||||
} else {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime - mCrossedThresholdTime >= timeToEnableHbm * 1000 && (!mAutoHbmActive || !isCurrentlyEnabled()) && !keyguardShowing) {
|
||||
mAutoHbmActive = true;
|
||||
saveCurrentBrightness();
|
||||
setBrightnessDirectly(MAX_BRIGHTNESS);
|
||||
mLastTriggerTime = currentTime;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mCrossedThreshold = false;
|
||||
|
||||
if (mAutoHbmActive) {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime - mLastTriggerTime >= timeToDisableHbm * 1000) {
|
||||
mAutoHbmActive = false;
|
||||
restoreBrightness();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
|
||||
private void saveCurrentBrightness() {
|
||||
try {
|
||||
String fileValue = FileUtils.getFileValue(Constants.NODE_BRIGHTNESS, String.valueOf(FALLBACK_BRIGHTNESS));
|
||||
mLastManualBrightness = Integer.parseInt(fileValue);
|
||||
} catch (NumberFormatException e) {
|
||||
mLastManualBrightness = FALLBACK_BRIGHTNESS;
|
||||
}
|
||||
mIsAutoBrightnessEnabled = mSharedPrefs.getBoolean("auto_brightness", false);
|
||||
}
|
||||
|
||||
private BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
|
||||
activateLightSensorRead();
|
||||
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
|
||||
deactivateLightSensorRead();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
mExecutorService = Executors.newSingleThreadExecutor();
|
||||
IntentFilter screenStateFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
|
||||
screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
registerReceiver(mScreenStateReceiver, screenStateFilter);
|
||||
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
if (pm.isInteractive()) {
|
||||
activateLightSensorRead();
|
||||
}
|
||||
}
|
||||
|
||||
private Future<?> submit(Runnable runnable) {
|
||||
return mExecutorService.submit(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
unregisterReceiver(mScreenStateReceiver);
|
||||
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
||||
if (pm.isInteractive()) {
|
||||
deactivateLightSensorRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.autohbm;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.lineageos.settings.Constants;
|
||||
import org.lineageos.settings.R;
|
||||
import org.lineageos.settings.utils.FileUtils;
|
||||
|
||||
public class AutoHbmTileService extends TileService {
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
super.onStartListening();
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
updateTile(sharedPrefs.getBoolean(Constants.KEY_AUTO_HBM, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopListening() {
|
||||
super.onStopListening();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
super.onClick();
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
final boolean enabled = !(sharedPrefs.getBoolean(Constants.KEY_AUTO_HBM, false));
|
||||
sharedPrefs.edit().putBoolean(Constants.KEY_AUTO_HBM, enabled).commit();
|
||||
AutoHbmFragment.toggleAutoHbmService(this);
|
||||
updateTile(enabled);
|
||||
}
|
||||
|
||||
private void updateTile(boolean enabled) {
|
||||
final Tile tile = getQsTile();
|
||||
tile.setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||
|
||||
// Set the title for the tile using the new string resource
|
||||
String title = getString(R.string.tile_auto_hbm);
|
||||
tile.setLabel(title);
|
||||
|
||||
// Set the subtitle based on the state
|
||||
String subtitle = enabled ? getString(R.string.tile_hbm_on) : getString(R.string.tile_hbm_off);
|
||||
tile.setSubtitle(subtitle);
|
||||
|
||||
tile.updateTile();
|
||||
}
|
||||
}
|
||||
158
parts/src/org/lineageos/settings/autohbm/HbmTileService.java
Normal file
158
parts/src/org/lineageos/settings/autohbm/HbmTileService.java
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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.autohbm;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.provider.Settings;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import org.lineageos.settings.Constants;
|
||||
import org.lineageos.settings.R;
|
||||
import org.lineageos.settings.utils.FileUtils;
|
||||
|
||||
public class HbmTileService extends TileService {
|
||||
private static final int MAX_BRIGHTNESS = 4000;
|
||||
private static final int FALLBACK_BRIGHTNESS = 200;
|
||||
private static final String NOTIFICATION_CHANNEL_ID = "hbm_tile_service_channel";
|
||||
private static final int NOTIFICATION_ID = 2;
|
||||
private int mLastManualBrightness = FALLBACK_BRIGHTNESS;
|
||||
private boolean mIsAutoBrightnessEnabled = false;
|
||||
private NotificationManager mNotificationManager;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
setupNotificationChannel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
super.onStartListening();
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean isAutoHbmEnabled = sharedPrefs.getBoolean(Constants.KEY_AUTO_HBM, false);
|
||||
mIsAutoBrightnessEnabled = isSystemAutoBrightnessEnabled();
|
||||
boolean isHbmEnabled = isCurrentlyEnabled();
|
||||
updateTile(isAutoHbmEnabled, mIsAutoBrightnessEnabled, isHbmEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
super.onClick();
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
boolean isAutoHbmEnabled = sharedPrefs.getBoolean(Constants.KEY_AUTO_HBM, false);
|
||||
mIsAutoBrightnessEnabled = isSystemAutoBrightnessEnabled();
|
||||
|
||||
if (isAutoHbmEnabled || mIsAutoBrightnessEnabled) {
|
||||
// Do nothing if Auto HBM or Auto Brightness is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isHbmEnabled = isCurrentlyEnabled();
|
||||
if (isHbmEnabled) {
|
||||
restoreBrightness();
|
||||
cancelHbmNotification();
|
||||
} else {
|
||||
saveCurrentBrightness();
|
||||
setBrightnessDirectly(MAX_BRIGHTNESS);
|
||||
showHbmNotification();
|
||||
}
|
||||
updateTile(isAutoHbmEnabled, mIsAutoBrightnessEnabled, !isHbmEnabled);
|
||||
}
|
||||
|
||||
private void updateTile(boolean isAutoHbmEnabled, boolean isAutoBrightnessEnabled, boolean isHbmEnabled) {
|
||||
final Tile tile = getQsTile();
|
||||
if (isAutoHbmEnabled || isAutoBrightnessEnabled) {
|
||||
tile.setState(Tile.STATE_UNAVAILABLE);
|
||||
tile.setLabel(getString(R.string.tile_auto_hbm_or_brightness_enabled));
|
||||
tile.setSubtitle(null);
|
||||
} else {
|
||||
tile.setState(isHbmEnabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||
tile.setLabel(getString(R.string.tile_hbm));
|
||||
tile.setSubtitle(isHbmEnabled ? getString(R.string.tile_hbm_on) : getString(R.string.tile_hbm_off));
|
||||
}
|
||||
tile.updateTile();
|
||||
}
|
||||
|
||||
private void setBrightnessDirectly(int brightness) {
|
||||
FileUtils.writeValue(Constants.NODE_BRIGHTNESS, String.valueOf(brightness));
|
||||
}
|
||||
|
||||
private void restoreBrightness() {
|
||||
if (mIsAutoBrightnessEnabled) {
|
||||
return;
|
||||
}
|
||||
setBrightnessDirectly(mLastManualBrightness > 0 ? mLastManualBrightness : FALLBACK_BRIGHTNESS);
|
||||
}
|
||||
|
||||
private boolean isCurrentlyEnabled() {
|
||||
String fileValue = FileUtils.getFileValue(Constants.NODE_BRIGHTNESS, "0");
|
||||
return Integer.parseInt(fileValue) == MAX_BRIGHTNESS;
|
||||
}
|
||||
|
||||
private void saveCurrentBrightness() {
|
||||
try {
|
||||
String fileValue = FileUtils.getFileValue(Constants.NODE_BRIGHTNESS, String.valueOf(FALLBACK_BRIGHTNESS));
|
||||
mLastManualBrightness = Integer.parseInt(fileValue);
|
||||
} catch (NumberFormatException e) {
|
||||
mLastManualBrightness = FALLBACK_BRIGHTNESS;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSystemAutoBrightnessEnabled() {
|
||||
try {
|
||||
return Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
|
||||
} catch (Settings.SettingNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setupNotificationChannel() {
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
NOTIFICATION_CHANNEL_ID,
|
||||
getString(R.string.hbm_mode_title),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
);
|
||||
channel.setBlockable(true);
|
||||
mNotificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
private void showHbmNotification() {
|
||||
Intent intent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
|
||||
Notification notification = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||
.setContentTitle(getString(R.string.hbm_mode_title))
|
||||
.setContentText(getString(R.string.hbm_mode_notification))
|
||||
.setSmallIcon(R.drawable.ic_auto_hbm_tile)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setOngoing(true)
|
||||
.setFlag(Notification.FLAG_NO_CLEAR, true)
|
||||
.build();
|
||||
mNotificationManager.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
|
||||
private void cancelHbmNotification() {
|
||||
mNotificationManager.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
774
parts/src/org/lineageos/settings/gamebar/GameBar.java
Normal file
774
parts/src/org/lineageos/settings/gamebar/GameBar.java
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* 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/power_supply/battery/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 / 10f;
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
130
parts/src/org/lineageos/settings/gamebar/GameBarCpuInfo.java
Normal file
130
parts/src/org/lineageos/settings/gamebar/GameBarCpuInfo.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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_zone0/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
187
parts/src/org/lineageos/settings/gamebar/GameBarFpsMeter.java
Normal file
187
parts/src/org/lineageos/settings/gamebar/GameBarFpsMeter.java
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
394
parts/src/org/lineageos/settings/gamebar/GameBarFragment.java
Normal file
394
parts/src/org/lineageos/settings/gamebar/GameBarFragment.java
Normal file
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
80
parts/src/org/lineageos/settings/gamebar/GameBarGpuInfo.java
Normal file
80
parts/src/org/lineageos/settings/gamebar/GameBarGpuInfo.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
65
parts/src/org/lineageos/settings/gamebar/GameBarMemInfo.java
Normal file
65
parts/src/org/lineageos/settings/gamebar/GameBarMemInfo.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
132
parts/src/org/lineageos/settings/gamebar/GameDataExport.java
Normal file
132
parts/src/org/lineageos/settings/gamebar/GameDataExport.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2022 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.refreshrate;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
|
||||
public class RefreshActivity extends CollapsingToolbarBaseActivity {
|
||||
private static final String TAG_REFRESH = "refresh";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getFragmentManager().beginTransaction().replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
||||
new RefreshSettingsFragment(), TAG_REFRESH).commit();
|
||||
}
|
||||
}
|
||||
102
parts/src/org/lineageos/settings/refreshrate/RefreshService.java
Normal file
102
parts/src/org/lineageos/settings/refreshrate/RefreshService.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.refreshrate;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.ActivityTaskManager.RootTaskInfo;
|
||||
import android.app.IActivityTaskManager;
|
||||
import android.app.TaskStackListener;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.os.RemoteException;
|
||||
|
||||
public class RefreshService extends Service {
|
||||
|
||||
private static final String TAG = "RefreshService";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private String mPreviousApp;
|
||||
private RefreshUtils mRefreshUtils;
|
||||
private IActivityTaskManager mActivityTaskManager;
|
||||
|
||||
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mPreviousApp = "";
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
if (DEBUG) Log.d(TAG, "Creating service");
|
||||
try {
|
||||
mActivityTaskManager = ActivityTaskManager.getService();
|
||||
mActivityTaskManager.registerTaskStackListener(mTaskListener);
|
||||
} catch (RemoteException e) {
|
||||
// Do nothing
|
||||
}
|
||||
mRefreshUtils = new RefreshUtils(this);
|
||||
registerReceiver();
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (DEBUG) Log.d(TAG, "Starting service");
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerReceiver() {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
// filter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
this.registerReceiver(mIntentReceiver, filter);
|
||||
}
|
||||
|
||||
private final TaskStackListener mTaskListener = new TaskStackListener() {
|
||||
@Override
|
||||
public void onTaskStackChanged() {
|
||||
try {
|
||||
final RootTaskInfo info = mActivityTaskManager.getFocusedRootTaskInfo();
|
||||
if (info == null || info.topActivity == null) {
|
||||
return;
|
||||
}
|
||||
String foregroundApp = info.topActivity.getPackageName();
|
||||
if (!mRefreshUtils.isAppInList) {
|
||||
mRefreshUtils.getOldRate();
|
||||
}
|
||||
if (!foregroundApp.equals(mPreviousApp)) {
|
||||
mRefreshUtils.setRefreshRate(foregroundApp);
|
||||
mPreviousApp = foregroundApp;
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
/**
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.lineageos.settings.refreshrate;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SectionIndexer;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.PreferenceFragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RefreshSettingsFragment extends PreferenceFragment
|
||||
implements ApplicationsState.Callbacks {
|
||||
|
||||
private AllPackagesAdapter mAllPackagesAdapter;
|
||||
private ApplicationsState mApplicationsState;
|
||||
private ApplicationsState.Session mSession;
|
||||
private ActivityFilter mActivityFilter;
|
||||
private Map<String, ApplicationsState.AppEntry> mEntryMap =
|
||||
new HashMap<String, ApplicationsState.AppEntry>();
|
||||
|
||||
private RefreshUtils mRefreshUtils;
|
||||
private RecyclerView mAppsRecyclerView;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
|
||||
mSession = mApplicationsState.newSession(this);
|
||||
mSession.onResume();
|
||||
mActivityFilter = new ActivityFilter(getActivity().getPackageManager());
|
||||
|
||||
mAllPackagesAdapter = new AllPackagesAdapter(getActivity());
|
||||
|
||||
mRefreshUtils = new RefreshUtils(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.refresh_layout, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
mAppsRecyclerView = view.findViewById(R.id.refresh_rv_view);
|
||||
mAppsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
mAppsRecyclerView.setAdapter(mAllPackagesAdapter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
getActivity().setTitle(getResources().getString(R.string.refresh_title));
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
mSession.onPause();
|
||||
mSession.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageListChanged() {
|
||||
mActivityFilter.updateLauncherInfoList();
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> entries) {
|
||||
if (entries != null) {
|
||||
handleAppEntries(entries);
|
||||
mAllPackagesAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadEntriesCompleted() {
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllSizesComputed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLauncherInfoChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageIconChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageSizeChanged(String packageName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRunningStateChanged(boolean running) {
|
||||
}
|
||||
|
||||
private void handleAppEntries(List<ApplicationsState.AppEntry> entries) {
|
||||
final ArrayList<String> sections = new ArrayList<String>();
|
||||
final ArrayList<Integer> positions = new ArrayList<Integer>();
|
||||
final PackageManager pm = getActivity().getPackageManager();
|
||||
String lastSectionIndex = null;
|
||||
int offset = 0;
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
final ApplicationInfo info = entries.get(i).info;
|
||||
final String label = (String) info.loadLabel(pm);
|
||||
final String sectionIndex;
|
||||
|
||||
if (!info.enabled) {
|
||||
sectionIndex = "--"; // XXX
|
||||
} else if (TextUtils.isEmpty(label)) {
|
||||
sectionIndex = "";
|
||||
} else {
|
||||
sectionIndex = label.substring(0, 1).toUpperCase();
|
||||
}
|
||||
|
||||
if (lastSectionIndex == null ||
|
||||
!TextUtils.equals(sectionIndex, lastSectionIndex)) {
|
||||
sections.add(sectionIndex);
|
||||
positions.add(offset);
|
||||
lastSectionIndex = sectionIndex;
|
||||
}
|
||||
|
||||
offset++;
|
||||
}
|
||||
|
||||
mAllPackagesAdapter.setEntries(entries, sections, positions);
|
||||
mEntryMap.clear();
|
||||
for (ApplicationsState.AppEntry e : entries) {
|
||||
mEntryMap.put(e.info.packageName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuild() {
|
||||
mSession.rebuild(mActivityFilter, ApplicationsState.ALPHA_COMPARATOR);
|
||||
}
|
||||
|
||||
private int getStateDrawable(int state) {
|
||||
switch (state) {
|
||||
case RefreshUtils.STATE_STANDARD:
|
||||
return R.drawable.ic_refresh_60;
|
||||
case RefreshUtils.STATE_HIGH:
|
||||
return R.drawable.ic_refresh_90;
|
||||
case RefreshUtils.STATE_EXTREME:
|
||||
return R.drawable.ic_refresh_120;
|
||||
case RefreshUtils.STATE_DEFAULT:
|
||||
default:
|
||||
return R.drawable.ic_refresh_default;
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private TextView title;
|
||||
private Spinner mode;
|
||||
private ImageView icon;
|
||||
private View rootView;
|
||||
private ImageView stateIcon;
|
||||
|
||||
private ViewHolder(View view) {
|
||||
super(view);
|
||||
this.title = view.findViewById(R.id.app_name);
|
||||
this.mode = view.findViewById(R.id.app_mode);
|
||||
this.icon = view.findViewById(R.id.app_icon);
|
||||
this.stateIcon = view.findViewById(R.id.state);
|
||||
this.rootView = view;
|
||||
|
||||
view.setTag(this);
|
||||
}
|
||||
}
|
||||
|
||||
private class ModeAdapter extends BaseAdapter {
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
private final int[] items = {
|
||||
R.string.refresh_default,
|
||||
R.string.refresh_standard,
|
||||
R.string.refresh_high,
|
||||
R.string.refresh_extreme
|
||||
};
|
||||
|
||||
private ModeAdapter(Context context) {
|
||||
inflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return items[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
TextView view;
|
||||
if (convertView != null) {
|
||||
view = (TextView) convertView;
|
||||
} else {
|
||||
view = (TextView) inflater.inflate(android.R.layout.simple_spinner_dropdown_item,
|
||||
parent, false);
|
||||
}
|
||||
|
||||
view.setText(items[position]);
|
||||
view.setTextSize(14f);
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
private class AllPackagesAdapter extends RecyclerView.Adapter<ViewHolder>
|
||||
implements AdapterView.OnItemSelectedListener, SectionIndexer {
|
||||
|
||||
private List<ApplicationsState.AppEntry> mEntries = new ArrayList<>();
|
||||
private String[] mSections;
|
||||
private int[] mPositions;
|
||||
|
||||
public AllPackagesAdapter(Context context) {
|
||||
mActivityFilter = new ActivityFilter(context.getPackageManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mEntries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mEntries.get(position).id;
|
||||
}
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.refresh_list_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Context context = holder.itemView.getContext();
|
||||
|
||||
ApplicationsState.AppEntry entry = mEntries.get(position);
|
||||
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
holder.mode.setAdapter(new ModeAdapter(context));
|
||||
holder.mode.setOnItemSelectedListener(this);
|
||||
holder.title.setText(entry.label);
|
||||
holder.title.setOnClickListener(v -> holder.mode.performClick());
|
||||
mApplicationsState.ensureIcon(entry);
|
||||
holder.icon.setImageDrawable(entry.icon);
|
||||
int packageState = mRefreshUtils.getStateForPackage(entry.info.packageName);
|
||||
holder.mode.setSelection(packageState, false);
|
||||
holder.mode.setTag(entry);
|
||||
holder.stateIcon.setImageResource(getStateDrawable(packageState));
|
||||
}
|
||||
|
||||
private void setEntries(List<ApplicationsState.AppEntry> entries,
|
||||
List<String> sections, List<Integer> positions) {
|
||||
mEntries = entries;
|
||||
mSections = sections.toArray(new String[sections.size()]);
|
||||
mPositions = new int[positions.size()];
|
||||
for (int i = 0; i < positions.size(); i++) {
|
||||
mPositions[i] = positions.get(i);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
final ApplicationsState.AppEntry entry = (ApplicationsState.AppEntry) parent.getTag();
|
||||
|
||||
int currentState = mRefreshUtils.getStateForPackage(entry.info.packageName);
|
||||
if (currentState != position) {
|
||||
mRefreshUtils.writePackage(entry.info.packageName, position);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionForSection(int section) {
|
||||
if (section < 0 || section >= mSections.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mPositions[section];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionForPosition(int position) {
|
||||
if (position < 0 || position >= getItemCount()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final int index = Arrays.binarySearch(mPositions, position);
|
||||
|
||||
/*
|
||||
* Consider this example: section positions are 0, 3, 5; the supplied
|
||||
* position is 4. The section corresponding to position 4 starts at
|
||||
* position 3, so the expected return value is 1. Binary search will not
|
||||
* find 4 in the array and thus will return -insertPosition-1, i.e. -3.
|
||||
* To get from that number to the expected value of 1 we need to negate
|
||||
* and subtract 2.
|
||||
*/
|
||||
return index >= 0 ? index : -index - 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSections() {
|
||||
return mSections;
|
||||
}
|
||||
}
|
||||
|
||||
private class ActivityFilter implements ApplicationsState.AppFilter {
|
||||
|
||||
private final PackageManager mPackageManager;
|
||||
private final List<String> mLauncherResolveInfoList = new ArrayList<String>();
|
||||
|
||||
private ActivityFilter(PackageManager packageManager) {
|
||||
this.mPackageManager = packageManager;
|
||||
|
||||
updateLauncherInfoList();
|
||||
}
|
||||
|
||||
public void updateLauncherInfoList() {
|
||||
Intent i = new Intent(Intent.ACTION_MAIN);
|
||||
i.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
List<ResolveInfo> resolveInfoList = mPackageManager.queryIntentActivities(i, 0);
|
||||
|
||||
synchronized (mLauncherResolveInfoList) {
|
||||
mLauncherResolveInfoList.clear();
|
||||
for (ResolveInfo ri : resolveInfoList) {
|
||||
mLauncherResolveInfoList.add(ri.activityInfo.packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filterApp(ApplicationsState.AppEntry entry) {
|
||||
boolean show = !mAllPackagesAdapter.mEntries.contains(entry.info.packageName);
|
||||
if (show) {
|
||||
synchronized (mLauncherResolveInfoList) {
|
||||
show = mLauncherResolveInfoList.contains(entry.info.packageName);
|
||||
}
|
||||
}
|
||||
return show;
|
||||
}
|
||||
}
|
||||
}
|
||||
155
parts/src/org/lineageos/settings/refreshrate/RefreshUtils.java
Normal file
155
parts/src/org/lineageos/settings/refreshrate/RefreshUtils.java
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.refreshrate;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.UserHandle;
|
||||
import android.view.Display;
|
||||
|
||||
import android.provider.Settings;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public final class RefreshUtils {
|
||||
|
||||
private static final String REFRESH_CONTROL = "refresh_control";
|
||||
|
||||
private static float defaultMaxRate;
|
||||
private static float defaultMinRate;
|
||||
private static final String KEY_PEAK_REFRESH_RATE = "peak_refresh_rate";
|
||||
private static final String KEY_MIN_REFRESH_RATE = "min_refresh_rate";
|
||||
private Context mContext;
|
||||
protected static boolean isAppInList = false;
|
||||
|
||||
protected static final int STATE_DEFAULT = 0;
|
||||
protected static final int STATE_STANDARD = 1;
|
||||
protected static final int STATE_HIGH = 2;
|
||||
protected static final int STATE_EXTREME = 3;
|
||||
|
||||
private static final float REFRESH_STATE_DEFAULT = 120f;
|
||||
private static final float REFRESH_STATE_STANDARD = 60f;
|
||||
private static final float REFRESH_STATE_HIGH = 90f;
|
||||
private static final float REFRESH_STATE_EXTREME = 120f;
|
||||
|
||||
private static final String REFRESH_STANDARD = "refresh.standard=";
|
||||
private static final String REFRESH_HIGH = "refresh.high=";
|
||||
private static final String REFRESH_EXTREME = "refresh.extreme=";
|
||||
|
||||
private SharedPreferences mSharedPrefs;
|
||||
|
||||
protected RefreshUtils(Context context) {
|
||||
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public static void startService(Context context) {
|
||||
context.startServiceAsUser(new Intent(context, RefreshService.class),
|
||||
UserHandle.CURRENT);
|
||||
}
|
||||
|
||||
private void writeValue(String profiles) {
|
||||
mSharedPrefs.edit().putString(REFRESH_CONTROL, profiles).apply();
|
||||
}
|
||||
|
||||
protected void getOldRate(){
|
||||
defaultMaxRate = Settings.System.getFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, REFRESH_STATE_DEFAULT);
|
||||
defaultMinRate = Settings.System.getFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, REFRESH_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
private String getValue() {
|
||||
String value = mSharedPrefs.getString(REFRESH_CONTROL, null);
|
||||
|
||||
if (value == null || value.isEmpty()) {
|
||||
value = REFRESH_STANDARD + ":" + REFRESH_HIGH + ":" + REFRESH_EXTREME;
|
||||
writeValue(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected void writePackage(String packageName, int mode) {
|
||||
String value = getValue();
|
||||
value = value.replace(packageName + ",", "");
|
||||
String[] modes = value.split(":");
|
||||
String finalString;
|
||||
|
||||
switch (mode) {
|
||||
case STATE_STANDARD:
|
||||
modes[0] = modes[0] + packageName + ",";
|
||||
break;
|
||||
case STATE_HIGH:
|
||||
modes[1] = modes[1] + packageName + ",";
|
||||
break;
|
||||
case STATE_EXTREME:
|
||||
modes[2] = modes[2] + packageName + ",";
|
||||
break;
|
||||
}
|
||||
|
||||
finalString = modes[0] + ":" + modes[1] + ":" + modes[2];
|
||||
|
||||
writeValue(finalString);
|
||||
}
|
||||
|
||||
protected int getStateForPackage(String packageName) {
|
||||
String value = getValue();
|
||||
String[] modes = value.split(":");
|
||||
int state = STATE_DEFAULT;
|
||||
if (modes[0].contains(packageName + ",")) {
|
||||
state = STATE_STANDARD;
|
||||
} else if (modes[1].contains(packageName + ",")) {
|
||||
state = STATE_HIGH;
|
||||
} else if (modes[2].contains(packageName + ",")) {
|
||||
state = STATE_EXTREME;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
protected void setRefreshRate(String packageName) {
|
||||
String value = getValue();
|
||||
String modes[];
|
||||
float maxrate = defaultMaxRate;
|
||||
float minrate = defaultMinRate;
|
||||
isAppInList = false;
|
||||
|
||||
if (value != null) {
|
||||
modes = value.split(":");
|
||||
|
||||
if (modes[0].contains(packageName + ",")) {
|
||||
maxrate = REFRESH_STATE_STANDARD;
|
||||
if ( minrate > maxrate){
|
||||
minrate = maxrate;
|
||||
}
|
||||
isAppInList = true;
|
||||
} else if (modes[1].contains(packageName + ",")) {
|
||||
maxrate = REFRESH_STATE_HIGH;
|
||||
if (minrate > maxrate) {
|
||||
minrate = maxrate;
|
||||
}
|
||||
isAppInList = true;
|
||||
} else if (modes[2].contains(packageName + ",")) {
|
||||
maxrate = REFRESH_STATE_EXTREME;
|
||||
if ( minrate > maxrate){
|
||||
minrate = maxrate;
|
||||
}
|
||||
isAppInList = true;
|
||||
}
|
||||
}
|
||||
Settings.System.putFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, minrate);
|
||||
Settings.System.putFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, maxrate);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.saturation;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
|
||||
public class SaturationActivity extends CollapsingToolbarBaseActivity {
|
||||
|
||||
private static final String TAG = "Saturation";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getSupportFragmentManager().beginTransaction().replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
||||
new SaturationFragment(), TAG).commit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* 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.saturation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.viewpager.widget.PagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.android.settingslib.widget.LayoutPreference;
|
||||
|
||||
import org.lineageos.settings.Constants;
|
||||
import org.lineageos.settings.CustomSeekBarPreference;
|
||||
import org.lineageos.settings.R;
|
||||
import org.lineageos.settings.utils.TileUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class SaturationFragment extends PreferenceFragmentCompat
|
||||
implements Preference.OnPreferenceChangeListener {
|
||||
|
||||
private View mViewArrowPrevious;
|
||||
private View mViewArrowNext;
|
||||
private ViewPager mViewPager;
|
||||
|
||||
private ImageView[] mDotIndicators;
|
||||
private View[] mViewPagerImages;
|
||||
|
||||
private CustomSeekBarPreference mSaturationPreference;
|
||||
|
||||
private IBinder mSurfaceFlinger;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.saturation, rootKey);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
LayoutPreference preview = findPreference(Constants.KEY_SATURATION_PREVIEW);
|
||||
addViewPager(preview);
|
||||
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
|
||||
mSaturationPreference = (CustomSeekBarPreference) findPreference(Constants.KEY_SATURATION);
|
||||
mSaturationPreference.setOnPreferenceChangeListener(this);
|
||||
int seekBarValue = sharedPrefs.getInt(Constants.KEY_SATURATION, 100);
|
||||
updateSaturation(seekBarValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.saturation_menu, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (preference == mSaturationPreference) {
|
||||
int seekBarValue = (Integer) newValue;
|
||||
updateSaturation(seekBarValue);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.add_tile) {
|
||||
TileUtils.requestAddTileService(
|
||||
getContext(),
|
||||
SaturationTileService.class,
|
||||
R.string.saturation_title,
|
||||
R.drawable.ic_saturation_tile
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSaturation(int seekBarValue) {
|
||||
float saturation;
|
||||
if (seekBarValue == 100) {
|
||||
saturation = 1.001f;
|
||||
} else {
|
||||
saturation = seekBarValue / 100.0f;
|
||||
}
|
||||
|
||||
if (mSurfaceFlinger != null) {
|
||||
try {
|
||||
Parcel data = Parcel.obtain();
|
||||
data.writeInterfaceToken("android.ui.ISurfaceComposer");
|
||||
data.writeFloat(saturation);
|
||||
mSurfaceFlinger.transact(1022, data, null, 0);
|
||||
data.recycle();
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
|
||||
}
|
||||
|
||||
public void restoreSaturationSetting(Context context) {
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
int seekBarValue = sharedPrefs.getInt(Constants.KEY_SATURATION, 100);
|
||||
updateSaturation(seekBarValue);
|
||||
}
|
||||
|
||||
void addViewPager(LayoutPreference preview) {
|
||||
mViewPager = preview.findViewById(R.id.viewpager);
|
||||
|
||||
int[] drawables = new int[]{
|
||||
R.drawable.image_preview1,
|
||||
R.drawable.image_preview2,
|
||||
R.drawable.image_preview3
|
||||
};
|
||||
|
||||
mViewPagerImages = new View[drawables.length];
|
||||
|
||||
for (int idx = 0; idx < drawables.length; idx++) {
|
||||
mViewPagerImages[idx] = getLayoutInflater().inflate(R.layout.image_layout, null);
|
||||
ImageView imageView = mViewPagerImages[idx].findViewById(R.id.imageView);
|
||||
imageView.setImageResource(drawables[idx]);
|
||||
}
|
||||
|
||||
mViewPager.setAdapter(new ImagePreviewPagerAdapter(mViewPagerImages));
|
||||
|
||||
mViewArrowPrevious = preview.findViewById(R.id.arrow_previous);
|
||||
mViewArrowPrevious.setOnClickListener(v -> mViewPager.setCurrentItem(mViewPager.getCurrentItem() - 1, true));
|
||||
|
||||
mViewArrowNext = preview.findViewById(R.id.arrow_next);
|
||||
mViewArrowNext.setOnClickListener(v -> mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1, true));
|
||||
|
||||
mViewPager.addOnPageChangeListener(createPageListener());
|
||||
|
||||
final ViewGroup viewGroup = preview.findViewById(R.id.viewGroup);
|
||||
mDotIndicators = new ImageView[mViewPagerImages.length];
|
||||
for (int i = 0; i < mViewPagerImages.length; i++) {
|
||||
final ImageView imageView = new ImageView(getContext());
|
||||
final ViewGroup.MarginLayoutParams lp =
|
||||
new ViewGroup.MarginLayoutParams(12, 12);
|
||||
lp.setMargins(6, 0, 6, 0);
|
||||
imageView.setLayoutParams(lp);
|
||||
mDotIndicators[i] = imageView;
|
||||
|
||||
viewGroup.addView(mDotIndicators[i]);
|
||||
}
|
||||
|
||||
updateIndicator(mViewPager.getCurrentItem());
|
||||
}
|
||||
|
||||
private ViewPager.OnPageChangeListener createPageListener() {
|
||||
return new ViewPager.OnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageScrolled(
|
||||
int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (positionOffset != 0) {
|
||||
for (View mViewPagerImage : mViewPagerImages) {
|
||||
mViewPagerImage.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
mViewPagerImages[position].setContentDescription(
|
||||
getContext().getString(R.string.image_preview_content_description));
|
||||
updateIndicator(position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateIndicator(int position) {
|
||||
for (int i = 0; i < mViewPagerImages.length; i++) {
|
||||
if (position == i) {
|
||||
mDotIndicators[i].setBackgroundResource(
|
||||
R.drawable.ic_image_preview_page_indicator_focused);
|
||||
|
||||
mViewPagerImages[i].setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mDotIndicators[i].setBackgroundResource(
|
||||
R.drawable.ic_image_preview_page_indicator_unfocused);
|
||||
|
||||
mViewPagerImages[i].setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
if (position == 0) {
|
||||
mViewArrowPrevious.setVisibility(View.INVISIBLE);
|
||||
mViewArrowNext.setVisibility(View.VISIBLE);
|
||||
} else if (position == (mViewPagerImages.length - 1)) {
|
||||
mViewArrowPrevious.setVisibility(View.VISIBLE);
|
||||
mViewArrowNext.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
mViewArrowPrevious.setVisibility(View.VISIBLE);
|
||||
mViewArrowNext.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
static class ImagePreviewPagerAdapter extends PagerAdapter {
|
||||
private final View[] mPageViewList;
|
||||
|
||||
ImagePreviewPagerAdapter(View[] pageViewList) {
|
||||
mPageViewList = pageViewList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
if (mPageViewList[position] != null) {
|
||||
container.removeView(mPageViewList[position]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int position) {
|
||||
container.addView(mPageViewList[position]);
|
||||
return mPageViewList[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mPageViewList.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
return object == view;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.saturation;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Intent;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
|
||||
public class SaturationTileService extends TileService {
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
super.onStartListening();
|
||||
updateTile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
super.onClick();
|
||||
Intent intent = new Intent(this, SaturationActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(
|
||||
this,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
);
|
||||
startActivityAndCollapse(pendingIntent);
|
||||
}
|
||||
|
||||
private void updateTile() {
|
||||
final Tile tile = getQsTile();
|
||||
tile.setState(Tile.STATE_ACTIVE);
|
||||
tile.updateTile();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Paranoid Android
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.speaker;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
|
||||
public class ClearSpeakerActivity extends CollapsingToolbarBaseActivity {
|
||||
|
||||
private static final String TAG_CLEARSPEAKER = "clearspeaker";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getFragmentManager().beginTransaction().replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
||||
new ClearSpeakerFragment(), TAG_CLEARSPEAKER).commit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Paranoid Android
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.speaker;
|
||||
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.media.AudioAttributes;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaPlayer;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragment;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ClearSpeakerFragment extends PreferenceFragment implements
|
||||
Preference.OnPreferenceChangeListener {
|
||||
|
||||
private static final String TAG = "ClearSpeakerFragment";
|
||||
private static final String PREF_CLEAR_SPEAKER = "clear_speaker_pref";
|
||||
private static final int PLAY_DURATION_MS = 30000;
|
||||
|
||||
private Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
private MediaPlayer mMediaPlayer;
|
||||
private SwitchPreference mClearSpeakerPref;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.clear_speaker_settings);
|
||||
|
||||
mClearSpeakerPref = findPreference(PREF_CLEAR_SPEAKER);
|
||||
mClearSpeakerPref.setOnPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (preference == mClearSpeakerPref) {
|
||||
boolean value = (Boolean) newValue;
|
||||
if (value && startPlaying()) {
|
||||
mHandler.removeCallbacksAndMessages(null);
|
||||
mHandler.postDelayed(this::stopPlaying, PLAY_DURATION_MS);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
stopPlaying();
|
||||
}
|
||||
|
||||
public boolean startPlaying() {
|
||||
getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
||||
mMediaPlayer = new MediaPlayer();
|
||||
mMediaPlayer.setAudioAttributes(new AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||
.build());
|
||||
mMediaPlayer.setLooping(true);
|
||||
try (AssetFileDescriptor afd = getResources().openRawResourceFd(
|
||||
R.raw.clear_speaker_sound)) {
|
||||
mMediaPlayer.setDataSource(afd);
|
||||
mMediaPlayer.setVolume(1.0f, 1.0f);
|
||||
mMediaPlayer.prepare();
|
||||
mMediaPlayer.start();
|
||||
mClearSpeakerPref.setEnabled(false);
|
||||
} catch (IOException | IllegalArgumentException e) {
|
||||
Log.e(TAG, "Failed to play speaker clean sound!", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void stopPlaying() {
|
||||
if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
|
||||
try {
|
||||
mMediaPlayer.stop();
|
||||
} catch (IllegalStateException e) {
|
||||
Log.e(TAG, "Failed to stop media player!", e);
|
||||
} finally {
|
||||
mMediaPlayer.reset();
|
||||
mMediaPlayer.release();
|
||||
mMediaPlayer=null;
|
||||
}
|
||||
}
|
||||
mClearSpeakerPref.setEnabled(true);
|
||||
mClearSpeakerPref.setChecked(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.thermal;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
|
||||
public class ThermalActivity extends CollapsingToolbarBaseActivity {
|
||||
|
||||
private static final String TAG_THERMAL = "thermal";
|
||||
private static final String THERMAL_SCONFIG = "/sys/class/thermal/thermal_message/sconfig";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getFragmentManager().beginTransaction().replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
||||
new ThermalSettingsFragment(), TAG_THERMAL).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
119
parts/src/org/lineageos/settings/thermal/ThermalService.java
Normal file
119
parts/src/org/lineageos/settings/thermal/ThermalService.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.thermal;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.ActivityTaskManager.RootTaskInfo;
|
||||
import android.app.IActivityTaskManager;
|
||||
import android.app.TaskStackListener;
|
||||
import android.app.Service;
|
||||
import android.app.TaskStackListener;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
public class ThermalService extends Service {
|
||||
|
||||
private static final String TAG = "ThermalService";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private boolean mScreenOn = true;
|
||||
private String mCurrentApp = "";
|
||||
private ThermalUtils mThermalUtils;
|
||||
|
||||
private IActivityTaskManager mActivityTaskManager;
|
||||
|
||||
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
switch (intent.getAction()) {
|
||||
case Intent.ACTION_SCREEN_OFF:
|
||||
mScreenOn = false;
|
||||
setThermalProfile();
|
||||
break;
|
||||
case Intent.ACTION_SCREEN_ON:
|
||||
mScreenOn = true;
|
||||
setThermalProfile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
if (DEBUG) Log.d(TAG, "Creating service");
|
||||
try {
|
||||
mActivityTaskManager = ActivityTaskManager.getService();
|
||||
mActivityTaskManager.registerTaskStackListener(mTaskListener);
|
||||
} catch (RemoteException e) {
|
||||
// Do nothing
|
||||
}
|
||||
mThermalUtils = new ThermalUtils(this);
|
||||
registerReceiver();
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (DEBUG) Log.d(TAG, "Starting service");
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerReceiver() {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
filter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
this.registerReceiver(mIntentReceiver, filter);
|
||||
}
|
||||
|
||||
private void setThermalProfile() {
|
||||
if (mScreenOn) {
|
||||
mThermalUtils.setThermalProfile(mCurrentApp);
|
||||
} else {
|
||||
mThermalUtils.setDefaultThermalProfile();
|
||||
}
|
||||
}
|
||||
|
||||
private final TaskStackListener mTaskListener = new TaskStackListener() {
|
||||
@Override
|
||||
public void onTaskStackChanged() {
|
||||
try {
|
||||
final ActivityTaskManager.RootTaskInfo focusedTask =
|
||||
ActivityTaskManager.getService().getFocusedRootTaskInfo();
|
||||
if (focusedTask != null && focusedTask.topActivity != null) {
|
||||
ComponentName taskComponentName = focusedTask.topActivity;
|
||||
String foregroundApp = taskComponentName.getPackageName();
|
||||
if (!foregroundApp.equals(mCurrentApp)) {
|
||||
mCurrentApp = foregroundApp;
|
||||
setThermalProfile();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,432 @@
|
||||
/**
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.lineageos.settings.thermal;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SectionIndexer;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.PreferenceFragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ThermalSettingsFragment extends PreferenceFragment
|
||||
implements ApplicationsState.Callbacks {
|
||||
|
||||
private AllPackagesAdapter mAllPackagesAdapter;
|
||||
private ApplicationsState mApplicationsState;
|
||||
private ApplicationsState.Session mSession;
|
||||
private ActivityFilter mActivityFilter;
|
||||
private Map<String, ApplicationsState.AppEntry> mEntryMap =
|
||||
new HashMap<String, ApplicationsState.AppEntry>();
|
||||
|
||||
private ThermalUtils mThermalUtils;
|
||||
private RecyclerView mAppsRecyclerView;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
|
||||
mSession = mApplicationsState.newSession(this);
|
||||
mSession.onResume();
|
||||
mActivityFilter = new ActivityFilter(getActivity().getPackageManager());
|
||||
|
||||
mAllPackagesAdapter = new AllPackagesAdapter(getActivity());
|
||||
|
||||
mThermalUtils = new ThermalUtils(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.thermal_layout, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
mAppsRecyclerView = view.findViewById(R.id.thermal_rv_view);
|
||||
mAppsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
mAppsRecyclerView.setAdapter(mAllPackagesAdapter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
getActivity().setTitle(getResources().getString(R.string.thermal_title));
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
mSession.onPause();
|
||||
mSession.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageListChanged() {
|
||||
mActivityFilter.updateLauncherInfoList();
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> entries) {
|
||||
if (entries != null) {
|
||||
handleAppEntries(entries);
|
||||
mAllPackagesAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadEntriesCompleted() {
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllSizesComputed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLauncherInfoChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageIconChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageSizeChanged(String packageName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRunningStateChanged(boolean running) {
|
||||
}
|
||||
|
||||
private void handleAppEntries(List<ApplicationsState.AppEntry> entries) {
|
||||
final ArrayList<String> sections = new ArrayList<String>();
|
||||
final ArrayList<Integer> positions = new ArrayList<Integer>();
|
||||
final PackageManager pm = getActivity().getPackageManager();
|
||||
String lastSectionIndex = null;
|
||||
int offset = 0;
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
final ApplicationInfo info = entries.get(i).info;
|
||||
final String label = (String) info.loadLabel(pm);
|
||||
final String sectionIndex;
|
||||
|
||||
if (!info.enabled) {
|
||||
sectionIndex = "--"; // XXX
|
||||
} else if (TextUtils.isEmpty(label)) {
|
||||
sectionIndex = "";
|
||||
} else {
|
||||
sectionIndex = label.substring(0, 1).toUpperCase();
|
||||
}
|
||||
|
||||
if (lastSectionIndex == null ||
|
||||
!TextUtils.equals(sectionIndex, lastSectionIndex)) {
|
||||
sections.add(sectionIndex);
|
||||
positions.add(offset);
|
||||
lastSectionIndex = sectionIndex;
|
||||
}
|
||||
|
||||
offset++;
|
||||
}
|
||||
|
||||
mAllPackagesAdapter.setEntries(entries, sections, positions);
|
||||
mEntryMap.clear();
|
||||
for (ApplicationsState.AppEntry e : entries) {
|
||||
mEntryMap.put(e.info.packageName, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuild() {
|
||||
mSession.rebuild(mActivityFilter, ApplicationsState.ALPHA_COMPARATOR);
|
||||
}
|
||||
|
||||
private int getStateDrawable(int state) {
|
||||
switch (state) {
|
||||
case ThermalUtils.STATE_BENCHMARK:
|
||||
return R.drawable.ic_thermal_benchmark;
|
||||
case ThermalUtils.STATE_BROWSER:
|
||||
return R.drawable.ic_thermal_browser;
|
||||
case ThermalUtils.STATE_CAMERA:
|
||||
return R.drawable.ic_thermal_camera;
|
||||
case ThermalUtils.STATE_DIALER:
|
||||
return R.drawable.ic_thermal_dialer;
|
||||
case ThermalUtils.STATE_GAMING:
|
||||
return R.drawable.ic_thermal_gaming;
|
||||
case ThermalUtils.STATE_STREAMING:
|
||||
return R.drawable.ic_thermal_streaming;
|
||||
case ThermalUtils.STATE_DEFAULT:
|
||||
default:
|
||||
return R.drawable.ic_thermal_default;
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private TextView title;
|
||||
private Spinner mode;
|
||||
private ImageView icon;
|
||||
private View rootView;
|
||||
private ImageView stateIcon;
|
||||
|
||||
private ViewHolder(View view) {
|
||||
super(view);
|
||||
this.title = view.findViewById(R.id.app_name);
|
||||
this.mode = view.findViewById(R.id.app_mode);
|
||||
this.icon = view.findViewById(R.id.app_icon);
|
||||
this.stateIcon = view.findViewById(R.id.state);
|
||||
this.rootView = view;
|
||||
|
||||
view.setTag(this);
|
||||
}
|
||||
}
|
||||
|
||||
private class ModeAdapter extends BaseAdapter {
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
private final int[] items = {
|
||||
R.string.thermal_default,
|
||||
R.string.thermal_benchmark,
|
||||
R.string.thermal_browser,
|
||||
R.string.thermal_camera,
|
||||
R.string.thermal_dialer,
|
||||
R.string.thermal_gaming,
|
||||
R.string.thermal_streaming
|
||||
};
|
||||
|
||||
private ModeAdapter(Context context) {
|
||||
inflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return items[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
TextView view;
|
||||
if (convertView != null) {
|
||||
view = (TextView) convertView;
|
||||
} else {
|
||||
view = (TextView) inflater.inflate(android.R.layout.simple_spinner_dropdown_item,
|
||||
parent, false);
|
||||
}
|
||||
|
||||
view.setText(items[position]);
|
||||
view.setTextSize(14f);
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
private class AllPackagesAdapter extends RecyclerView.Adapter<ViewHolder>
|
||||
implements AdapterView.OnItemSelectedListener, SectionIndexer {
|
||||
|
||||
private List<ApplicationsState.AppEntry> mEntries = new ArrayList<>();
|
||||
private String[] mSections;
|
||||
private int[] mPositions;
|
||||
|
||||
public AllPackagesAdapter(Context context) {
|
||||
mActivityFilter = new ActivityFilter(context.getPackageManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mEntries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mEntries.get(position).id;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
ViewHolder holder = new ViewHolder(LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.thermal_list_item, parent, false));
|
||||
Context context = holder.itemView.getContext();
|
||||
holder.mode.setAdapter(new ModeAdapter(context));
|
||||
holder.mode.setOnItemSelectedListener(this);
|
||||
return holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
ApplicationsState.AppEntry entry = mEntries.get(position);
|
||||
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
holder.title.setText(entry.label);
|
||||
holder.title.setOnClickListener(v -> holder.mode.performClick());
|
||||
mApplicationsState.ensureIcon(entry);
|
||||
holder.icon.setImageDrawable(entry.icon);
|
||||
int packageState = mThermalUtils.getStateForPackage(entry.info.packageName);
|
||||
holder.mode.setSelection(packageState, false);
|
||||
holder.mode.setTag(entry);
|
||||
holder.stateIcon.setImageResource(getStateDrawable(packageState));
|
||||
}
|
||||
|
||||
private void setEntries(List<ApplicationsState.AppEntry> entries,
|
||||
List<String> sections, List<Integer> positions) {
|
||||
mEntries = entries;
|
||||
mSections = sections.toArray(new String[sections.size()]);
|
||||
mPositions = new int[positions.size()];
|
||||
for (int i = 0; i < positions.size(); i++) {
|
||||
mPositions[i] = positions.get(i);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
final ApplicationsState.AppEntry entry = (ApplicationsState.AppEntry) parent.getTag();
|
||||
int currentState = mThermalUtils.getStateForPackage(entry.info.packageName);
|
||||
if (currentState != position) {
|
||||
mThermalUtils.writePackage(entry.info.packageName, position);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionForSection(int section) {
|
||||
if (section < 0 || section >= mSections.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mPositions[section];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionForPosition(int position) {
|
||||
if (position < 0 || position >= getItemCount()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final int index = Arrays.binarySearch(mPositions, position);
|
||||
|
||||
/*
|
||||
* Consider this example: section positions are 0, 3, 5; the supplied
|
||||
* position is 4. The section corresponding to position 4 starts at
|
||||
* position 3, so the expected return value is 1. Binary search will not
|
||||
* find 4 in the array and thus will return -insertPosition-1, i.e. -3.
|
||||
* To get from that number to the expected value of 1 we need to negate
|
||||
* and subtract 2.
|
||||
*/
|
||||
return index >= 0 ? index : -index - 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSections() {
|
||||
return mSections;
|
||||
}
|
||||
}
|
||||
|
||||
private class ActivityFilter implements ApplicationsState.AppFilter {
|
||||
|
||||
private final PackageManager mPackageManager;
|
||||
private final List<String> mLauncherResolveInfoList = new ArrayList<String>();
|
||||
|
||||
private ActivityFilter(PackageManager packageManager) {
|
||||
this.mPackageManager = packageManager;
|
||||
|
||||
updateLauncherInfoList();
|
||||
}
|
||||
|
||||
public void updateLauncherInfoList() {
|
||||
Intent i = new Intent(Intent.ACTION_MAIN);
|
||||
i.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
List<ResolveInfo> resolveInfoList = mPackageManager.queryIntentActivities(i, 0);
|
||||
|
||||
synchronized (mLauncherResolveInfoList) {
|
||||
mLauncherResolveInfoList.clear();
|
||||
for (ResolveInfo ri : resolveInfoList) {
|
||||
mLauncherResolveInfoList.add(ri.activityInfo.packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filterApp(ApplicationsState.AppEntry entry) {
|
||||
boolean show = !mAllPackagesAdapter.mEntries.contains(entry.info.packageName);
|
||||
if (show) {
|
||||
synchronized (mLauncherResolveInfoList) {
|
||||
show = mLauncherResolveInfoList.contains(entry.info.packageName);
|
||||
}
|
||||
}
|
||||
return show;
|
||||
}
|
||||
}
|
||||
}
|
||||
165
parts/src/org/lineageos/settings/thermal/ThermalUtils.java
Normal file
165
parts/src/org/lineageos/settings/thermal/ThermalUtils.java
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.thermal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.lineageos.settings.utils.FileUtils;
|
||||
|
||||
public final class ThermalUtils {
|
||||
|
||||
private static final String THERMAL_CONTROL = "thermal_control";
|
||||
|
||||
protected static final int STATE_DEFAULT = 0;
|
||||
protected static final int STATE_BENCHMARK = 1;
|
||||
protected static final int STATE_BROWSER = 2;
|
||||
protected static final int STATE_CAMERA = 3;
|
||||
protected static final int STATE_DIALER = 4;
|
||||
protected static final int STATE_GAMING = 5;
|
||||
protected static final int STATE_STREAMING = 6;
|
||||
|
||||
private static final String THERMAL_STATE_DEFAULT = "0";
|
||||
private static final String THERMAL_STATE_BENCHMARK = "10";
|
||||
private static final String THERMAL_STATE_BROWSER = "11";
|
||||
private static final String THERMAL_STATE_CAMERA = "12";
|
||||
private static final String THERMAL_STATE_DIALER = "8";
|
||||
private static final String THERMAL_STATE_GAMING = "9";
|
||||
private static final String THERMAL_STATE_STREAMING = "14";
|
||||
|
||||
private static final String THERMAL_BENCHMARK = "thermal.benchmark=";
|
||||
private static final String THERMAL_BROWSER = "thermal.browser=";
|
||||
private static final String THERMAL_CAMERA = "thermal.camera=";
|
||||
private static final String THERMAL_DIALER = "thermal.dialer=";
|
||||
private static final String THERMAL_GAMING = "thermal.gaming=";
|
||||
private static final String THERMAL_STREAMING = "thermal.streaming=";
|
||||
|
||||
private static final String THERMAL_SCONFIG = "/sys/class/thermal/thermal_message/sconfig";
|
||||
|
||||
private SharedPreferences mSharedPrefs;
|
||||
|
||||
protected ThermalUtils(Context context) {
|
||||
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
}
|
||||
|
||||
public static void startService(Context context) {
|
||||
context.startServiceAsUser(new Intent(context, ThermalService.class),
|
||||
UserHandle.CURRENT);
|
||||
}
|
||||
|
||||
private void writeValue(String profiles) {
|
||||
mSharedPrefs.edit().putString(THERMAL_CONTROL, profiles).apply();
|
||||
}
|
||||
|
||||
private String getValue() {
|
||||
String value = mSharedPrefs.getString(THERMAL_CONTROL, null);
|
||||
|
||||
if (value == null || value.isEmpty()) {
|
||||
value = THERMAL_BENCHMARK + ":" + THERMAL_BROWSER + ":" + THERMAL_CAMERA + ":" +
|
||||
THERMAL_DIALER + ":" + THERMAL_GAMING + ":" + THERMAL_STREAMING;
|
||||
writeValue(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected void writePackage(String packageName, int mode) {
|
||||
String value = getValue();
|
||||
value = value.replace(packageName + ",", "");
|
||||
String[] modes = value.split(":");
|
||||
String finalString;
|
||||
|
||||
switch (mode) {
|
||||
case STATE_BENCHMARK:
|
||||
modes[0] = modes[0] + packageName + ",";
|
||||
break;
|
||||
case STATE_BROWSER:
|
||||
modes[1] = modes[1] + packageName + ",";
|
||||
break;
|
||||
case STATE_CAMERA:
|
||||
modes[2] = modes[2] + packageName + ",";
|
||||
break;
|
||||
case STATE_DIALER:
|
||||
modes[3] = modes[3] + packageName + ",";
|
||||
break;
|
||||
case STATE_GAMING:
|
||||
modes[4] = modes[4] + packageName + ",";
|
||||
break;
|
||||
case STATE_STREAMING:
|
||||
modes[5] = modes[5] + packageName + ",";
|
||||
break;
|
||||
}
|
||||
|
||||
finalString = modes[0] + ":" + modes[1] + ":" + modes[2] + ":" + modes[3] + ":" +
|
||||
modes[4] + ":" + modes[5];
|
||||
|
||||
writeValue(finalString);
|
||||
}
|
||||
|
||||
protected int getStateForPackage(String packageName) {
|
||||
String value = getValue();
|
||||
String[] modes = value.split(":");
|
||||
int state = STATE_DEFAULT;
|
||||
if (modes[0].contains(packageName + ",")) {
|
||||
state = STATE_BENCHMARK;
|
||||
} else if (modes[1].contains(packageName + ",")) {
|
||||
state = STATE_BROWSER;
|
||||
} else if (modes[2].contains(packageName + ",")) {
|
||||
state = STATE_CAMERA;
|
||||
} else if (modes[3].contains(packageName + ",")) {
|
||||
state = STATE_DIALER;
|
||||
} else if (modes[4].contains(packageName + ",")) {
|
||||
state = STATE_GAMING;
|
||||
} else if (modes[5].contains(packageName + ",")) {
|
||||
state = STATE_STREAMING;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
protected void setDefaultThermalProfile() {
|
||||
FileUtils.writeLine(THERMAL_SCONFIG, THERMAL_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
protected void setThermalProfile(String packageName) {
|
||||
String value = getValue();
|
||||
String modes[];
|
||||
String state = THERMAL_STATE_DEFAULT;
|
||||
|
||||
if (value != null) {
|
||||
modes = value.split(":");
|
||||
|
||||
if (modes[0].contains(packageName + ",")) {
|
||||
state = THERMAL_STATE_BENCHMARK;
|
||||
} else if (modes[1].contains(packageName + ",")) {
|
||||
state = THERMAL_STATE_BROWSER;
|
||||
} else if (modes[2].contains(packageName + ",")) {
|
||||
state = THERMAL_STATE_CAMERA;
|
||||
} else if (modes[3].contains(packageName + ",")) {
|
||||
state = THERMAL_STATE_DIALER;
|
||||
} else if (modes[4].contains(packageName + ",")) {
|
||||
state = THERMAL_STATE_GAMING;
|
||||
} else if (modes[5].contains(packageName + ",")) {
|
||||
state = THERMAL_STATE_STREAMING;
|
||||
}
|
||||
}
|
||||
FileUtils.writeLine(THERMAL_SCONFIG, state);
|
||||
}
|
||||
}
|
||||
47
parts/src/org/lineageos/settings/utils/ComponentUtils.java
Normal file
47
parts/src/org/lineageos/settings/utils/ComponentUtils.java
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
222
parts/src/org/lineageos/settings/utils/FileUtils.java
Normal file
222
parts/src/org/lineageos/settings/utils/FileUtils.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user