Compare commits
16 commits
c723e710ab
...
9e750ef2d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e750ef2d1 | ||
|
|
a6a0bbf8e1 | ||
|
|
b226c659cb | ||
|
|
c165248466 | ||
|
|
51659a044d | ||
|
|
c873db5b07 | ||
|
|
77e324ab72 | ||
|
|
acf4649586 | ||
|
|
3c102e80f4 | ||
|
|
9fcc609526 | ||
|
|
8fa7797f8d | ||
|
|
5684a5e044 | ||
|
|
de2fb061fd | ||
|
|
350a96ba76 | ||
|
|
892334b356 | ||
|
|
d9e11d3f64 |
38 changed files with 3762 additions and 0 deletions
|
|
@ -46,6 +46,9 @@ TARGET_NO_BOOTLOADER := true
|
|||
# Display
|
||||
TARGET_SCREEN_DENSITY ?= 440
|
||||
|
||||
# Camera
|
||||
TARGET_CAMERA_SERVICE_EXT_LIB := //$(COMMON_PATH):libcameraservice_extension.xiaomi_sm8350
|
||||
|
||||
# Filesystem
|
||||
TARGET_FS_CONFIG_GEN := $(COMMON_PATH)/config.fs
|
||||
|
||||
|
|
|
|||
22
camera/Android.bp
Normal file
22
camera/Android.bp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// Copyright (C) 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.
|
||||
|
||||
cc_library_static {
|
||||
name: "libcameraservice_extension.xiaomi_sm8350",
|
||||
srcs: ["CameraProviderExtension.cpp"],
|
||||
include_dirs: [
|
||||
"frameworks/av/services/camera/libcameraservice/common"
|
||||
],
|
||||
}
|
||||
74
camera/CameraProviderExtension.cpp
Normal file
74
camera/CameraProviderExtension.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (C) 2024 LibreMobileOS Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "CameraProviderExtension.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#define TORCH_BRIGHTNESS "brightness"
|
||||
#define TORCH_MAX_BRIGHTNESS "max_brightness"
|
||||
#define TOGGLE_SWITCH "/sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm8350c@2:qcom,flash_led@ee00/leds/led:switch_1/brightness"
|
||||
static std::string kTorchLedPath = "/sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm8350c@2:qcom,flash_led@ee00/leds/led:torch_1";
|
||||
|
||||
/**
|
||||
* Write value to path and close file.
|
||||
*/
|
||||
template <typename T>
|
||||
static void set(const std::string& path, const T& value) {
|
||||
std::ofstream file(path);
|
||||
file << value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read value from the path and close file.
|
||||
*/
|
||||
template <typename T>
|
||||
static T get(const std::string& path, const T& def) {
|
||||
std::ifstream file(path);
|
||||
T result;
|
||||
|
||||
file >> result;
|
||||
return file.fail() ? def : result;
|
||||
}
|
||||
|
||||
bool supportsTorchStrengthControlExt() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool supportsSetTorchModeExt() {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t getTorchDefaultStrengthLevelExt() {
|
||||
return 80;
|
||||
}
|
||||
|
||||
int32_t getTorchMaxStrengthLevelExt() {
|
||||
// In our device, both LEDs has same maximum value
|
||||
// so get from one.
|
||||
auto node = kTorchLedPath + "/" + TORCH_MAX_BRIGHTNESS;
|
||||
return 750;
|
||||
}
|
||||
|
||||
int32_t getTorchStrengthLevelExt() {
|
||||
// We write same value in the both LEDs,
|
||||
// so get from one.
|
||||
auto node = kTorchLedPath + "/" + TORCH_BRIGHTNESS;
|
||||
return get(node, 0);
|
||||
}
|
||||
|
||||
void setTorchStrengthLevelExt(int32_t torchStrength, bool enabled) {
|
||||
set(TOGGLE_SWITCH, 0);
|
||||
auto node = kTorchLedPath + "/" + TORCH_BRIGHTNESS;
|
||||
set(node, torchStrength);
|
||||
if (enabled)
|
||||
set(TOGGLE_SWITCH, 255);
|
||||
}
|
||||
|
||||
void setTorchModeExt(bool enabled) {
|
||||
int32_t strength = getTorchDefaultStrengthLevelExt();
|
||||
setTorchStrengthLevelExt(enabled ? strength : 0, enabled);
|
||||
}
|
||||
|
|
@ -127,6 +127,11 @@ PRODUCT_COPY_FILES += \
|
|||
frameworks/native/data/etc/android.hardware.camera.full.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.full.xml \
|
||||
frameworks/native/data/etc/android.hardware.camera.raw.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.camera.raw.xml
|
||||
|
||||
# Config Store
|
||||
PRODUCT_PACKAGES += \
|
||||
vendor.qti.hardware.capabilityconfigstore@1.0 \
|
||||
vendor.qti.hardware.capabilityconfigstore@1.0.vendor
|
||||
|
||||
# DebugFS
|
||||
PRODUCT_SET_DEBUGFS_RESTRICTIONS := true
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ lib_fixups: lib_fixups_user_type = {
|
|||
'libmmosal',
|
||||
'vendor.qti.hardware.wifidisplaysession@1.0',
|
||||
'vendor.qti.imsrtpservice@3.0',
|
||||
'vendor.qti.diaghal@1.0',
|
||||
): lib_fixup_vendor_suffix,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.lineageos.settings"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
android:sharedUserId="android.uid.system">
|
||||
|
|
@ -24,6 +25,8 @@
|
|||
<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.SYSTEM_ALERT_WINDOW" />
|
||||
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" tools:ignore="ProtectedPermissions" />
|
||||
|
||||
<protected-broadcast android:name="com.android.systemui.doze.pulse" />
|
||||
|
||||
|
|
@ -203,5 +206,54 @@
|
|||
android:name="android.service.quicksettings.action.QS_TILE"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- GameBar Overlay -->
|
||||
<activity
|
||||
android:name=".gameoverlay.GameOverlaySettingsActivity"
|
||||
android:label="@string/game_overlay_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.system" />
|
||||
<meta-data
|
||||
android:name="com.android.settings.summary"
|
||||
android:resource="@string/game_overlay_summary" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.android.settings.icon"
|
||||
android:resource="@drawable/ic_gamebar" />
|
||||
</activity>
|
||||
|
||||
<!-- GameBar Overlay Tile Service -->
|
||||
<service
|
||||
android:name=".gameoverlay.GameOverlayTileService"
|
||||
android:label="@string/game_overlay_tile_label"
|
||||
android:icon="@drawable/ic_gamebar_overlay_tile"
|
||||
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 BootReceiver -->
|
||||
<receiver
|
||||
android:name="org.lineageos.settings.gameoverlay.GameOverlayBootReceiver"
|
||||
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>
|
||||
|
|
|
|||
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_gamebar_overlay_tile.xml
Normal file
10
parts/res/drawable/ic_gamebar_overlay_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="M189,800Q129,800 86.5,757Q44,714 42,653Q42,644 43,635Q44,626 46,617L130,281Q144,227 187,193.5Q230,160 285,160L675,160Q730,160 773,193.5Q816,227 830,281L914,617Q916,626 917.5,635.5Q919,645 919,654Q919,715 875.5,757.5Q832,800 771,800Q729,800 693,778Q657,756 639,718L611,660Q606,650 596,645Q586,640 575,640L385,640Q374,640 364,645Q354,650 349,660L321,718Q303,756 267,778Q231,800 189,800ZM540.12,433.33Q554.33,433.33 563.83,423.72Q573.33,414.1 573.33,399.88Q573.33,385.67 563.72,376.17Q554.1,366.67 539.88,366.67Q525.67,366.67 516.17,376.28Q506.67,385.9 506.67,400.12Q506.67,414.33 516.28,423.83Q525.9,433.33 540.12,433.33ZM620.12,353.33Q634.33,353.33 643.83,343.72Q653.33,334.1 653.33,319.88Q653.33,305.67 643.72,296.17Q634.1,286.67 619.88,286.67Q605.67,286.67 596.17,296.28Q586.67,305.9 586.67,320.12Q586.67,334.33 596.28,343.83Q605.9,353.33 620.12,353.33ZM620.12,513.33Q634.33,513.33 643.83,503.72Q653.33,494.1 653.33,479.88Q653.33,465.67 643.72,456.17Q634.1,446.67 619.88,446.67Q605.67,446.67 596.17,456.28Q586.67,465.9 586.67,480.12Q586.67,494.33 596.28,503.83Q605.9,513.33 620.12,513.33ZM700.12,433.33Q714.33,433.33 723.83,423.72Q733.33,414.1 733.33,399.88Q733.33,385.67 723.72,376.17Q714.1,366.67 699.88,366.67Q685.67,366.67 676.17,376.28Q666.67,385.9 666.67,400.12Q666.67,414.33 676.28,423.83Q685.9,433.33 700.12,433.33ZM340.08,496.67Q351.67,496.67 359.17,489.11Q366.67,481.56 366.67,470L366.67,426.67L410,426.67Q421.56,426.67 429.11,419.09Q436.67,411.51 436.67,399.92Q436.67,388.33 429.11,380.83Q421.56,373.33 410,373.33L366.67,373.33L366.67,330Q366.67,318.44 359.09,310.89Q351.51,303.33 339.92,303.33Q328.33,303.33 320.83,310.89Q313.33,318.44 313.33,330L313.33,373.33L270,373.33Q258.44,373.33 250.89,380.91Q243.33,388.49 243.33,400.08Q243.33,411.67 250.89,419.17Q258.44,426.67 270,426.67L313.33,426.67L313.33,470Q313.33,481.56 320.91,489.11Q328.49,496.67 340.08,496.67Z"/>
|
||||
</vector>
|
||||
12
parts/res/layout/activity_game_overlay.xml
Normal file
12
parts/res/layout/activity_game_overlay.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_overlay_fragment"
|
||||
android:name="org.lineageos.settings.gameoverlay.GameOverlayFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
10
parts/res/layout/game_overlay.xml
Normal file
10
parts/res/layout/game_overlay.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_overlay_root"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#80000000"
|
||||
android:padding="8dp"
|
||||
android:orientation="vertical">
|
||||
</LinearLayout>
|
||||
|
|
@ -25,4 +25,95 @@
|
|||
<item>1</item>
|
||||
<item>2</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_overlay_format_entries">
|
||||
<item>Full</item>
|
||||
<item>Minimal</item>
|
||||
</string-array>
|
||||
<string-array name="game_overlay_format_values">
|
||||
<item>full</item>
|
||||
<item>minimal</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Split Mode -->
|
||||
<string-array name="game_overlay_split_mode_entries">
|
||||
<item>Side-by-Side</item>
|
||||
<item>Stacked</item>
|
||||
</string-array>
|
||||
<string-array name="game_overlay_split_mode_values">
|
||||
<item>side_by_side</item>
|
||||
<item>stacked</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Long press timeouts -->
|
||||
<string-array name="game_overlay_longpress_entries">
|
||||
<item>1 second</item>
|
||||
<item>3 seconds</item>
|
||||
<item>5 seconds</item>
|
||||
<item>10 seconds</item>
|
||||
</string-array>
|
||||
<string-array name="game_overlay_longpress_values">
|
||||
<item>1000</item>
|
||||
<item>3000</item>
|
||||
<item>5000</item>
|
||||
<item>10000</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -72,4 +72,13 @@
|
|||
<string name="htsr_enable_summary">Increases touch polling rate to decrease latency</string>
|
||||
<string name="htsr_enable_summary_not_supported">Increase Touch Responsiveness is currently not supported by the kernel</string>
|
||||
|
||||
<!-- GameBar Overlay -->
|
||||
<string name="game_overlay_title">GameBar</string>
|
||||
<string name="game_overlay_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_overlay_tile_label">GameBar</string>
|
||||
<string name="game_overlay_tile_description">Toggle the game overlay</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
221
parts/res/xml/game_overlay_preferences.xml
Normal file
221
parts/res/xml/game_overlay_preferences.xml
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
<?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">
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_enable"
|
||||
android:title="Enable GameBar Overlay"
|
||||
android:summary="@string/game_overlay_summary"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Overlay Features"
|
||||
android:dependency="game_overlay_enable">
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_fps_enable"
|
||||
android:title="FPS Overlay"
|
||||
android:summary="Show current FPS on screen"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_temp_enable"
|
||||
android:title="Device Temperature"
|
||||
android:summary="Show device (battery) temperature"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_cpu_usage_enable"
|
||||
android:title="CPU Usage"
|
||||
android:summary="Show current CPU usage percentage"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_cpu_clock_enable"
|
||||
android:title="CPU Clock Speeds"
|
||||
android:summary="Show current CPU clock speeds for each core"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_cpu_temp_enable"
|
||||
android:title="CPU Temperature"
|
||||
android:summary="Show CPU temperature (thermal_zone0)"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_ram_enable"
|
||||
android:title="RAM Usage"
|
||||
android:summary="Show current RAM usage in MB"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_gpu_usage_enable"
|
||||
android:title="GPU Usage"
|
||||
android:summary="Show GPU usage percentage"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_gpu_clock_enable"
|
||||
android:title="GPU Clock Speed"
|
||||
android:summary="Show current GPU clock frequency"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_gpu_temp_enable"
|
||||
android:title="GPU Temperature"
|
||||
android:summary="Show current GPU temperature"
|
||||
android:defaultValue="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Customization"
|
||||
android:dependency="game_overlay_enable">
|
||||
|
||||
<SeekBarPreference
|
||||
android:key="game_overlay_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_overlay_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_overlay_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_overlay_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_overlay_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_overlay_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_overlay_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_overlay_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_overlay_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_overlay_format"
|
||||
android:title="Overlay Format"
|
||||
android:summary="Choose between Full or Minimal display"
|
||||
android:defaultValue="full"
|
||||
android:entries="@array/game_overlay_format_entries"
|
||||
android:entryValues="@array/game_overlay_format_values" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Split Config"
|
||||
android:dependency="game_overlay_enable">
|
||||
|
||||
<ListPreference
|
||||
android:key="game_overlay_split_mode"
|
||||
android:title="Split Mode"
|
||||
android:summary="Choose Side-by-Side or Stacked arrangement"
|
||||
android:defaultValue="stacked"
|
||||
android:entries="@array/game_overlay_split_mode_entries"
|
||||
android:entryValues="@array/game_overlay_split_mode_values" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Overlay Gesture Controls"
|
||||
android:dependency="game_overlay_enable">
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_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" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_doubletap_capture"
|
||||
android:title="Enable Double Tap to Capture"
|
||||
android:summary="Double-tap overlay to start/stop capture logs"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<SwitchPreference
|
||||
android:key="game_overlay_longpress_enable"
|
||||
android:title="Enable Long Press"
|
||||
android:summary="Long-press overlay to access Gamebar settings"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<ListPreference
|
||||
android:key="game_overlay_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_overlay_longpress_entries"
|
||||
android:entryValues="@array/game_overlay_longpress_values"
|
||||
android:dependency="game_overlay_longpress_enable" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="Capture Logs"
|
||||
android:dependency="game_overlay_enable">
|
||||
|
||||
<Preference
|
||||
android:key="game_overlay_capture_start"
|
||||
android:title="Start Logging"
|
||||
android:summary="Begin capturing FPS and performance data in real-time" />
|
||||
|
||||
<Preference
|
||||
android:key="game_overlay_capture_stop"
|
||||
android:title="Stop Logging"
|
||||
android:summary="Stop capturing FPS and performance data in real-time" />
|
||||
|
||||
<Preference
|
||||
android:key="game_overlay_capture_export"
|
||||
android:title="Export GameBar Log Data"
|
||||
android:summary="Save the captured FPS and performance data as a CSV file" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
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.gameoverlay.GameOverlaySettingsActivity;
|
||||
import org.lineageos.settings.gameoverlay.GameOverlayTileService;
|
||||
|
||||
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(GameOverlayTileService.class.getName(), GameOverlaySettingsActivity.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,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.gameoverlay;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
132
parts/src/org/lineageos/settings/gameoverlay/GameDataExport.java
Normal file
132
parts/src/org/lineageos/settings/gameoverlay/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.gameoverlay;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
776
parts/src/org/lineageos/settings/gameoverlay/GameOverlay.java
Normal file
776
parts/src/org/lineageos/settings/gameoverlay/GameOverlay.java
Normal file
|
|
@ -0,0 +1,776 @@
|
|||
/*
|
||||
* 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.gameoverlay;
|
||||
|
||||
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 GameOverlay {
|
||||
|
||||
private static GameOverlay sInstance;
|
||||
public static synchronized GameOverlay getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new GameOverlay(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_overlay_x";
|
||||
private static final String PREF_KEY_Y = "game_overlay_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 mPosition = "top_left";
|
||||
private String mSplitMode = "stacked";
|
||||
private String mOverlayFormat = "full";
|
||||
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 GameOverlay(Context context) {
|
||||
mContext = context;
|
||||
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
mBgDrawable = new GradientDrawable();
|
||||
applyBackgroundStyle();
|
||||
}
|
||||
|
||||
public void applyPreferences() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||
|
||||
mShowFps = prefs.getBoolean("game_overlay_fps_enable", false);
|
||||
mShowBatteryTemp = prefs.getBoolean("game_overlay_temp_enable", false);
|
||||
mShowCpuUsage = prefs.getBoolean("game_overlay_cpu_usage_enable", false);
|
||||
mShowCpuClock = prefs.getBoolean("game_overlay_cpu_clock_enable", false);
|
||||
mShowCpuTemp = prefs.getBoolean("game_overlay_cpu_temp_enable", false);
|
||||
mShowRam = prefs.getBoolean("game_overlay_ram_enable", false);
|
||||
|
||||
mShowGpuUsage = prefs.getBoolean("game_overlay_gpu_usage_enable", false);
|
||||
mShowGpuClock = prefs.getBoolean("game_overlay_gpu_clock_enable", false);
|
||||
mShowGpuTemp = prefs.getBoolean("game_overlay_gpu_temp_enable", false);
|
||||
|
||||
mDoubleTapCaptureEnabled = prefs.getBoolean("game_overlay_doubletap_capture", false);
|
||||
mSingleTapToggleEnabled = prefs.getBoolean("game_overlay_single_tap_toggle", false);
|
||||
|
||||
updateSplitMode(prefs.getString("game_overlay_split_mode", "stacked"));
|
||||
updateTextSize(prefs.getInt("game_overlay_text_size", 16));
|
||||
updateBackgroundAlpha(prefs.getInt("game_overlay_background_alpha", 128));
|
||||
updateCornerRadius(prefs.getInt("game_overlay_corner_radius", 16));
|
||||
updatePadding(prefs.getInt("game_overlay_padding", 12));
|
||||
updateTitleColor(prefs.getString("game_overlay_title_color", "#FFFFFF"));
|
||||
updateValueColor(prefs.getString("game_overlay_value_color", "#4CAF50"));
|
||||
updateOverlayFormat(prefs.getString("game_overlay_format", "full"));
|
||||
updateUpdateInterval(prefs.getString("game_overlay_update_interval", "1000"));
|
||||
updatePosition(prefs.getString("game_overlay_position", "top_left"));
|
||||
|
||||
int spacing = prefs.getInt("game_overlay_item_spacing", 8);
|
||||
updateItemSpacing(spacing);
|
||||
|
||||
mLongPressEnabled = prefs.getBoolean("game_overlay_longpress_enable", false);
|
||||
String lpTimeoutStr = prefs.getString("game_overlay_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();
|
||||
|
||||
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";
|
||||
Toast.makeText(mContext, "Overlay Format: " + mOverlayFormat, Toast.LENGTH_SHORT).show();
|
||||
updateStats();
|
||||
return true;
|
||||
}
|
||||
return super.onSingleTapConfirmed(e);
|
||||
}
|
||||
});
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void updateStats() {
|
||||
if (!mIsShowing || mRootLayout == null) return;
|
||||
|
||||
mRootLayout.removeAllViews();
|
||||
|
||||
List<View> statViews = new ArrayList<>();
|
||||
|
||||
// 1) FPS
|
||||
float fpsVal = parseFps();
|
||||
String fpsStr = fpsVal >= 0 ? String.format(Locale.getDefault(), "%.1f", 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 = GameOverlayCpuInfo.getCpuUsage();
|
||||
String display = "N/A".equals(cpuUsageStr) ? "N/A" : cpuUsageStr + "%";
|
||||
statViews.add(createStatLine("CPU", display));
|
||||
}
|
||||
|
||||
// 4) CPU freq
|
||||
if (mShowCpuClock) {
|
||||
List<String> freqs = GameOverlayCpuInfo.getCpuFrequencies();
|
||||
if (!freqs.isEmpty()) {
|
||||
statViews.add(buildCpuFreqView(freqs));
|
||||
}
|
||||
}
|
||||
|
||||
// 5) CPU temp
|
||||
String cpuTempStr = "N/A";
|
||||
if (mShowCpuTemp) {
|
||||
cpuTempStr = GameOverlayCpuInfo.getCpuTemp();
|
||||
statViews.add(createStatLine("CPU Temp", "N/A".equals(cpuTempStr) ? "N/A" : cpuTempStr + "°C"));
|
||||
}
|
||||
|
||||
// 6) RAM usage
|
||||
String ramStr = "N/A";
|
||||
if (mShowRam) {
|
||||
ramStr = GameOverlayMemInfo.getRamUsage();
|
||||
statViews.add(createStatLine("RAM", "N/A".equals(ramStr) ? "N/A" : ramStr + " MB"));
|
||||
}
|
||||
|
||||
// 7) GPU usage
|
||||
String gpuUsageStr = "N/A";
|
||||
if (mShowGpuUsage) {
|
||||
gpuUsageStr = GameOverlayGpuInfo.getGpuUsage();
|
||||
statViews.add(createStatLine("GPU", "N/A".equals(gpuUsageStr) ? "N/A" : gpuUsageStr + "%"));
|
||||
}
|
||||
|
||||
// 8) GPU clock
|
||||
String gpuClockStr = "N/A";
|
||||
if (mShowGpuClock) {
|
||||
gpuClockStr = GameOverlayGpuInfo.getGpuClock();
|
||||
statViews.add(createStatLine("GPU Freq", "N/A".equals(gpuClockStr) ? "N/A" : gpuClockStr + "MHz"));
|
||||
}
|
||||
|
||||
// 9) GPU temp
|
||||
String gpuTempStr = "N/A";
|
||||
if (mShowGpuTemp) {
|
||||
gpuTempStr = GameOverlayGpuInfo.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, // PackageName
|
||||
fpsStr, // FPS
|
||||
batteryTempStr, // Battery_Temp
|
||||
cpuUsageStr, // CPU_Usage
|
||||
cpuTempStr, // CPU_Temp
|
||||
gpuUsageStr, // GPU_Usage
|
||||
gpuClockStr, // GPU_Clock
|
||||
gpuTempStr // GPU_Temp
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private float parseFps() {
|
||||
String line = readLine(FPS_PATH);
|
||||
if (line != null && line.startsWith("fps:")) {
|
||||
String[] parts = line.split("\\s+");
|
||||
if (parts.length >= 2) {
|
||||
try {
|
||||
return Float.parseFloat(parts[1].trim());
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
}
|
||||
return -1f;
|
||||
}
|
||||
|
||||
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, GameOverlaySettingsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
private static int dpToPx(Context context, int dp) {
|
||||
float scale = context.getResources().getDisplayMetrics().density;
|
||||
return Math.round(dp * scale);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.gameoverlay;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public class GameOverlayBootReceiver 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 enabled = prefs.getBoolean("game_overlay_enable", false);
|
||||
GameOverlay overlay = GameOverlay.getInstance(context);
|
||||
if (!enabled) {
|
||||
overlay.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
overlay.applyPreferences();
|
||||
overlay.show();
|
||||
}
|
||||
}
|
||||
|
|
@ -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.gameoverlay;
|
||||
|
||||
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 GameOverlayCpuInfo {
|
||||
|
||||
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(GameOverlayCpuInfo::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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* 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.gameoverlay;
|
||||
|
||||
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 org.lineageos.settings.R;
|
||||
|
||||
public class GameOverlayFragment extends PreferenceFragmentCompat {
|
||||
|
||||
private GameOverlay mOverlay;
|
||||
|
||||
private SwitchPreference mMasterSwitch;
|
||||
|
||||
private SwitchPreference mFpsSwitch;
|
||||
private SwitchPreference mBatteryTempSwitch;
|
||||
private SwitchPreference mCpuUsageSwitch;
|
||||
private SwitchPreference mCpuClockSwitch;
|
||||
private SwitchPreference mCpuTempSwitch;
|
||||
private SwitchPreference mRamSwitch;
|
||||
|
||||
private SwitchPreference mGpuUsageSwitch;
|
||||
private SwitchPreference mGpuClockSwitch;
|
||||
private SwitchPreference mGpuTempSwitch;
|
||||
|
||||
private Preference mCaptureStartPref;
|
||||
private Preference mCaptureStopPref;
|
||||
private Preference mCaptureExportPref;
|
||||
|
||||
private SwitchPreference mDoubleTapCapturePref;
|
||||
private SwitchPreference mSingleTapTogglePref;
|
||||
private SwitchPreference 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_overlay_preferences, rootKey);
|
||||
|
||||
mOverlay = GameOverlay.getInstance(getContext());
|
||||
|
||||
mMasterSwitch = findPreference("game_overlay_enable");
|
||||
|
||||
mFpsSwitch = findPreference("game_overlay_fps_enable");
|
||||
mBatteryTempSwitch = findPreference("game_overlay_temp_enable");
|
||||
mCpuUsageSwitch = findPreference("game_overlay_cpu_usage_enable");
|
||||
mCpuClockSwitch = findPreference("game_overlay_cpu_clock_enable");
|
||||
mCpuTempSwitch = findPreference("game_overlay_cpu_temp_enable");
|
||||
mRamSwitch = findPreference("game_overlay_ram_enable");
|
||||
|
||||
mGpuUsageSwitch = findPreference("game_overlay_gpu_usage_enable");
|
||||
mGpuClockSwitch = findPreference("game_overlay_gpu_clock_enable");
|
||||
mGpuTempSwitch = findPreference("game_overlay_gpu_temp_enable");
|
||||
|
||||
mCaptureStartPref = findPreference("game_overlay_capture_start");
|
||||
mCaptureStopPref = findPreference("game_overlay_capture_stop");
|
||||
mCaptureExportPref = findPreference("game_overlay_capture_export");
|
||||
|
||||
mDoubleTapCapturePref = findPreference("game_overlay_doubletap_capture");
|
||||
mSingleTapTogglePref = findPreference("game_overlay_single_tap_toggle");
|
||||
mLongPressEnablePref = findPreference("game_overlay_longpress_enable");
|
||||
mLongPressTimeoutPref = findPreference("game_overlay_longpress_timeout");
|
||||
|
||||
mTextSizePref = findPreference("game_overlay_text_size");
|
||||
mBgAlphaPref = findPreference("game_overlay_background_alpha");
|
||||
mCornerRadiusPref = findPreference("game_overlay_corner_radius");
|
||||
mPaddingPref = findPreference("game_overlay_padding");
|
||||
mItemSpacingPref = findPreference("game_overlay_item_spacing");
|
||||
|
||||
mUpdateIntervalPref = findPreference("game_overlay_update_interval");
|
||||
mTextColorPref = findPreference("game_overlay_text_color");
|
||||
mTitleColorPref = findPreference("game_overlay_title_color");
|
||||
mValueColorPref = findPreference("game_overlay_value_color");
|
||||
mPositionPref = findPreference("game_overlay_position");
|
||||
mSplitModePref = findPreference("game_overlay_split_mode");
|
||||
mOverlayFormatPref = findPreference("game_overlay_format");
|
||||
|
||||
if (mMasterSwitch != null) {
|
||||
mMasterSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
boolean enabled = (boolean) newValue;
|
||||
if (enabled) {
|
||||
if (Settings.canDrawOverlays(getContext())) {
|
||||
mOverlay.applyPreferences();
|
||||
mOverlay.show();
|
||||
} else {
|
||||
Toast.makeText(getContext(), R.string.overlay_permission_required, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
mOverlay.hide();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (mFpsSwitch != null) {
|
||||
mFpsSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setShowFps((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mBatteryTempSwitch != null) {
|
||||
mBatteryTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setShowBatteryTemp((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCpuUsageSwitch != null) {
|
||||
mCpuUsageSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setShowCpuUsage((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCpuClockSwitch != null) {
|
||||
mCpuClockSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setShowCpuClock((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCpuTempSwitch != null) {
|
||||
mCpuTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setShowCpuTemp((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mRamSwitch != null) {
|
||||
mRamSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setShowRam((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (mGpuUsageSwitch != null) {
|
||||
mGpuUsageSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setShowGpuUsage((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mGpuClockSwitch != null) {
|
||||
mGpuClockSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setShowGpuClock((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mGpuTempSwitch != null) {
|
||||
mGpuTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.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) -> {
|
||||
mOverlay.setDoubleTapCaptureEnabled((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mSingleTapTogglePref != null) {
|
||||
mSingleTapTogglePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setSingleTapToggleEnabled((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mLongPressEnablePref != null) {
|
||||
mLongPressEnablePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
mOverlay.setLongPressEnabled((boolean) newValue);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mLongPressTimeoutPref != null) {
|
||||
mLongPressTimeoutPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
long ms = Long.parseLong((String) newValue);
|
||||
mOverlay.setLongPressThresholdMs(ms);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (mTextSizePref != null) {
|
||||
mTextSizePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mOverlay.updateTextSize((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mBgAlphaPref != null) {
|
||||
mBgAlphaPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mOverlay.updateBackgroundAlpha((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mCornerRadiusPref != null) {
|
||||
mCornerRadiusPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mOverlay.updateCornerRadius((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mPaddingPref != null) {
|
||||
mPaddingPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mOverlay.updatePadding((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (mItemSpacingPref != null) {
|
||||
mItemSpacingPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof Integer) {
|
||||
mOverlay.updateItemSpacing((Integer) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (mUpdateIntervalPref != null) {
|
||||
mUpdateIntervalPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mOverlay.updateUpdateInterval((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mTextColorPref != null) {
|
||||
mTextColorPref.setOnPreferenceChangeListener((pref, newValue) -> true);
|
||||
}
|
||||
if (mTitleColorPref != null) {
|
||||
mTitleColorPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mOverlay.updateTitleColor((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mValueColorPref != null) {
|
||||
mValueColorPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mOverlay.updateValueColor((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mPositionPref != null) {
|
||||
mPositionPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mOverlay.updatePosition((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mSplitModePref != null) {
|
||||
mSplitModePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mOverlay.updateSplitMode((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (mOverlayFormatPref != null) {
|
||||
mOverlayFormatPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (newValue instanceof String) {
|
||||
mOverlay.updateOverlayFormat((String) newValue);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (!hasUsageStatsPermission(requireContext())) {
|
||||
requestUsageStatsPermission();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.gameoverlay;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class GameOverlayGpuInfo {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.gameoverlay;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
public class GameOverlayMemInfo {
|
||||
|
||||
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,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.gameoverlay;
|
||||
|
||||
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 GameOverlaySettingsActivity 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_overlay);
|
||||
setTitle(getString(R.string.game_overlay_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,73 @@
|
|||
/*
|
||||
* 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.gameoverlay;
|
||||
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import org.lineageos.settings.R;
|
||||
|
||||
public class GameOverlayTileService extends TileService {
|
||||
private GameOverlay mOverlay;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mOverlay = GameOverlay.getInstance(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
super.onStartListening();
|
||||
boolean enabled = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getBoolean("game_overlay_enable", false);
|
||||
updateTileState(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
super.onClick();
|
||||
boolean currentlyEnabled = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.getBoolean("game_overlay_enable", false);
|
||||
boolean newState = !currentlyEnabled;
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.edit()
|
||||
.putBoolean("game_overlay_enable", newState)
|
||||
.commit();
|
||||
|
||||
updateTileState(newState);
|
||||
|
||||
if (newState) {
|
||||
mOverlay.show();
|
||||
} else {
|
||||
mOverlay.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_overlay_tile_label));
|
||||
tile.setContentDescription(getString(R.string.game_overlay_tile_description));
|
||||
tile.updateTile();
|
||||
}
|
||||
}
|
||||
|
|
@ -124,6 +124,12 @@ vendor/bin/hw/vendor.qti.hardware.capabilityconfigstore@1.0-service
|
|||
vendor/etc/init/vendor.qti.hardware.capabilityconfigstore@1.0-service.rc
|
||||
vendor/lib64/hw/vendor.qti.hardware.capabilityconfigstore@1.0-impl.so
|
||||
|
||||
# Diag HAL
|
||||
vendor/etc/vintf/manifest/vendor.qti.diag.hal.service.xml
|
||||
vendor/bin/diag-router
|
||||
vendor/etc/init/vendor.qti.diag.rc
|
||||
vendor/lib64/vendor.qti.diaghal@1.0.so;MODULE_SUFFIX=_vendor
|
||||
|
||||
# Display - from sunstone V816.0.8.0.UMQMIXM
|
||||
vendor/etc/display/DPU660.xml|b26dd73e361546d89bf3d7082a471703dc6ac2cb
|
||||
vendor/etc/display/DPU670.xml|e5131a60ceff29ca5eb561eec7eddadef1d0486f
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -146,3 +146,7 @@ firmware_directories /vendor/firmware_mnt/image/
|
|||
|
||||
# Battery
|
||||
/sys/class/qcom-battery reverse_chg_mode 0644 system system
|
||||
|
||||
# Torch control
|
||||
/sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm8350c@2:qcom,flash_led@ee00/leds/led:torch_1 brightness 0660 cameraserver camera
|
||||
/sys/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm8350c@2:qcom,flash_led@ee00/leds/led:switch_1 0660 cameraserver camera
|
||||
|
|
|
|||
1
sepolicy/vendor/cameraserver.te
vendored
Normal file
1
sepolicy/vendor/cameraserver.te
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
allow cameraserver sysfs_torch:file rw_file_perms;
|
||||
8
sepolicy/vendor/devicesettings_app.te
vendored
8
sepolicy/vendor/devicesettings_app.te
vendored
|
|
@ -4,3 +4,11 @@ allow devicesettings_app vendor_sysfs_graphics:file rw_file_perms;
|
|||
allow devicesettings_app vendor_sysfs_kgsl:dir search;
|
||||
|
||||
allow devicesettings_app vendor_sysfs_kgsl:{ file lnk_file } rw_file_perms;
|
||||
|
||||
allow devicesettings_app vendor_sysfs_battery_supply:dir search;
|
||||
allow devicesettings_app vendor_sysfs_battery_supply:file r_file_perms;
|
||||
|
||||
allow devicesettings_app proc_stat:file { read open getattr };
|
||||
|
||||
allow devicesettings_app vendor_sysfs_kgsl_gpuclk:file { read open getattr };
|
||||
allow devicesettings_app vendor_sysfs_kgsl:file { read open getattr };
|
||||
|
|
|
|||
8
sepolicy/vendor/file_contexts
vendored
8
sepolicy/vendor/file_contexts
vendored
|
|
@ -62,3 +62,11 @@
|
|||
/data/vendor/mac_addr(/.*)? u:object_r:vendor_wifi_vendor_data_file:s0
|
||||
/data/vendor/wlan_logs(/.*)? u:object_r:vendor_wifi_vendor_data_file:s0
|
||||
/vendor/bin/nv_mac u:object_r:vendor_wcnss_service_exec:s0
|
||||
|
||||
# Process and system statistics files
|
||||
/proc/stat u:object_r:proc_stat:s0
|
||||
/sys/class/kgsl/kgsl-3d0/gpu_busy_percentage u:object_r:vendor_sysfs_kgsl:s0
|
||||
/sys/class/kgsl/kgsl-3d0/temp u:object_r:vendor_sysfs_kgsl:s0
|
||||
/sys/class/kgsl/kgsl-3d0/gpuclk u:object_r:vendor_sysfs_kgsl_gpuclk:s0
|
||||
/sys/class/power_supply/battery/ u:object_r:vendor_sysfs_battery_supply:s0
|
||||
/sys/class/graphics/fb0/measured_fps u:object_r:vendor_sysfs_graphics:s0
|
||||
|
|
|
|||
5
sepolicy/vendor/genfs_contexts
vendored
5
sepolicy/vendor/genfs_contexts
vendored
|
|
@ -13,6 +13,11 @@ genfscon sysfs /devices/platform/soc/soc:fingerprint_fpc
|
|||
# USB
|
||||
genfscon sysfs /devices/platform/soc/soc:qcom,pmic_glink/soc:qcom,pmic_glink:qcom,ucsi/typec u:object_r:vendor_sysfs_usb_c:s0
|
||||
|
||||
# Torch control
|
||||
genfscon sysfs /devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm8350c@2:qcom,flash_led@ee00/leds/led:torch_1/brightness u:object_r:sysfs_torch:s0
|
||||
genfscon sysfs /devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm8350c@2:qcom,flash_led@ee00/leds/led:torch_1/max_brightness u:object_r:sysfs_torch:s0
|
||||
genfscon sysfs /devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-02/c440000.qcom,spmi:qcom,pm8350c@2:qcom,flash_led@ee00/leds/led:switch_1/brightness u:object_r:sysfs_torch:s0
|
||||
|
||||
# Wakeup nodes
|
||||
genfscon sysfs /devices/platform/goodix_ts.0/wakeup u:object_r:sysfs_wakeup:s0
|
||||
genfscon sysfs /devices/platform/soc/17300000.qcom,lpass/subsys6/wakeup u:object_r:sysfs_wakeup:s0
|
||||
|
|
|
|||
2
sepolicy/vendor/hal_sensors_default.te
vendored
2
sepolicy/vendor/hal_sensors_default.te
vendored
|
|
@ -11,3 +11,5 @@ allow hal_sensors_default vendor_sysfs_udfps:file rw_file_perms;
|
|||
|
||||
hal_client_domain(hal_sensors_default, hal_audio)
|
||||
allow hal_sensors_default hal_audio_hwservice:hwservice_manager find;
|
||||
|
||||
allow hal_sensors_default vendor_diag_device:chr_file rw_file_perms;
|
||||
|
|
|
|||
7
sepolicy/vendor/system_app.te
vendored
7
sepolicy/vendor/system_app.te
vendored
|
|
@ -8,3 +8,10 @@ allow system_app vendor_sysfs_graphics:file { getattr open write };
|
|||
# HTSR
|
||||
allow system_app sysfs_htsr:file { read write open setattr getattr };
|
||||
allow system_app sysfs_htsr:dir { search open read };
|
||||
|
||||
#GameBar
|
||||
allow system_app vendor_sysfs_graphics:file r_file_perms;
|
||||
allow system_app vendor_sysfs_battery_supply:dir search;
|
||||
allow system_app proc_stat:file r_file_perms;
|
||||
allow system_app vendor_sysfs_kgsl:file r_file_perms;
|
||||
allow system_app vendor_sysfs_kgsl_gpuclk:file r_file_perms;
|
||||
|
|
|
|||
1
sepolicy/vendor/torch.te
vendored
Normal file
1
sepolicy/vendor/torch.te
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
type sysfs_torch, fs_type, sysfs_type;
|
||||
1
sepolicy/vendor/untrusted_app.te
vendored
Normal file
1
sepolicy/vendor/untrusted_app.te
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
allow untrusted_app vendor_diag_device:chr_file rw_file_perms;
|
||||
1
sepolicy/vendor/vendor_dpmd.te
vendored
Normal file
1
sepolicy/vendor/vendor_dpmd.te
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
hal_client_domain(vendor_dpmd, vendor_hal_diaghal);
|
||||
|
|
@ -4,6 +4,9 @@ vendor.bluetooth.soc=hastings
|
|||
# CNE
|
||||
persist.vendor.cne.feature=1
|
||||
|
||||
# Camera
|
||||
vendor.camera.aux.packagelist=org.lineageos.aperture,com.android.camera,com.google.camera,com.snapchat.android
|
||||
|
||||
# Disable Skia tracing by default
|
||||
debug.hwui.skia_atrace_enabled=false
|
||||
|
||||
|
|
@ -62,6 +65,11 @@ ro.vendor.qti.sys.fw.bservice_enable=true
|
|||
DEVICE_PROVISIONED=1
|
||||
ril.subscription.types=NV,RUIM
|
||||
|
||||
# Radio VoNR Calling
|
||||
persist.radio.is_vonr_enabled_0=true
|
||||
persist.radio.is_vonr_enabled_1=true
|
||||
persist.vendor.vonr_setting_support=1
|
||||
|
||||
# Sensors
|
||||
persist.vendor.sensors.enable.mag_filter=true
|
||||
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ ro.incremental.enable=yes
|
|||
vendor.sys.thermal.data.path=/data/vendor/thermal/
|
||||
|
||||
# USB
|
||||
vendor.usb.diag.func.name=ffs
|
||||
vendor.usb.use_ffs_mtp=1
|
||||
|
||||
# Wifi
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue