temp2
Change-Id: Ia38ffba8ac4da1fbd3a51d34dc6a6bb60982567a
This commit is contained in:
@@ -19,7 +19,18 @@ android_app {
|
|||||||
"org.lineageos.platform.internal",
|
"org.lineageos.platform.internal",
|
||||||
],
|
],
|
||||||
|
|
||||||
|
required: [
|
||||||
|
"privapp-permissions-device_settings.xml",
|
||||||
|
],
|
||||||
|
|
||||||
optimize: {
|
optimize: {
|
||||||
proguard_flags_files: ["proguard.flags"],
|
proguard_flags_files: ["proguard.flags"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prebuilt_etc {
|
||||||
|
name: "privapp-permissions-device_settings.xml",
|
||||||
|
src: "privapp-permissions-device_settings.xml",
|
||||||
|
sub_dir: "permissions",
|
||||||
|
system_ext_specific: true,
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||||
<uses-permission android:name="lineageos.permission.HARDWARE_ABSTRACTION_ACCESS" />
|
<uses-permission android:name="lineageos.permission.HARDWARE_ABSTRACTION_ACCESS" />
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
|
||||||
|
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
|
||||||
|
|
||||||
<protected-broadcast android:name="org.lineageos.device.DeviceSettings.UPDATE_SLIDER_SETTINGS" />
|
<protected-broadcast android:name="org.lineageos.device.DeviceSettings.UPDATE_SLIDER_SETTINGS" />
|
||||||
<protected-broadcast android:name="org.lineageos.device.DeviceSettings.UPDATE_SLIDER_POSITION" />
|
<protected-broadcast android:name="org.lineageos.device.DeviceSettings.UPDATE_SLIDER_POSITION" />
|
||||||
@@ -35,13 +38,23 @@
|
|||||||
android:label="@string/device_title"
|
android:label="@string/device_title"
|
||||||
android:defaultToDeviceProtectedStorage="true"
|
android:defaultToDeviceProtectedStorage="true"
|
||||||
android:directBootAware="true"
|
android:directBootAware="true"
|
||||||
android:theme="@style/Theme.SubSettingsBase.Expressive"
|
android:theme="@style/Theme.DeviceSettings"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
|
|
||||||
|
<receiver android:name=".BootCompletedReceiver"
|
||||||
|
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>
|
||||||
|
|
||||||
<!-- Device Settings -->
|
<!-- Device Settings -->
|
||||||
<activity
|
<activity
|
||||||
android:name=".DeviceSettingsActivity"
|
android:name=".DeviceSettingsActivity"
|
||||||
android:label="@string/device_title"
|
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="com.android.settings.action.EXTRA_SETTINGS" />
|
<action android:name="com.android.settings.action.EXTRA_SETTINGS" />
|
||||||
@@ -88,5 +101,74 @@
|
|||||||
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
|
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
|
<!-- BypassCharging activity -->
|
||||||
|
<activity android:name=".bypasschrg.BypassChargingActivity"
|
||||||
|
android:label="@string/bypass_charging_title"
|
||||||
|
android:exported="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="com.android.settings.summary"
|
||||||
|
android:resource="@string/bypass_charging_summary" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<!-- BypassChargingTile service -->
|
||||||
|
<service
|
||||||
|
android:name=".bypasschrg.BypassChargingTile"
|
||||||
|
android:label="@string/bypass_charging_title"
|
||||||
|
android:icon="@drawable/ic_bypass_charging"
|
||||||
|
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>
|
||||||
|
|
||||||
|
<!-- TileHandler activity -->
|
||||||
|
<activity
|
||||||
|
android:name=".TileHandlerActivity"
|
||||||
|
android:exported="true"
|
||||||
|
android:noHistory="true"
|
||||||
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<!-- GameBar Overlay -->
|
||||||
|
<activity
|
||||||
|
android:name=".gamebar.GameBarSettingsActivity"
|
||||||
|
android:label="@string/game_bar_title"
|
||||||
|
android:exported="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="com.android.settings.summary"
|
||||||
|
android:resource="@string/game_bar_summary" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<!-- GameBar AppSelector -->
|
||||||
|
<activity android:name=".gamebar.GameBarAppSelectorActivity" />
|
||||||
|
<activity android:name=".gamebar.GameBarAppRemoverActivity" />
|
||||||
|
|
||||||
|
<!-- GameBar Overlay Tile Service -->
|
||||||
|
<service
|
||||||
|
android:name=".gamebar.GameBarTileService"
|
||||||
|
android:label="@string/game_bar_tile_label"
|
||||||
|
android:icon="@drawable/ic_game_bar"
|
||||||
|
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.service.quicksettings.action.QS_TILE" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.service.quicksettings.TOGGLEABLE_TILE"
|
||||||
|
android:value="true" />
|
||||||
|
</service>
|
||||||
|
|
||||||
|
<!-- GameBar Overlay Monitor Service -->
|
||||||
|
<service
|
||||||
|
android:name=".gamebar.GameBarMonitorService"
|
||||||
|
android:exported="false" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
21
DeviceSettings/privapp-permissions-device_settings.xml
Normal file
21
DeviceSettings/privapp-permissions-device_settings.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2017-2019 The LineageOS Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<permissions>
|
||||||
|
<privapp-permissions package="org.lineageos.device.DeviceSettings">
|
||||||
|
<permission name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||||
|
</privapp-permissions>
|
||||||
|
</permissions>
|
||||||
6
DeviceSettings/res/drawable/banner_fade_gradient.xml
Normal file
6
DeviceSettings/res/drawable/banner_fade_gradient.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:startColor="@android:color/transparent"
|
||||||
|
android:endColor="#CC000000"
|
||||||
|
android:angle="270"/>
|
||||||
|
</shape>
|
||||||
27
DeviceSettings/res/drawable/ic_bypass_charging.xml
Normal file
27
DeviceSettings/res/drawable/ic_bypass_charging.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (C) 2024 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?android:attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M8,6C8.552,6 9,6.448 9,7C9,7.552 8.552,8 8,8L4,8L4,16L7,16C7.552,16 8,16.448 8,17C8,17.552 7.552,18 7,18L4,18C2.895,18 2,17.105 2,16L2,8C2,6.895 2.895,6 4,6L8,6ZM18,6C19.105,6 20,6.895 20,8L20,9C21.105,9 22,9.895 22,11L22,13C22,14.105 21.105,15 20,15L20,16C20,17.105 19.105,18 18,18L14,18C13.448,18 13,17.552 13,17C13,16.448 13.448,16 14,16L18,16L18,8L15,8C14.448,8 14,7.552 14,7C14,6.448 14.448,6 15,6L18,6ZM12.514,6.143C12.988,6.427 13.142,7.041 12.858,7.515L10.766,11L12.982,11C13.767,11 14.252,11.856 13.848,12.53L10.858,17.514C10.573,17.988 9.959,18.142 9.486,17.858C9.012,17.573 8.858,16.959 9.143,16.486L11.234,13L9.018,13C8.233,13 7.748,12.144 8.152,11.47L11.142,6.486C11.427,6.012 12.041,5.858 12.514,6.143Z" />
|
||||||
|
|
||||||
|
</vector>
|
||||||
11
DeviceSettings/res/drawable/ic_game_bar.xml
Normal file
11
DeviceSettings/res/drawable/ic_game_bar.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>
|
||||||
BIN
DeviceSettings/res/drawable/oplus_banner.png
Normal file
BIN
DeviceSettings/res/drawable/oplus_banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 365 KiB |
12
DeviceSettings/res/layout/activity_bypass_charging.xml
Normal file
12
DeviceSettings/res/layout/activity_bypass_charging.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/bypass_charging_fragment"
|
||||||
|
android:name="org.lineageos.device.DeviceSettings.bypasschrg.BypassChargingFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
12
DeviceSettings/res/layout/activity_game_bar.xml
Normal file
12
DeviceSettings/res/layout/activity_game_bar.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/game_bar_fragment"
|
||||||
|
android:name="org.lineageos.device.DeviceSettings.gamebar.GameBarFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/content_frame"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
22
DeviceSettings/res/layout/banner_collapsing_toolbar.xml
Normal file
22
DeviceSettings/res/layout/banner_collapsing_toolbar.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?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="240dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/bannerImage"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@drawable/oplus_banner" />
|
||||||
|
|
||||||
|
<!-- Fade overlay at the bottom -->
|
||||||
|
<View
|
||||||
|
android:id="@+id/bannerFadeOverlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="80dp"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="@drawable/banner_fade_gradient"/>
|
||||||
|
</FrameLayout>
|
||||||
48
DeviceSettings/res/layout/device_settings_activity.xml
Normal file
48
DeviceSettings/res/layout/device_settings_activity.xml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".DeviceSettingsActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_width="match_parent">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||||
|
android:id="@+id/collapsing_toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="240dp"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||||
|
app:contentScrim="@android:color/transparent"
|
||||||
|
app:toolbarId="@id/action_bar">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/header"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:src="@drawable/oplus_banner"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
app:layout_collapseMode="parallax" />
|
||||||
|
|
||||||
|
<Toolbar
|
||||||
|
android:id="@+id/my_toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorPrimary"
|
||||||
|
android:elevation="4dp" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/content_frame"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="72dp"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
10
DeviceSettings/res/layout/game_bar.xml
Normal file
10
DeviceSettings/res/layout/game_bar.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/game_bar_root"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="#80000000"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
</LinearLayout>
|
||||||
6
DeviceSettings/res/layout/game_bar_app_selector.xml
Normal file
6
DeviceSettings/res/layout/game_bar_app_selector.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/app_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
34
DeviceSettings/res/layout/game_bar_app_selector_item.xml
Normal file
34
DeviceSettings/res/layout/game_bar_app_selector_item.xml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/app_item"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/app_icon"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginEnd="8dp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/app_package"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
-->
|
-->
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
|
||||||
<string name="device_title">Настройки OnePlus</string>
|
<string name="device_title">Aston Settings</string>
|
||||||
<string name="device_summary">Изменение особых настроек устройства OnePlus</string>
|
<string name="device_summary">Extra settings for OnePlus Ace3 | 12R</string>
|
||||||
|
|
||||||
<!-- Notification slider -->
|
<!-- Notification slider -->
|
||||||
<string name="notification_slider_category_title">Переключатель режима</string>
|
<string name="notification_slider_category_title">Переключатель режима</string>
|
||||||
@@ -69,4 +69,26 @@
|
|||||||
<string name="edge_touch_title">Снять ограничения касаний</string>
|
<string name="edge_touch_title">Снять ограничения касаний</string>
|
||||||
<string name="edge_touch_summary">Улучшение в играх нескольких касаний</string>
|
<string name="edge_touch_summary">Улучшение в играх нескольких касаний</string>
|
||||||
<string name="edge_touch_warning">Может увеличить вероятность случайного прикосновения</string>
|
<string name="edge_touch_warning">Может увеличить вероятность случайного прикосновения</string>
|
||||||
|
|
||||||
|
<!-- Gaming category -->
|
||||||
|
<string name="gaming_category_title">Gaming</string>
|
||||||
|
<string name="gaming_category_summary">Extra settings for gamers</string>
|
||||||
|
|
||||||
|
<!-- Bypass charging strings -->
|
||||||
|
<string name="bypass_charging_title">Bypass charging</string>
|
||||||
|
<string name="bypass_charging_summary">Supply power directly to the phone</string>
|
||||||
|
<string name="bypass_charging_info_title">Bypass charging supplies power directly to the board, instead of the battery, helping to reduce device heat, when running demanding applications like games.</string>
|
||||||
|
<string name="bypass_charging_unavailable">Bypass charging is not supported on this device</string>
|
||||||
|
<string name="bypass_charging_enabled">Enabled</string>
|
||||||
|
<string name="bypass_charging_disabled">Disabled</string>
|
||||||
|
<string name="bypass_charging_error">Coudn\'t enable Bypass Charging.</string>
|
||||||
|
|
||||||
|
<!-- GameBar Overlay -->
|
||||||
|
<string name="game_bar_title">GameBar</string>
|
||||||
|
<string name="game_bar_summary">Enable the system overlay (FPS, Temp, etc.)</string>
|
||||||
|
<string name="overlay_permission_required">Overlay permission is required</string>
|
||||||
|
<string name="overlay_permission_granted">Overlay permission granted</string>
|
||||||
|
<string name="overlay_permission_denied">Overlay permission denied</string>
|
||||||
|
<string name="game_bar_tile_label">GameBar</string>
|
||||||
|
<string name="game_bar_tile_description">Toggle the game overlay</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -111,4 +111,104 @@
|
|||||||
<item>64</item>
|
<item>64</item>
|
||||||
<item>63</item>
|
<item>63</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<!-- FPS Overlay -->
|
||||||
|
<string-array name="game_bar_fps_method_entries">
|
||||||
|
<item>New API (Default)</item>
|
||||||
|
<item>Legacy Sysfs</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="game_bar_fps_method_values">
|
||||||
|
<item>new</item>
|
||||||
|
<item>legacy</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Update Interval -->
|
||||||
|
<string-array name="fps_overlay_update_interval_entries">
|
||||||
|
<item>Every 500ms</item>
|
||||||
|
<item>Every second</item>
|
||||||
|
<item>Every 2 seconds</item>
|
||||||
|
<item>Every 5 seconds</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="fps_overlay_update_interval_values">
|
||||||
|
<item>500</item>
|
||||||
|
<item>1000</item>
|
||||||
|
<item>2000</item>
|
||||||
|
<item>5000</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Position -->
|
||||||
|
<string-array name="fps_overlay_position_entries">
|
||||||
|
<item>Top Left</item>
|
||||||
|
<item>Top Center</item>
|
||||||
|
<item>Top Right</item>
|
||||||
|
<item>Bottom Left</item>
|
||||||
|
<item>Bottom Center</item>
|
||||||
|
<item>Bottom Right</item>
|
||||||
|
<item>Custom Draggable</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="fps_overlay_position_values">
|
||||||
|
<item>top_left</item>
|
||||||
|
<item>top_center</item>
|
||||||
|
<item>top_right</item>
|
||||||
|
<item>bottom_left</item>
|
||||||
|
<item>bottom_center</item>
|
||||||
|
<item>bottom_right</item>
|
||||||
|
<item>draggable</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Overlay color -->
|
||||||
|
<string-array name="fps_overlay_color_entries">
|
||||||
|
<item>White</item>
|
||||||
|
<item>Crimson</item>
|
||||||
|
<item>Fruit Salad</item>
|
||||||
|
<item>Royal Blue</item>
|
||||||
|
<item>Amber</item>
|
||||||
|
<item>Teal</item>
|
||||||
|
<item>Electric Violet</item>
|
||||||
|
<item>Magenta</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="fps_overlay_color_values">
|
||||||
|
<item>#FFFFFF</item>
|
||||||
|
<item>#DC143C</item>
|
||||||
|
<item>#4CAF50</item>
|
||||||
|
<item>#4169E1</item>
|
||||||
|
<item>#FFBF00</item>
|
||||||
|
<item>#008080</item>
|
||||||
|
<item>#8A2BE2</item>
|
||||||
|
<item>#FF1493</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Overlay format -->
|
||||||
|
<string-array name="game_bar_format_entries">
|
||||||
|
<item>Full</item>
|
||||||
|
<item>Minimal</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="game_bar_format_values">
|
||||||
|
<item>full</item>
|
||||||
|
<item>minimal</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Split Mode -->
|
||||||
|
<string-array name="game_bar_split_mode_entries">
|
||||||
|
<item>Side-by-Side</item>
|
||||||
|
<item>Stacked</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="game_bar_split_mode_values">
|
||||||
|
<item>side_by_side</item>
|
||||||
|
<item>stacked</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Long press timeouts -->
|
||||||
|
<string-array name="game_bar_longpress_entries">
|
||||||
|
<item>1 second</item>
|
||||||
|
<item>3 seconds</item>
|
||||||
|
<item>5 seconds</item>
|
||||||
|
<item>10 seconds</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="game_bar_longpress_values">
|
||||||
|
<item>1000</item>
|
||||||
|
<item>3000</item>
|
||||||
|
<item>5000</item>
|
||||||
|
<item>10000</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
-->
|
-->
|
||||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||||
|
|
||||||
<string name="device_title">OnePlus Settings</string>
|
<string name="device_title">Aston Settings</string>
|
||||||
<string name="device_summary">Adjust OnePlus specific device settings</string>
|
<string name="device_summary">Extra settings for OnePlus Ace3 | 12R</string>
|
||||||
|
|
||||||
<!-- Notification slider -->
|
<!-- Notification slider -->
|
||||||
<string name="notification_slider_category_title">Alert slider</string>
|
<string name="notification_slider_category_title">Alert slider</string>
|
||||||
@@ -69,4 +69,26 @@
|
|||||||
<string name="edge_touch_title">Unlimit edge touch</string>
|
<string name="edge_touch_title">Unlimit edge touch</string>
|
||||||
<string name="edge_touch_summary">Improve your multi-touch experience in games</string>
|
<string name="edge_touch_summary">Improve your multi-touch experience in games</string>
|
||||||
<string name="edge_touch_warning">May increase the possibility of accidental touch</string>
|
<string name="edge_touch_warning">May increase the possibility of accidental touch</string>
|
||||||
|
|
||||||
|
<!-- Gaming category -->
|
||||||
|
<string name="gaming_category_title">Gaming</string>
|
||||||
|
<string name="gaming_category_summary">Extra settings for gamers</string>
|
||||||
|
|
||||||
|
<!-- Bypass charging strings -->
|
||||||
|
<string name="bypass_charging_title">Bypass charging</string>
|
||||||
|
<string name="bypass_charging_summary">Supply power directly to the phone</string>
|
||||||
|
<string name="bypass_charging_info_title">Bypass charging supplies power directly to the board, instead of the battery, helping to reduce device heat, when running demanding applications like games.</string>
|
||||||
|
<string name="bypass_charging_unavailable">Bypass charging is not supported on this device</string>
|
||||||
|
<string name="bypass_charging_enabled">Enabled</string>
|
||||||
|
<string name="bypass_charging_disabled">Disabled</string>
|
||||||
|
<string name="bypass_charging_error">Coudn\'t enable Bypass Charging.</string>
|
||||||
|
|
||||||
|
<!-- GameBar Overlay -->
|
||||||
|
<string name="game_bar_title">GameBar</string>
|
||||||
|
<string name="game_bar_summary">Enable the system overlay (FPS, Temp, etc.)</string>
|
||||||
|
<string name="overlay_permission_required">Overlay permission is required</string>
|
||||||
|
<string name="overlay_permission_granted">Overlay permission granted</string>
|
||||||
|
<string name="overlay_permission_denied">Overlay permission denied</string>
|
||||||
|
<string name="game_bar_tile_label">GameBar</string>
|
||||||
|
<string name="game_bar_tile_description">Toggle the game overlay</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
25
DeviceSettings/res/values/themes.xml
Normal file
25
DeviceSettings/res/values/themes.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2021 The Android Open Source Project
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<!-- Using in SubSettings page including injected settings page -->
|
||||||
|
<style name="Theme.DeviceSettings" parent="@style/Theme.SubSettingsBase.Expressive">
|
||||||
|
<!-- Suppress the built-in action bar -->
|
||||||
|
<item name="android:windowActionBar">false</item>
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
14
DeviceSettings/res/xml/bypass_charging_settings.xml
Normal file
14
DeviceSettings/res/xml/bypass_charging_settings.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="bypass_charging"
|
||||||
|
android:title="@string/bypass_charging_title"
|
||||||
|
android:icon="@drawable/ic_bypass_charging"
|
||||||
|
android:summary="@string/bypass_charging_summary"
|
||||||
|
android:persistent="false" />
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.FooterPreference
|
||||||
|
android:key="bypass_charging_info"
|
||||||
|
android:title="@string/bypass_charging_info_title"
|
||||||
|
android:selectable="false" />
|
||||||
|
</PreferenceScreen>
|
||||||
252
DeviceSettings/res/xml/game_bar_preferences.xml
Normal file
252
DeviceSettings/res/xml/game_bar_preferences.xml
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.MainSwitchPreference
|
||||||
|
android:key="game_bar_enable"
|
||||||
|
android:title="Enable GameBar Overlay"
|
||||||
|
android:summary="@string/game_bar_summary"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="Overlay Features"
|
||||||
|
android:dependency="game_bar_enable">
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_fps_enable"
|
||||||
|
android:title="FPS Overlay"
|
||||||
|
android:summary="Show current FPS on screen"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_temp_enable"
|
||||||
|
android:title="Device Temperature"
|
||||||
|
android:summary="Show device (battery) temperature"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_cpu_usage_enable"
|
||||||
|
android:title="CPU Usage"
|
||||||
|
android:summary="Show current CPU usage percentage"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_cpu_clock_enable"
|
||||||
|
android:title="CPU Clock Speeds"
|
||||||
|
android:summary="Show current CPU clock speeds for each core"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_cpu_temp_enable"
|
||||||
|
android:title="CPU Temperature"
|
||||||
|
android:summary="Show CPU temperature (thermal_zone0)"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_ram_enable"
|
||||||
|
android:title="RAM Usage"
|
||||||
|
android:summary="Show current RAM usage in MB"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_gpu_usage_enable"
|
||||||
|
android:title="GPU Usage"
|
||||||
|
android:summary="Show GPU usage percentage"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_gpu_clock_enable"
|
||||||
|
android:title="GPU Clock Speed"
|
||||||
|
android:summary="Show current GPU clock frequency"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_gpu_temp_enable"
|
||||||
|
android:title="GPU Temperature"
|
||||||
|
android:summary="Show current GPU temperature"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="FPS Measurement Method"
|
||||||
|
android:dependency="game_bar_fps_enable">
|
||||||
|
<ListPreference
|
||||||
|
android:key="game_bar_fps_method"
|
||||||
|
android:title="Select FPS Method"
|
||||||
|
android:summary="Choose between the New API method (default) and Legacy Sysfs"
|
||||||
|
android:defaultValue="new"
|
||||||
|
android:entries="@array/game_bar_fps_method_entries"
|
||||||
|
android:entryValues="@array/game_bar_fps_method_values" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="Customization"
|
||||||
|
android:dependency="game_bar_enable">
|
||||||
|
|
||||||
|
<SeekBarPreference
|
||||||
|
android:key="game_bar_text_size"
|
||||||
|
android:title="Text Size"
|
||||||
|
android:summary="Adjust the size of overlay text"
|
||||||
|
android:defaultValue="16"
|
||||||
|
android:max="32"
|
||||||
|
android:min="12" />
|
||||||
|
|
||||||
|
<SeekBarPreference
|
||||||
|
android:key="game_bar_background_alpha"
|
||||||
|
android:title="Background Transparency"
|
||||||
|
android:summary="Adjust the transparency of the background"
|
||||||
|
android:defaultValue="128"
|
||||||
|
android:max="255"
|
||||||
|
android:min="0" />
|
||||||
|
|
||||||
|
<SeekBarPreference
|
||||||
|
android:key="game_bar_corner_radius"
|
||||||
|
android:title="Overlay Corner Radius"
|
||||||
|
android:summary="Adjust how rounded the overlay corners should be"
|
||||||
|
android:defaultValue="16"
|
||||||
|
android:max="100"
|
||||||
|
android:min="0" />
|
||||||
|
|
||||||
|
<SeekBarPreference
|
||||||
|
android:key="game_bar_padding"
|
||||||
|
android:title="Overlay Padding"
|
||||||
|
android:summary="Adjust the space around the stats"
|
||||||
|
android:defaultValue="12"
|
||||||
|
android:max="64"
|
||||||
|
android:min="0" />
|
||||||
|
|
||||||
|
<SeekBarPreference
|
||||||
|
android:key="game_bar_item_spacing"
|
||||||
|
android:title="Item Spacing"
|
||||||
|
android:summary="Adjust spacing between overlay lines"
|
||||||
|
android:defaultValue="8"
|
||||||
|
android:max="50"
|
||||||
|
android:min="0" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="game_bar_update_interval"
|
||||||
|
android:title="Update Interval"
|
||||||
|
android:summary="Set how often the overlay values update"
|
||||||
|
android:defaultValue="1000"
|
||||||
|
android:entries="@array/fps_overlay_update_interval_entries"
|
||||||
|
android:entryValues="@array/fps_overlay_update_interval_values" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="game_bar_title_color"
|
||||||
|
android:title="Stat Title Color"
|
||||||
|
android:summary="Color for 'FPS', 'Temp', 'CPU', etc. text"
|
||||||
|
android:defaultValue="#FFFFFF"
|
||||||
|
android:entries="@array/fps_overlay_color_entries"
|
||||||
|
android:entryValues="@array/fps_overlay_color_values" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="game_bar_value_color"
|
||||||
|
android:title="Stat Value Color"
|
||||||
|
android:summary="Color for numeric stats (e.g., '29', '32.0°C')"
|
||||||
|
android:defaultValue="#4CAF50"
|
||||||
|
android:entries="@array/fps_overlay_color_entries"
|
||||||
|
android:entryValues="@array/fps_overlay_color_values" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="game_bar_position"
|
||||||
|
android:title="Overlay Position"
|
||||||
|
android:summary="Select the position of the overlay on screen"
|
||||||
|
android:defaultValue="top_left"
|
||||||
|
android:entries="@array/fps_overlay_position_entries"
|
||||||
|
android:entryValues="@array/fps_overlay_position_values" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="game_bar_format"
|
||||||
|
android:title="Overlay Format"
|
||||||
|
android:summary="Choose between Full or Minimal display"
|
||||||
|
android:defaultValue="full"
|
||||||
|
android:entries="@array/game_bar_format_entries"
|
||||||
|
android:entryValues="@array/game_bar_format_values" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="Split Config"
|
||||||
|
android:dependency="game_bar_enable">
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="game_bar_split_mode"
|
||||||
|
android:title="Split Mode"
|
||||||
|
android:summary="Choose Side-by-Side or Stacked arrangement"
|
||||||
|
android:defaultValue="stacked"
|
||||||
|
android:entries="@array/game_bar_split_mode_entries"
|
||||||
|
android:entryValues="@array/game_bar_split_mode_values" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="Overlay Gesture Controls"
|
||||||
|
android:dependency="game_bar_enable">
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_single_tap_toggle"
|
||||||
|
android:title="Enable Single Tap to Toggle"
|
||||||
|
android:summary="Tap once to switch between full and minimal overlay formats"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_doubletap_capture"
|
||||||
|
android:title="Enable Double Tap to Capture"
|
||||||
|
android:summary="Double-tap overlay to start/stop capture logs"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_longpress_enable"
|
||||||
|
android:title="Enable Long Press"
|
||||||
|
android:summary="Long-press overlay to access GameBar settings"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<ListPreference
|
||||||
|
android:key="game_bar_longpress_timeout"
|
||||||
|
android:title="Long Press Duration"
|
||||||
|
android:summary="Set the duration required to long-press the overlay"
|
||||||
|
android:defaultValue="1000"
|
||||||
|
android:entries="@array/game_bar_longpress_entries"
|
||||||
|
android:entryValues="@array/game_bar_longpress_values"
|
||||||
|
android:dependency="game_bar_longpress_enable" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="Capture Logs"
|
||||||
|
android:dependency="game_bar_enable">
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="game_bar_capture_start"
|
||||||
|
android:title="Start Logging"
|
||||||
|
android:summary="Begin capturing FPS and performance data in real-time" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="game_bar_capture_stop"
|
||||||
|
android:title="Stop Logging"
|
||||||
|
android:summary="Stop capturing FPS and performance data in real-time" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="game_bar_capture_export"
|
||||||
|
android:title="Export GameBar Log Data"
|
||||||
|
android:summary="Save the captured FPS and performance data as a CSV file" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:title="Auto Enable GameBar">
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:key="game_bar_auto_enable"
|
||||||
|
android:title="Auto-Enable GameBar for Selected Apps"
|
||||||
|
android:summary="If turned on, selected apps will auto-enable GameBar even if the main switch is off"
|
||||||
|
android:defaultValue="false" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="game_bar_app_selector"
|
||||||
|
android:title="Select Apps"
|
||||||
|
android:summary="Add apps that should auto-enable GameBar" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="game_bar_app_remover"
|
||||||
|
android:title="Remove Selected Apps"
|
||||||
|
android:summary="Remove apps from the auto-enable list" />
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
@@ -93,4 +93,22 @@
|
|||||||
android:title="@string/usb2_fc_title" />
|
android:title="@string/usb2_fc_title" />
|
||||||
</PreferenceCategory>-->
|
</PreferenceCategory>-->
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="gaming"
|
||||||
|
android:title="@string/gaming_category_title">
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="bypass_charging"
|
||||||
|
android:icon="@drawable/ic_bypass_charging"
|
||||||
|
android:title="@string/bypass_charging_title"
|
||||||
|
android:summary="@string/bypass_charging_summary"
|
||||||
|
android:fragment="org.lineageos.device.DeviceSettings.bypasschrg.BypassChargingFragment" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="game_bar"
|
||||||
|
android:icon="@drawable/ic_game_bar"
|
||||||
|
android:title="@string/game_bar_title"
|
||||||
|
android:summary="@string/game_bar_summary"
|
||||||
|
android:fragment="org.lineageos.device.DeviceSettings.gamebar.GameBarFragment" />
|
||||||
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The CyanogenMod Project
|
||||||
|
* 2017-2020 The LineageOS Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.gamebar.GameBar;
|
||||||
|
import org.lineageos.device.DeviceSettings.gamebar.GameBarMonitorService;
|
||||||
|
|
||||||
|
public class BootCompletedReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(final Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
|
||||||
|
restoreGameBarOverlayState(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreGameBarOverlayState(Context context) {
|
||||||
|
var prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
boolean mainEnabled = prefs.getBoolean("game_bar_enable", false);
|
||||||
|
boolean autoEnabled = prefs.getBoolean("game_bar_auto_enable", false);
|
||||||
|
if (mainEnabled) {
|
||||||
|
// Restore game bar preferences
|
||||||
|
GameBar.getInstance(context).applyPreferences();
|
||||||
|
GameBar.getInstance(context).show();
|
||||||
|
}
|
||||||
|
if (autoEnabled) {
|
||||||
|
// Start GameBarMonitorService
|
||||||
|
Intent monitorIntent = new Intent(context, GameBarMonitorService.class);
|
||||||
|
context.startService(monitorIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -384,14 +384,14 @@ public class DeviceSettings extends SettingsBasePreferenceFragment
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void restoreFastChargeSetting(Context context) {
|
// public static void restoreFastChargeSetting(Context context) {
|
||||||
if (Utils.fileWritable(FILE_FAST_CHARGE)) {
|
// if (Utils.fileWritable(FILE_FAST_CHARGE)) {
|
||||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
// SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
boolean value = sharedPrefs.getBoolean(KEY_USB2_SWITCH,
|
// boolean value = sharedPrefs.getBoolean(KEY_USB2_SWITCH,
|
||||||
Utils.getFileValueAsBoolean(FILE_FAST_CHARGE, false));
|
// Utils.getFileValueAsBoolean(FILE_FAST_CHARGE, false));
|
||||||
Utils.writeValue(FILE_FAST_CHARGE, value ? "1" : "0");
|
// Utils.writeValue(FILE_FAST_CHARGE, value ? "1" : "0");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private static int getDefaultResIdForUsage(String usage) {
|
private static int getDefaultResIdForUsage(String usage) {
|
||||||
switch (usage) {
|
switch (usage) {
|
||||||
|
|||||||
@@ -16,29 +16,51 @@
|
|||||||
|
|
||||||
package org.lineageos.device.DeviceSettings;
|
package org.lineageos.device.DeviceSettings;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.app.DialogFragment;
|
|
||||||
import android.app.Fragment;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Menu;
|
import android.view.View;
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import androidx.preference.PreferenceFragment;
|
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||||
|
|
||||||
|
import com.google.android.material.appbar.AppBarLayout;
|
||||||
|
import com.google.android.material.appbar.CollapsingToolbarLayout;
|
||||||
|
|
||||||
public class DeviceSettingsActivity extends CollapsingToolbarBaseActivity {
|
public class DeviceSettingsActivity extends CollapsingToolbarBaseActivity {
|
||||||
|
private View bannerFadeOverlay;
|
||||||
|
private boolean pinned = false; // Set true to pin the fade overlay
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
setTitle(" ");
|
||||||
|
|
||||||
|
// Load your fragment as usual
|
||||||
getSupportFragmentManager().beginTransaction().replace(
|
getSupportFragmentManager().beginTransaction().replace(
|
||||||
com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
R.id.content_frame,
|
||||||
new DeviceSettings()).commit();
|
new DeviceSettings()).commit();
|
||||||
|
|
||||||
|
// Inject banner dynamically into CollapsingToolbarLayout
|
||||||
|
CollapsingToolbarLayout collapsingToolbar =
|
||||||
|
findViewById(R.id.collapsing_toolbar);
|
||||||
|
if (collapsingToolbar != null) {
|
||||||
|
View banner = getLayoutInflater().inflate(R.layout.banner_collapsing_toolbar, collapsingToolbar, false);
|
||||||
|
|
||||||
|
// You may want to insert at position 0 to ensure it's on top
|
||||||
|
collapsingToolbar.addView(banner, 0);
|
||||||
|
|
||||||
|
bannerFadeOverlay = banner.findViewById(R.id.bannerFadeOverlay);
|
||||||
|
|
||||||
|
// Animate fade overlay on scroll
|
||||||
|
AppBarLayout appBar = findViewById(R.id.app_bar);
|
||||||
|
if (appBar != null) {
|
||||||
|
appBar.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> {
|
||||||
|
if (bannerFadeOverlay == null) return;
|
||||||
|
int totalScrollRange = appBarLayout.getTotalScrollRange();
|
||||||
|
float offsetFraction = Math.abs(verticalOffset) / (float) totalScrollRange;
|
||||||
|
float maxAlpha = 0.8f;
|
||||||
|
float alpha = pinned ? maxAlpha : maxAlpha * (1 - offsetFraction);
|
||||||
|
bannerFadeOverlay.setAlpha(alpha);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.device.DeviceSettings;
|
||||||
|
|
||||||
|
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.device.DeviceSettings.bypasschrg.BypassChargingActivity;
|
||||||
|
import org.lineageos.device.DeviceSettings.bypasschrg.BypassChargingTile;
|
||||||
|
import org.lineageos.device.DeviceSettings.gamebar.GameBarSettingsActivity;
|
||||||
|
import org.lineageos.device.DeviceSettings.gamebar.GameBarTileService;
|
||||||
|
|
||||||
|
public final class TileHandlerActivity extends Activity {
|
||||||
|
private static final String TAG = "TileHandlerActivity";
|
||||||
|
|
||||||
|
// Map QS Tile services to their corresponding activity
|
||||||
|
private static final Map<String, Class<?>> TILE_ACTIVITY_MAP = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
TILE_ACTIVITY_MAP.put(GameBarTileService.class.getName(), GameBarSettingsActivity.class);
|
||||||
|
TILE_ACTIVITY_MAP.put(BypassChargingTile.class.getName(), BypassChargingActivity.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,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 The LineageOS Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.bypasschrg;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
public class BypassChargingActivity extends CollapsingToolbarBaseActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_bypass_charging);
|
||||||
|
setTitle(getString(R.string.bypass_charging_title));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 The LineageOS Project
|
||||||
|
* Copyright (C) 2025 AlphaDroid
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.bypasschrg;
|
||||||
|
|
||||||
|
import static lineageos.health.HealthInterface.MODE_AUTO;
|
||||||
|
import static lineageos.health.HealthInterface.MODE_LIMIT;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.database.ContentObserver;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
import org.lineageos.device.DeviceSettings.utils.FileUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is implemented to coexist with Lineage Charging Control (CC).
|
||||||
|
* Bypass Charging will override (disable) CC, while it's enabled.
|
||||||
|
* CC status will be restored, when Bypass Charging is disabled.
|
||||||
|
* Any user changes to CC settings, while Bypass Charging is enabled,
|
||||||
|
* will override Bypass Charging settings.
|
||||||
|
*/
|
||||||
|
public class BypassChargingController {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
private static final String TAG = "BypassChargingController";
|
||||||
|
private static final String BYPASS_CHARGING_NODE = "/sys/class/oplus_chg/battery/mmi_charging_enable";
|
||||||
|
private static final String KEY_BYPASS_CHARGING_ENABLED = "bypass_charging_enabled";
|
||||||
|
|
||||||
|
// Bypass modes
|
||||||
|
private static final String BYPASS_CHARGING_ENABLED = "0";
|
||||||
|
private static final String BYPASS_CHARGING_DISABLED = "1";
|
||||||
|
|
||||||
|
private static final int CC_LIMIT_MIN = 10;
|
||||||
|
private static final int CC_LIMIT_MAX = 100;
|
||||||
|
private static final int CC_LIMIT_DEF = 80;
|
||||||
|
|
||||||
|
// Charging Control settings
|
||||||
|
private static final String KEY_CHARGING_CONTROL_ENABLED = "charging_control_enabled";
|
||||||
|
private static final String KEY_CHARGING_CONTROL_MODE = "charging_control_mode";
|
||||||
|
private static final String KEY_CHARGING_CONTROL_LIMIT = "charging_control_charging_limit";
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private ContentResolver mContentResolver;
|
||||||
|
|
||||||
|
private static BypassChargingController sInstance;
|
||||||
|
public static synchronized BypassChargingController getInstance(Context context) {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new BypassChargingController(context);
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BypassChargingController(Context context) {
|
||||||
|
mContext = context.getApplicationContext();
|
||||||
|
mContentResolver = mContext.getContentResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange, Uri uri) {
|
||||||
|
switch(uri.getLastPathSegment()) {
|
||||||
|
case KEY_CHARGING_CONTROL_ENABLED:
|
||||||
|
case KEY_CHARGING_CONTROL_MODE:
|
||||||
|
case KEY_CHARGING_CONTROL_LIMIT:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public boolean isBypassChargingSupported() {
|
||||||
|
return isNodeAccessible(BYPASS_CHARGING_NODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBypassChargingEnabled() {
|
||||||
|
try {
|
||||||
|
String value = FileUtils.readOneLine(BYPASS_CHARGING_NODE);
|
||||||
|
return value != null && BYPASS_CHARGING_ENABLED.equals(value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to read bypass sysnode", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNodeAccessible(String node) {
|
||||||
|
try {
|
||||||
|
String value = FileUtils.readOneLine(node);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Node " + node + " not accessible", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean writeToNode(String value) {
|
||||||
|
try {
|
||||||
|
FileUtils.writeLine(BYPASS_CHARGING_NODE, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Failed to write bypass sysnode", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBypassCharging(boolean enable) {
|
||||||
|
if (enable) {
|
||||||
|
enableBypassCharging();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
disableBypassCharging();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enableBypassCharging() {
|
||||||
|
setChargingControlEnabled(true);
|
||||||
|
setChargingControlMode(MODE_LIMIT);
|
||||||
|
setChargingControlLimit(CC_LIMIT_MIN);
|
||||||
|
writeToNode(BYPASS_CHARGING_ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void disableBypassCharging() {
|
||||||
|
writeToNode(BYPASS_CHARGING_DISABLED);
|
||||||
|
setChargingControlLimit(CC_LIMIT_DEF);
|
||||||
|
// setChargingControlMode(MODE_AUTO);
|
||||||
|
setChargingControlEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveBypassChargingEnabled(boolean enabled) {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||||
|
.edit()
|
||||||
|
.putBoolean(KEY_BYPASS_CHARGING_ENABLED, enabled)
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSavedBypassChargingEnabled() {
|
||||||
|
return PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||||
|
.getBoolean(KEY_BYPASS_CHARGING_ENABLED, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void backupChargingControlSettings() {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||||
|
.edit()
|
||||||
|
.putInt(KEY_CHARGING_CONTROL_MODE, getChargingControlMode())
|
||||||
|
.putInt(KEY_CHARGING_CONTROL_LIMIT, getChargingControlLimit())
|
||||||
|
.putBoolean(KEY_CHARGING_CONTROL_ENABLED, isChargingControlEnabled())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreChargingControlSettings() {
|
||||||
|
SharedPreferences sharedPreferences =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||||
|
setChargingControlMode(sharedPreferences.getInt(
|
||||||
|
KEY_CHARGING_CONTROL_LIMIT, CC_LIMIT_DEF));
|
||||||
|
setChargingControlMode(sharedPreferences.getInt(
|
||||||
|
KEY_CHARGING_CONTROL_MODE, MODE_AUTO));
|
||||||
|
setChargingControlEnabled(sharedPreferences.getBoolean(
|
||||||
|
KEY_CHARGING_CONTROL_ENABLED, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isChargingControlEnabled() {
|
||||||
|
return Settings.System.getInt(mContentResolver,
|
||||||
|
KEY_CHARGING_CONTROL_ENABLED, 0) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setChargingControlEnabled(boolean enabled) {
|
||||||
|
Settings.System.putInt(mContentResolver,
|
||||||
|
KEY_CHARGING_CONTROL_ENABLED, enabled ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getChargingControlMode() {
|
||||||
|
return Settings.System.getInt(mContentResolver,
|
||||||
|
KEY_CHARGING_CONTROL_MODE, MODE_AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setChargingControlMode(int mode) {
|
||||||
|
Settings.System.putInt(mContentResolver,
|
||||||
|
KEY_CHARGING_CONTROL_MODE, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getChargingControlLimit() {
|
||||||
|
return Settings.System.getInt(mContentResolver,
|
||||||
|
KEY_CHARGING_CONTROL_LIMIT, CC_LIMIT_DEF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setChargingControlLimit(int limit) {
|
||||||
|
if (limit < CC_LIMIT_MIN || limit > CC_LIMIT_MAX) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Settings.System.putInt(mContentResolver,
|
||||||
|
KEY_CHARGING_CONTROL_LIMIT, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showToast(int resId) {
|
||||||
|
Toast.makeText(mContext, mContext.getString(resId),
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 The LineageOS Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.bypasschrg;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
|
import androidx.preference.TwoStatePreference;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
public class BypassChargingFragment extends PreferenceFragmentCompat {
|
||||||
|
|
||||||
|
private static final String KEY_BYPASS_CHARGING = "bypass_charging";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
setPreferencesFromResource(R.xml.bypass_charging_settings, rootKey);
|
||||||
|
|
||||||
|
BypassChargingController bypassController =
|
||||||
|
BypassChargingController.getInstance(getContext());
|
||||||
|
boolean bypassSupported = bypassController.isBypassChargingSupported();
|
||||||
|
|
||||||
|
TwoStatePreference bypassPreference = findPreference(KEY_BYPASS_CHARGING);
|
||||||
|
bypassPreference.setEnabled(bypassSupported);
|
||||||
|
if (bypassSupported) {
|
||||||
|
bypassPreference.setChecked(bypassController.isBypassChargingEnabled());
|
||||||
|
bypassPreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
bypassController.setBypassCharging((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
bypassPreference.setSummary(R.string.bypass_charging_unavailable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.device.DeviceSettings.bypasschrg;
|
||||||
|
|
||||||
|
import android.service.quicksettings.Tile;
|
||||||
|
import android.service.quicksettings.TileService;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
public class BypassChargingTile extends TileService {
|
||||||
|
|
||||||
|
|
||||||
|
private BypassChargingController mBypassController;
|
||||||
|
private boolean mEnabled;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
mBypassController = BypassChargingController.getInstance(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartListening() {
|
||||||
|
mEnabled = mBypassController.isBypassChargingEnabled();
|
||||||
|
updateTileState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick() {
|
||||||
|
if (mEnabled == mBypassController.isBypassChargingEnabled()) {
|
||||||
|
mEnabled = !mEnabled;
|
||||||
|
updateTileState();
|
||||||
|
mBypassController.setBypassCharging(mEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTileState() {
|
||||||
|
Tile tile = getQsTile();
|
||||||
|
if (tile == null) return;
|
||||||
|
|
||||||
|
tile.setState(mEnabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||||
|
tile.setLabel(getString(R.string.bypass_charging_title));
|
||||||
|
tile.setContentDescription(getString(R.string.bypass_charging_summary));
|
||||||
|
tile.updateTile();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ForegroundAppDetector {
|
||||||
|
|
||||||
|
private static final String TAG = "ForegroundAppDetector";
|
||||||
|
|
||||||
|
public static String getForegroundPackageName(Context context) {
|
||||||
|
|
||||||
|
String pkg = tryGetRunningTasks(context);
|
||||||
|
if (pkg != null) {
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
pkg = tryReflectActivityTaskManager();
|
||||||
|
if (pkg != null) {
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String tryGetRunningTasks(Context context) {
|
||||||
|
try {
|
||||||
|
if (context.checkSelfPermission("android.permission.GET_TASKS")
|
||||||
|
== PackageManager.PERMISSION_GRANTED) {
|
||||||
|
|
||||||
|
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
|
||||||
|
if (tasks != null && !tasks.isEmpty()) {
|
||||||
|
ActivityManager.RunningTaskInfo top = tasks.get(0);
|
||||||
|
if (top.topActivity != null) {
|
||||||
|
return top.topActivity.getPackageName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "GET_TASKS permission not granted to this system app?");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "tryGetRunningTasks error: ", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String tryReflectActivityTaskManager() {
|
||||||
|
try {
|
||||||
|
Class<?> atmClass = Class.forName("android.app.ActivityTaskManager");
|
||||||
|
Method getServiceMethod = atmClass.getDeclaredMethod("getService");
|
||||||
|
getServiceMethod.setAccessible(true);
|
||||||
|
Object atmService = getServiceMethod.invoke(null);
|
||||||
|
Method getTasksMethod = atmService.getClass().getMethod("getTasks", int.class);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<?> taskList = (List<?>) getTasksMethod.invoke(atmService, 1);
|
||||||
|
if (taskList != null && !taskList.isEmpty()) {
|
||||||
|
|
||||||
|
Object firstTask = taskList.get(0);
|
||||||
|
|
||||||
|
Class<?> rtiClass = firstTask.getClass();
|
||||||
|
Method getTopActivityMethod = rtiClass.getDeclaredMethod("getTopActivity");
|
||||||
|
Object compName = getTopActivityMethod.invoke(firstTask);
|
||||||
|
if (compName != null) {
|
||||||
|
|
||||||
|
Method getPackageNameMethod = compName.getClass().getMethod("getPackageName");
|
||||||
|
String pkgName = (String) getPackageNameMethod.invoke(compName);
|
||||||
|
return pkgName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "tryReflectActivityTaskManager error: ", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,774 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.app.usage.UsageStatsManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.graphics.drawable.GradientDrawable;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class GameBar {
|
||||||
|
|
||||||
|
private static GameBar sInstance;
|
||||||
|
public static synchronized GameBar getInstance(Context context) {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new GameBar(context.getApplicationContext());
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String FPS_PATH = "/sys/class/drm/sde-crtc-0/measured_fps";
|
||||||
|
private static final String BATTERY_TEMP_PATH = "/sys/class/power_supply/battery/temp";
|
||||||
|
|
||||||
|
private static final String PREF_KEY_X = "game_bar_x";
|
||||||
|
private static final String PREF_KEY_Y = "game_bar_y";
|
||||||
|
|
||||||
|
private final Context mContext;
|
||||||
|
private final WindowManager mWindowManager;
|
||||||
|
private final Handler mHandler;
|
||||||
|
|
||||||
|
private View mOverlayView;
|
||||||
|
private LinearLayout mRootLayout;
|
||||||
|
private WindowManager.LayoutParams mLayoutParams;
|
||||||
|
private boolean mIsShowing = false;
|
||||||
|
|
||||||
|
private int mTextSizeSp = 16;
|
||||||
|
private int mBackgroundAlpha = 128;
|
||||||
|
private int mCornerRadius = 16;
|
||||||
|
private int mPaddingDp = 12;
|
||||||
|
private String mTitleColorHex = "#FFFFFF";
|
||||||
|
private String mValueColorHex = "#FFFFFF";
|
||||||
|
private String mOverlayFormat = "full";
|
||||||
|
private String mPosition = "top_left";
|
||||||
|
private String mSplitMode = "stacked";
|
||||||
|
private int mUpdateIntervalMs = 1000;
|
||||||
|
private boolean mDraggable = false;
|
||||||
|
|
||||||
|
private boolean mShowBatteryTemp = false;
|
||||||
|
private boolean mShowCpuUsage = false;
|
||||||
|
private boolean mShowCpuClock = false;
|
||||||
|
private boolean mShowCpuTemp = false;
|
||||||
|
private boolean mShowRam = false;
|
||||||
|
private boolean mShowFps = false;
|
||||||
|
|
||||||
|
private boolean mShowGpuUsage = false;
|
||||||
|
private boolean mShowGpuClock = false;
|
||||||
|
private boolean mShowGpuTemp = false;
|
||||||
|
|
||||||
|
private boolean mLongPressEnabled = false;
|
||||||
|
private long mLongPressThresholdMs = 1000;
|
||||||
|
private boolean mPressActive = false;
|
||||||
|
private float mDownX, mDownY;
|
||||||
|
private static final float TOUCH_SLOP = 20f;
|
||||||
|
|
||||||
|
private GestureDetector mGestureDetector;
|
||||||
|
private boolean mDoubleTapCaptureEnabled = false;
|
||||||
|
private boolean mSingleTapToggleEnabled = false;
|
||||||
|
private GradientDrawable mBgDrawable;
|
||||||
|
|
||||||
|
private int mItemSpacingDp = 8;
|
||||||
|
|
||||||
|
private final Runnable mLongPressRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mPressActive) {
|
||||||
|
openOverlaySettings();
|
||||||
|
mPressActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final Runnable mUpdateRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mIsShowing) {
|
||||||
|
updateStats();
|
||||||
|
mHandler.postDelayed(this, mUpdateIntervalMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private GameBar(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
mHandler = new Handler(Looper.getMainLooper());
|
||||||
|
|
||||||
|
mBgDrawable = new GradientDrawable();
|
||||||
|
applyBackgroundStyle();
|
||||||
|
|
||||||
|
mGestureDetector = new GestureDetector(mContext, new GestureDetector.SimpleOnGestureListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onDoubleTap(MotionEvent e) {
|
||||||
|
if (mDoubleTapCaptureEnabled) {
|
||||||
|
if (GameDataExport.getInstance().isCapturing()) {
|
||||||
|
GameDataExport.getInstance().stopCapture();
|
||||||
|
Toast.makeText(mContext, "Capture Stopped", Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
GameDataExport.getInstance().startCapture();
|
||||||
|
Toast.makeText(mContext, "Capture Started", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onDoubleTap(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||||
|
if (mSingleTapToggleEnabled) {
|
||||||
|
mOverlayFormat = "full".equals(mOverlayFormat) ? "minimal" : "full";
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||||
|
.edit()
|
||||||
|
.putString("game_bar_format", mOverlayFormat)
|
||||||
|
.apply();
|
||||||
|
Toast.makeText(mContext, "Overlay Format: " + mOverlayFormat, Toast.LENGTH_SHORT).show();
|
||||||
|
updateStats();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.onSingleTapConfirmed(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyPreferences() {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||||
|
|
||||||
|
mShowFps = prefs.getBoolean("game_bar_fps_enable", false);
|
||||||
|
mShowBatteryTemp = prefs.getBoolean("game_bar_temp_enable", false);
|
||||||
|
mShowCpuUsage = prefs.getBoolean("game_bar_cpu_usage_enable", false);
|
||||||
|
mShowCpuClock = prefs.getBoolean("game_bar_cpu_clock_enable", false);
|
||||||
|
mShowCpuTemp = prefs.getBoolean("game_bar_cpu_temp_enable", false);
|
||||||
|
mShowRam = prefs.getBoolean("game_bar_ram_enable", false);
|
||||||
|
|
||||||
|
mShowGpuUsage = prefs.getBoolean("game_bar_gpu_usage_enable", false);
|
||||||
|
mShowGpuClock = prefs.getBoolean("game_bar_gpu_clock_enable", false);
|
||||||
|
mShowGpuTemp = prefs.getBoolean("game_bar_gpu_temp_enable", false);
|
||||||
|
|
||||||
|
mDoubleTapCaptureEnabled = prefs.getBoolean("game_bar_doubletap_capture", false);
|
||||||
|
mSingleTapToggleEnabled = prefs.getBoolean("game_bar_single_tap_toggle", false);
|
||||||
|
|
||||||
|
updateSplitMode(prefs.getString("game_bar_split_mode", "stacked"));
|
||||||
|
updateTextSize(prefs.getInt("game_bar_text_size", 16));
|
||||||
|
updateBackgroundAlpha(prefs.getInt("game_bar_background_alpha", 128));
|
||||||
|
updateCornerRadius(prefs.getInt("game_bar_corner_radius", 16));
|
||||||
|
updatePadding(prefs.getInt("game_bar_padding", 12));
|
||||||
|
updateTitleColor(prefs.getString("game_bar_title_color", "#FFFFFF"));
|
||||||
|
updateValueColor(prefs.getString("game_bar_value_color", "#4CAF50"));
|
||||||
|
updateOverlayFormat(prefs.getString("game_bar_format", "full"));
|
||||||
|
updateUpdateInterval(prefs.getString("game_bar_update_interval", "1000"));
|
||||||
|
updatePosition(prefs.getString("game_bar_position", "top_left"));
|
||||||
|
|
||||||
|
int spacing = prefs.getInt("game_bar_item_spacing", 8);
|
||||||
|
updateItemSpacing(spacing);
|
||||||
|
|
||||||
|
mLongPressEnabled = prefs.getBoolean("game_bar_longpress_enable", false);
|
||||||
|
String lpTimeoutStr = prefs.getString("game_bar_longpress_timeout", "1000");
|
||||||
|
try {
|
||||||
|
long lpt = Long.parseLong(lpTimeoutStr);
|
||||||
|
setLongPressThresholdMs(lpt);
|
||||||
|
} catch (NumberFormatException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show() {
|
||||||
|
if (mIsShowing) return;
|
||||||
|
|
||||||
|
applyPreferences();
|
||||||
|
|
||||||
|
mLayoutParams = new WindowManager.LayoutParams(
|
||||||
|
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||||
|
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||||
|
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
|
||||||
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
|
||||||
|
PixelFormat.TRANSLUCENT
|
||||||
|
);
|
||||||
|
|
||||||
|
if ("draggable".equals(mPosition)) {
|
||||||
|
mDraggable = true;
|
||||||
|
loadSavedPosition(mLayoutParams);
|
||||||
|
if (mLayoutParams.x == 0 && mLayoutParams.y == 0) {
|
||||||
|
mLayoutParams.gravity = Gravity.TOP | Gravity.START;
|
||||||
|
mLayoutParams.x = 0;
|
||||||
|
mLayoutParams.y = 100;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mDraggable = false;
|
||||||
|
applyPosition(mLayoutParams, mPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
mOverlayView = new LinearLayout(mContext);
|
||||||
|
mOverlayView.setLayoutParams(new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
));
|
||||||
|
mRootLayout = (LinearLayout) mOverlayView;
|
||||||
|
applySplitMode();
|
||||||
|
applyBackgroundStyle();
|
||||||
|
applyPadding();
|
||||||
|
|
||||||
|
mOverlayView.setOnTouchListener((v, event) -> {
|
||||||
|
if (mGestureDetector != null && mGestureDetector.onTouchEvent(event)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
switch (event.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
if (mDraggable) {
|
||||||
|
initialX = mLayoutParams.x;
|
||||||
|
initialY = mLayoutParams.y;
|
||||||
|
initialTouchX = event.getRawX();
|
||||||
|
initialTouchY = event.getRawY();
|
||||||
|
}
|
||||||
|
if (mLongPressEnabled) {
|
||||||
|
mPressActive = true;
|
||||||
|
mDownX = event.getRawX();
|
||||||
|
mDownY = event.getRawY();
|
||||||
|
mHandler.postDelayed(mLongPressRunnable, mLongPressThresholdMs);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
if (mLongPressEnabled && mPressActive) {
|
||||||
|
float dx = Math.abs(event.getRawX() - mDownX);
|
||||||
|
float dy = Math.abs(event.getRawY() - mDownY);
|
||||||
|
if (dx > TOUCH_SLOP || dy > TOUCH_SLOP) {
|
||||||
|
mPressActive = false;
|
||||||
|
mHandler.removeCallbacks(mLongPressRunnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mDraggable) {
|
||||||
|
int deltaX = (int) (event.getRawX() - initialTouchX);
|
||||||
|
int deltaY = (int) (event.getRawY() - initialTouchY);
|
||||||
|
mLayoutParams.x = initialX + deltaX;
|
||||||
|
mLayoutParams.y = initialY + deltaY;
|
||||||
|
mWindowManager.updateViewLayout(mOverlayView, mLayoutParams);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
if (mLongPressEnabled && mPressActive) {
|
||||||
|
mPressActive = false;
|
||||||
|
mHandler.removeCallbacks(mLongPressRunnable);
|
||||||
|
}
|
||||||
|
if (mDraggable) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||||
|
prefs.edit()
|
||||||
|
.putInt(PREF_KEY_X, mLayoutParams.x)
|
||||||
|
.putInt(PREF_KEY_Y, mLayoutParams.y)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
mWindowManager.addView(mOverlayView, mLayoutParams);
|
||||||
|
mIsShowing = true;
|
||||||
|
startUpdates();
|
||||||
|
|
||||||
|
// Start the FPS meter if using the new API method.
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
GameBarFpsMeter.getInstance(mContext).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int initialX, initialY;
|
||||||
|
private float initialTouchX, initialTouchY;
|
||||||
|
|
||||||
|
public void hide() {
|
||||||
|
if (!mIsShowing) return;
|
||||||
|
mHandler.removeCallbacksAndMessages(null);
|
||||||
|
if (mOverlayView != null) {
|
||||||
|
mWindowManager.removeView(mOverlayView);
|
||||||
|
mOverlayView = null;
|
||||||
|
}
|
||||||
|
mIsShowing = false;
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
GameBarFpsMeter.getInstance(mContext).stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateStats() {
|
||||||
|
if (!mIsShowing || mRootLayout == null) return;
|
||||||
|
|
||||||
|
mRootLayout.removeAllViews();
|
||||||
|
|
||||||
|
List<View> statViews = new ArrayList<>();
|
||||||
|
|
||||||
|
// 1) FPS
|
||||||
|
float fpsVal = GameBarFpsMeter.getInstance(mContext).getFps();
|
||||||
|
String fpsStr = fpsVal >= 0 ? String.format(Locale.getDefault(), "%.0f", fpsVal) : "N/A";
|
||||||
|
if (mShowFps) {
|
||||||
|
statViews.add(createStatLine("FPS", fpsStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Battery temp
|
||||||
|
String batteryTempStr = "N/A";
|
||||||
|
if (mShowBatteryTemp) {
|
||||||
|
String tmp = readLine(BATTERY_TEMP_PATH);
|
||||||
|
if (tmp != null && !tmp.isEmpty()) {
|
||||||
|
try {
|
||||||
|
int raw = Integer.parseInt(tmp.trim());
|
||||||
|
float c = raw / 10f;
|
||||||
|
batteryTempStr = String.format(Locale.getDefault(), "%.1f", c);
|
||||||
|
} catch (NumberFormatException ignored) {}
|
||||||
|
}
|
||||||
|
statViews.add(createStatLine("Temp", batteryTempStr + "°C"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) CPU usage
|
||||||
|
String cpuUsageStr = "N/A";
|
||||||
|
if (mShowCpuUsage) {
|
||||||
|
cpuUsageStr = GameBarCpuInfo.getCpuUsage();
|
||||||
|
String display = "N/A".equals(cpuUsageStr) ? "N/A" : cpuUsageStr + "%";
|
||||||
|
statViews.add(createStatLine("CPU", display));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) CPU freq
|
||||||
|
if (mShowCpuClock) {
|
||||||
|
List<String> freqs = GameBarCpuInfo.getCpuFrequencies();
|
||||||
|
if (!freqs.isEmpty()) {
|
||||||
|
statViews.add(buildCpuFreqView(freqs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5) CPU temp
|
||||||
|
String cpuTempStr = "N/A";
|
||||||
|
if (mShowCpuTemp) {
|
||||||
|
cpuTempStr = GameBarCpuInfo.getCpuTemp();
|
||||||
|
statViews.add(createStatLine("CPU Temp", "N/A".equals(cpuTempStr) ? "N/A" : cpuTempStr + "°C"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6) RAM usage
|
||||||
|
String ramStr = "N/A";
|
||||||
|
if (mShowRam) {
|
||||||
|
ramStr = GameBarMemInfo.getRamUsage();
|
||||||
|
statViews.add(createStatLine("RAM", "N/A".equals(ramStr) ? "N/A" : ramStr + " MB"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7) GPU usage
|
||||||
|
String gpuUsageStr = "N/A";
|
||||||
|
if (mShowGpuUsage) {
|
||||||
|
gpuUsageStr = GameBarGpuInfo.getGpuUsage();
|
||||||
|
statViews.add(createStatLine("GPU", "N/A".equals(gpuUsageStr) ? "N/A" : gpuUsageStr + "%"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8) GPU clock
|
||||||
|
String gpuClockStr = "N/A";
|
||||||
|
if (mShowGpuClock) {
|
||||||
|
gpuClockStr = GameBarGpuInfo.getGpuClock();
|
||||||
|
statViews.add(createStatLine("GPU Freq", "N/A".equals(gpuClockStr) ? "N/A" : gpuClockStr + "MHz"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9) GPU temp
|
||||||
|
String gpuTempStr = "N/A";
|
||||||
|
if (mShowGpuTemp) {
|
||||||
|
gpuTempStr = GameBarGpuInfo.getGpuTemp();
|
||||||
|
statViews.add(createStatLine("GPU Temp", "N/A".equals(gpuTempStr) ? "N/A" : gpuTempStr + "°C"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("side_by_side".equals(mSplitMode)) {
|
||||||
|
mRootLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
if ("minimal".equals(mOverlayFormat)) {
|
||||||
|
for (int i = 0; i < statViews.size(); i++) {
|
||||||
|
mRootLayout.addView(statViews.get(i));
|
||||||
|
if (i < statViews.size() - 1) {
|
||||||
|
mRootLayout.addView(createDotView());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (View view : statViews) {
|
||||||
|
mRootLayout.addView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mRootLayout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
for (View view : statViews) {
|
||||||
|
mRootLayout.addView(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GameDataExport.getInstance().isCapturing()) {
|
||||||
|
String dateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date());
|
||||||
|
String pkgName = ForegroundAppDetector.getForegroundPackageName(mContext);
|
||||||
|
|
||||||
|
GameDataExport.getInstance().addOverlayData(
|
||||||
|
dateTime,
|
||||||
|
pkgName,
|
||||||
|
fpsStr,
|
||||||
|
batteryTempStr,
|
||||||
|
cpuUsageStr,
|
||||||
|
cpuTempStr,
|
||||||
|
gpuUsageStr,
|
||||||
|
gpuClockStr,
|
||||||
|
gpuTempStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mLayoutParams != null) {
|
||||||
|
mWindowManager.updateViewLayout(mOverlayView, mLayoutParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private View buildCpuFreqView(List<String> freqs) {
|
||||||
|
LinearLayout freqContainer = new LinearLayout(mContext);
|
||||||
|
freqContainer.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
|
int spacingPx = dpToPx(mContext, mItemSpacingDp);
|
||||||
|
LinearLayout.LayoutParams outerLp = new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
outerLp.setMargins(spacingPx, spacingPx / 2, spacingPx, spacingPx / 2);
|
||||||
|
freqContainer.setLayoutParams(outerLp);
|
||||||
|
|
||||||
|
if ("full".equals(mOverlayFormat)) {
|
||||||
|
TextView labelTv = new TextView(mContext);
|
||||||
|
labelTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||||
|
try {
|
||||||
|
labelTv.setTextColor(Color.parseColor(mTitleColorHex));
|
||||||
|
} catch (Exception e) {
|
||||||
|
labelTv.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
labelTv.setText("CPU Freq ");
|
||||||
|
freqContainer.addView(labelTv);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearLayout verticalFreqs = new LinearLayout(mContext);
|
||||||
|
verticalFreqs.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
|
||||||
|
for (String freqLine : freqs) {
|
||||||
|
LinearLayout lineLayout = new LinearLayout(mContext);
|
||||||
|
lineLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
|
TextView freqTv = new TextView(mContext);
|
||||||
|
freqTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||||
|
try {
|
||||||
|
freqTv.setTextColor(Color.parseColor(mValueColorHex));
|
||||||
|
} catch (Exception e) {
|
||||||
|
freqTv.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
freqTv.setText(freqLine);
|
||||||
|
|
||||||
|
lineLayout.addView(freqTv);
|
||||||
|
|
||||||
|
LinearLayout.LayoutParams lineLp = new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
lineLp.setMargins(spacingPx, spacingPx / 4, spacingPx, spacingPx / 4);
|
||||||
|
lineLayout.setLayoutParams(lineLp);
|
||||||
|
|
||||||
|
verticalFreqs.addView(lineLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
freqContainer.addView(verticalFreqs);
|
||||||
|
return freqContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinearLayout createStatLine(String title, String rawValue) {
|
||||||
|
LinearLayout lineLayout = new LinearLayout(mContext);
|
||||||
|
lineLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
|
||||||
|
if ("full".equals(mOverlayFormat)) {
|
||||||
|
TextView tvTitle = new TextView(mContext);
|
||||||
|
tvTitle.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||||
|
try {
|
||||||
|
tvTitle.setTextColor(Color.parseColor(mTitleColorHex));
|
||||||
|
} catch (Exception e) {
|
||||||
|
tvTitle.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
tvTitle.setText(title.isEmpty() ? "" : title + " ");
|
||||||
|
|
||||||
|
TextView tvValue = new TextView(mContext);
|
||||||
|
tvValue.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||||
|
try {
|
||||||
|
tvValue.setTextColor(Color.parseColor(mValueColorHex));
|
||||||
|
} catch (Exception e) {
|
||||||
|
tvValue.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
tvValue.setText(rawValue);
|
||||||
|
|
||||||
|
lineLayout.addView(tvTitle);
|
||||||
|
lineLayout.addView(tvValue);
|
||||||
|
} else {
|
||||||
|
TextView tvMinimal = new TextView(mContext);
|
||||||
|
tvMinimal.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||||
|
try {
|
||||||
|
tvMinimal.setTextColor(Color.parseColor(mValueColorHex));
|
||||||
|
} catch (Exception e) {
|
||||||
|
tvMinimal.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
tvMinimal.setText(rawValue);
|
||||||
|
lineLayout.addView(tvMinimal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int spacingPx = dpToPx(mContext, mItemSpacingDp);
|
||||||
|
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
lp.setMargins(spacingPx, spacingPx / 2, spacingPx, spacingPx / 2);
|
||||||
|
lineLayout.setLayoutParams(lp);
|
||||||
|
|
||||||
|
return lineLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private View createDotView() {
|
||||||
|
TextView dotView = new TextView(mContext);
|
||||||
|
dotView.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSizeSp);
|
||||||
|
try {
|
||||||
|
dotView.setTextColor(Color.parseColor(mValueColorHex));
|
||||||
|
} catch (Exception e) {
|
||||||
|
dotView.setTextColor(Color.WHITE);
|
||||||
|
}
|
||||||
|
dotView.setText(" . ");
|
||||||
|
return dotView;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShowBatteryTemp(boolean show) { mShowBatteryTemp = show; }
|
||||||
|
public void setShowCpuUsage(boolean show) { mShowCpuUsage = show; }
|
||||||
|
public void setShowCpuClock(boolean show) { mShowCpuClock = show; }
|
||||||
|
public void setShowCpuTemp(boolean show) { mShowCpuTemp = show; }
|
||||||
|
public void setShowRam(boolean show) { mShowRam = show; }
|
||||||
|
public void setShowFps(boolean show) { mShowFps = show; }
|
||||||
|
|
||||||
|
public void setShowGpuUsage(boolean show) { mShowGpuUsage = show; }
|
||||||
|
public void setShowGpuClock(boolean show) { mShowGpuClock = show; }
|
||||||
|
public void setShowGpuTemp(boolean show) { mShowGpuTemp = show; }
|
||||||
|
|
||||||
|
public void updateTextSize(int sp) {
|
||||||
|
mTextSizeSp = sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateCornerRadius(int radius) {
|
||||||
|
mCornerRadius = radius;
|
||||||
|
applyBackgroundStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateBackgroundAlpha(int alpha) {
|
||||||
|
mBackgroundAlpha = alpha;
|
||||||
|
applyBackgroundStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePadding(int dp) {
|
||||||
|
mPaddingDp = dp;
|
||||||
|
applyPadding();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateTitleColor(String hex) {
|
||||||
|
mTitleColorHex = hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateValueColor(String hex) {
|
||||||
|
mValueColorHex = hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateOverlayFormat(String format) {
|
||||||
|
mOverlayFormat = format;
|
||||||
|
if (mIsShowing) {
|
||||||
|
updateStats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateItemSpacing(int dp) {
|
||||||
|
mItemSpacingDp = dp;
|
||||||
|
if (mIsShowing) {
|
||||||
|
updateStats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyBackgroundStyle() {
|
||||||
|
int color = Color.argb(mBackgroundAlpha, 0, 0, 0);
|
||||||
|
mBgDrawable.setColor(color);
|
||||||
|
mBgDrawable.setCornerRadius(mCornerRadius);
|
||||||
|
|
||||||
|
if (mOverlayView != null) {
|
||||||
|
mOverlayView.setBackground(mBgDrawable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyPadding() {
|
||||||
|
if (mRootLayout != null) {
|
||||||
|
int px = dpToPx(mContext, mPaddingDp);
|
||||||
|
mRootLayout.setPadding(px, px, px, px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePosition(String pos) {
|
||||||
|
mPosition = pos;
|
||||||
|
if (mIsShowing && mOverlayView != null && mLayoutParams != null) {
|
||||||
|
if ("draggable".equals(mPosition)) {
|
||||||
|
mDraggable = true;
|
||||||
|
loadSavedPosition(mLayoutParams);
|
||||||
|
if (mLayoutParams.x == 0 && mLayoutParams.y == 0) {
|
||||||
|
mLayoutParams.gravity = Gravity.TOP | Gravity.START;
|
||||||
|
mLayoutParams.x = 0;
|
||||||
|
mLayoutParams.y = 100;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mDraggable = false;
|
||||||
|
applyPosition(mLayoutParams, mPosition);
|
||||||
|
}
|
||||||
|
mWindowManager.updateViewLayout(mOverlayView, mLayoutParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateSplitMode(String mode) {
|
||||||
|
mSplitMode = mode;
|
||||||
|
if (mIsShowing && mOverlayView != null) {
|
||||||
|
applySplitMode();
|
||||||
|
updateStats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateUpdateInterval(String intervalStr) {
|
||||||
|
try {
|
||||||
|
mUpdateIntervalMs = Integer.parseInt(intervalStr);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
mUpdateIntervalMs = 1000;
|
||||||
|
}
|
||||||
|
if (mIsShowing) {
|
||||||
|
startUpdates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLongPressEnabled(boolean enabled) {
|
||||||
|
mLongPressEnabled = enabled;
|
||||||
|
}
|
||||||
|
public void setLongPressThresholdMs(long ms) {
|
||||||
|
mLongPressThresholdMs = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDoubleTapCaptureEnabled(boolean enabled) {
|
||||||
|
mDoubleTapCaptureEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSingleTapToggleEnabled(boolean enabled) {
|
||||||
|
mSingleTapToggleEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startUpdates() {
|
||||||
|
mHandler.removeCallbacksAndMessages(null);
|
||||||
|
mHandler.post(mUpdateRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applySplitMode() {
|
||||||
|
if (mRootLayout == null) return;
|
||||||
|
if ("side_by_side".equals(mSplitMode)) {
|
||||||
|
mRootLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
} else {
|
||||||
|
mRootLayout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSavedPosition(WindowManager.LayoutParams lp) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||||
|
int savedX = prefs.getInt(PREF_KEY_X, Integer.MIN_VALUE);
|
||||||
|
int savedY = prefs.getInt(PREF_KEY_Y, Integer.MIN_VALUE);
|
||||||
|
if (savedX != Integer.MIN_VALUE && savedY != Integer.MIN_VALUE) {
|
||||||
|
lp.gravity = Gravity.TOP | Gravity.START;
|
||||||
|
lp.x = savedX;
|
||||||
|
lp.y = savedY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyPosition(WindowManager.LayoutParams lp, String pos) {
|
||||||
|
switch (pos) {
|
||||||
|
case "top_left":
|
||||||
|
lp.gravity = Gravity.TOP | Gravity.START;
|
||||||
|
lp.x = 0;
|
||||||
|
lp.y = 100;
|
||||||
|
break;
|
||||||
|
case "top_center":
|
||||||
|
lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
|
||||||
|
lp.y = 100;
|
||||||
|
break;
|
||||||
|
case "top_right":
|
||||||
|
lp.gravity = Gravity.TOP | Gravity.END;
|
||||||
|
lp.x = 0;
|
||||||
|
lp.y = 100;
|
||||||
|
break;
|
||||||
|
case "bottom_left":
|
||||||
|
lp.gravity = Gravity.BOTTOM | Gravity.START;
|
||||||
|
lp.x = 0;
|
||||||
|
lp.y = 100;
|
||||||
|
break;
|
||||||
|
case "bottom_center":
|
||||||
|
lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
|
||||||
|
lp.y = 100;
|
||||||
|
break;
|
||||||
|
case "bottom_right":
|
||||||
|
lp.gravity = Gravity.BOTTOM | Gravity.END;
|
||||||
|
lp.x = 0;
|
||||||
|
lp.y = 100;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
lp.gravity = Gravity.TOP | Gravity.START;
|
||||||
|
lp.x = 0;
|
||||||
|
lp.y = 100;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readLine(String path) {
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
|
||||||
|
return br.readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openOverlaySettings() {
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent(mContext, GameBarSettingsActivity.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
mContext.startActivity(intent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Exception ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int dpToPx(Context context, int dp) {
|
||||||
|
float scale = context.getResources().getDisplayMetrics().density;
|
||||||
|
return Math.round(dp * scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
public class GameBarAppRemoverActivity extends CollapsingToolbarBaseActivity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_game_bar_app_selector);
|
||||||
|
setTitle("Remove Auto-Enable Apps");
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
getSupportFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.content_frame, new GameBarAppRemoverFragment())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class GameBarAppRemoverFragment extends Fragment {
|
||||||
|
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
private GameBarAutoAppsAdapter adapter;
|
||||||
|
private PackageManager packageManager;
|
||||||
|
private List<ApplicationInfo> autoAppsList;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.game_bar_app_selector, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
recyclerView = view.findViewById(R.id.app_list);
|
||||||
|
packageManager = getContext().getPackageManager();
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
loadAutoApps();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAutoApps() {
|
||||||
|
Set<String> autoAppsSet = getSavedAutoApps();
|
||||||
|
autoAppsList = new ArrayList<>();
|
||||||
|
for (String pkg : autoAppsSet) {
|
||||||
|
try {
|
||||||
|
ApplicationInfo info = packageManager.getApplicationInfo(pkg, 0);
|
||||||
|
autoAppsList.add(info);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
adapter = new GameBarAutoAppsAdapter(packageManager, autoAppsList, new GameBarAutoAppsAdapter.OnAppRemoveListener() {
|
||||||
|
@Override
|
||||||
|
public void onAppRemove(ApplicationInfo appInfo) {
|
||||||
|
removeAppFromAutoList(appInfo.packageName);
|
||||||
|
Toast.makeText(getContext(), appInfo.loadLabel(packageManager) + " removed.", Toast.LENGTH_SHORT).show();
|
||||||
|
autoAppsList.remove(appInfo);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getSavedAutoApps() {
|
||||||
|
return PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||||
|
.getStringSet(GameBarAppSelectorFragment.PREF_AUTO_APPS, new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeAppFromAutoList(String packageName) {
|
||||||
|
Set<String> autoApps = new HashSet<>(getSavedAutoApps());
|
||||||
|
autoApps.remove(packageName);
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||||
|
.edit().putStringSet(GameBarAppSelectorFragment.PREF_AUTO_APPS, autoApps).apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
public class GameBarAppSelectorActivity extends CollapsingToolbarBaseActivity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_game_bar_app_selector);
|
||||||
|
setTitle("Select Apps for GameBar");
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
getSupportFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.content_frame, new GameBarAppSelectorFragment())
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class GameBarAppSelectorFragment extends Fragment {
|
||||||
|
|
||||||
|
public static final String PREF_AUTO_APPS = "game_bar_auto_apps";
|
||||||
|
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
private GameBarAppsAdapter adapter;
|
||||||
|
private PackageManager packageManager;
|
||||||
|
private List<ApplicationInfo> allApps;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.game_bar_app_selector, container, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
recyclerView = view.findViewById(R.id.app_list);
|
||||||
|
packageManager = getContext().getPackageManager();
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
|
loadApps();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadApps() {
|
||||||
|
allApps = new ArrayList<>();
|
||||||
|
List<ApplicationInfo> installedApps = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
|
||||||
|
Set<String> autoApps = getSavedAutoApps();
|
||||||
|
for (ApplicationInfo appInfo : installedApps) {
|
||||||
|
if ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0 &&
|
||||||
|
!appInfo.packageName.equals(getContext().getPackageName()) &&
|
||||||
|
!autoApps.contains(appInfo.packageName)) {
|
||||||
|
allApps.add(appInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
adapter = new GameBarAppsAdapter(packageManager, allApps, new GameBarAppsAdapter.OnAppClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onAppClick(ApplicationInfo appInfo) {
|
||||||
|
addAppToAutoList(appInfo.packageName);
|
||||||
|
Toast.makeText(getContext(), appInfo.loadLabel(packageManager) + " added.", Toast.LENGTH_SHORT).show();
|
||||||
|
allApps.remove(appInfo);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<String> getSavedAutoApps() {
|
||||||
|
return PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||||
|
.getStringSet(PREF_AUTO_APPS, new HashSet<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAppToAutoList(String packageName) {
|
||||||
|
Set<String> autoApps = new HashSet<>(getSavedAutoApps());
|
||||||
|
autoApps.add(packageName);
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||||
|
.edit().putStringSet(PREF_AUTO_APPS, autoApps).apply();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GameBarAppsAdapter extends RecyclerView.Adapter<GameBarAppsAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
public interface OnAppClickListener {
|
||||||
|
void onAppClick(ApplicationInfo appInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackageManager packageManager;
|
||||||
|
private List<ApplicationInfo> apps;
|
||||||
|
private OnAppClickListener listener;
|
||||||
|
|
||||||
|
public GameBarAppsAdapter(PackageManager packageManager, List<ApplicationInfo> apps, OnAppClickListener listener) {
|
||||||
|
this.packageManager = packageManager;
|
||||||
|
this.apps = apps;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public GameBarAppsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.game_bar_app_selector_item, parent, false);
|
||||||
|
return new ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull GameBarAppsAdapter.ViewHolder holder, int position) {
|
||||||
|
final ApplicationInfo appInfo = apps.get(position);
|
||||||
|
holder.appName.setText(appInfo.loadLabel(packageManager));
|
||||||
|
holder.appPackage.setText(appInfo.packageName);
|
||||||
|
holder.appIcon.setImageDrawable(appInfo.loadIcon(packageManager));
|
||||||
|
holder.itemView.setOnClickListener(v -> {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onAppClick(appInfo);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return apps.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView appName;
|
||||||
|
TextView appPackage;
|
||||||
|
ImageView appIcon;
|
||||||
|
|
||||||
|
public ViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
appName = itemView.findViewById(R.id.app_name);
|
||||||
|
appPackage = itemView.findViewById(R.id.app_package);
|
||||||
|
appIcon = itemView.findViewById(R.id.app_icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GameBarAutoAppsAdapter extends RecyclerView.Adapter<GameBarAutoAppsAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
public interface OnAppRemoveListener {
|
||||||
|
void onAppRemove(ApplicationInfo appInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PackageManager packageManager;
|
||||||
|
private List<ApplicationInfo> apps;
|
||||||
|
private OnAppRemoveListener listener;
|
||||||
|
|
||||||
|
public GameBarAutoAppsAdapter(PackageManager packageManager, List<ApplicationInfo> apps, OnAppRemoveListener listener) {
|
||||||
|
this.packageManager = packageManager;
|
||||||
|
this.apps = apps;
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public GameBarAutoAppsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.game_bar_app_selector_item, parent, false);
|
||||||
|
return new ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull GameBarAutoAppsAdapter.ViewHolder holder, int position) {
|
||||||
|
final ApplicationInfo appInfo = apps.get(position);
|
||||||
|
holder.appName.setText(appInfo.loadLabel(packageManager));
|
||||||
|
holder.appPackage.setText(appInfo.packageName);
|
||||||
|
holder.appIcon.setImageDrawable(appInfo.loadIcon(packageManager));
|
||||||
|
holder.itemView.setOnClickListener(v -> {
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onAppRemove(appInfo);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return apps.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView appName;
|
||||||
|
TextView appPackage;
|
||||||
|
ImageView appIcon;
|
||||||
|
|
||||||
|
public ViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
appName = itemView.findViewById(R.id.app_name);
|
||||||
|
appPackage = itemView.findViewById(R.id.app_package);
|
||||||
|
appIcon = itemView.findViewById(R.id.app_icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
public class GameBarBootReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
String action = intent.getAction();
|
||||||
|
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|
||||||
|
|| Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(action)) {
|
||||||
|
restoreOverlayState(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreOverlayState(Context context) {
|
||||||
|
var prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
boolean mainEnabled = prefs.getBoolean("game_bar_enable", false);
|
||||||
|
boolean autoEnabled = prefs.getBoolean("game_bar_auto_enable", false);
|
||||||
|
if (mainEnabled) {
|
||||||
|
GameBar.getInstance(context).applyPreferences();
|
||||||
|
GameBar.getInstance(context).show();
|
||||||
|
}
|
||||||
|
if (autoEnabled) {
|
||||||
|
Intent monitorIntent = new Intent(context, GameBarMonitorService.class);
|
||||||
|
context.startService(monitorIntent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GameBarCpuInfo {
|
||||||
|
|
||||||
|
private static long sPrevIdle = -1;
|
||||||
|
private static long sPrevTotal = -1;
|
||||||
|
|
||||||
|
private static final String CPU_TEMP_PATH = "/sys/class/thermal/thermal_zone0/temp";
|
||||||
|
|
||||||
|
public static String getCpuUsage() {
|
||||||
|
String line = readLine("/proc/stat");
|
||||||
|
if (line == null || !line.startsWith("cpu ")) return "N/A";
|
||||||
|
String[] parts = line.split("\\s+");
|
||||||
|
if (parts.length < 8) return "N/A";
|
||||||
|
|
||||||
|
try {
|
||||||
|
long user = Long.parseLong(parts[1]);
|
||||||
|
long nice = Long.parseLong(parts[2]);
|
||||||
|
long system = Long.parseLong(parts[3]);
|
||||||
|
long idle = Long.parseLong(parts[4]);
|
||||||
|
long iowait = Long.parseLong(parts[5]);
|
||||||
|
long irq = Long.parseLong(parts[6]);
|
||||||
|
long softirq = Long.parseLong(parts[7]);
|
||||||
|
long steal = parts.length > 8 ? Long.parseLong(parts[8]) : 0;
|
||||||
|
|
||||||
|
long total = user + nice + system + idle + iowait + irq + softirq + steal;
|
||||||
|
|
||||||
|
if (sPrevTotal != -1 && total != sPrevTotal) {
|
||||||
|
long diffTotal = total - sPrevTotal;
|
||||||
|
long diffIdle = idle - sPrevIdle;
|
||||||
|
long usage = 100 * (diffTotal - diffIdle) / diffTotal;
|
||||||
|
sPrevTotal = total;
|
||||||
|
sPrevIdle = idle;
|
||||||
|
return String.valueOf(usage);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
sPrevTotal = total;
|
||||||
|
sPrevIdle = idle;
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<String> getCpuFrequencies() {
|
||||||
|
List<String> result = new ArrayList<>();
|
||||||
|
String cpuDirPath = "/sys/devices/system/cpu/";
|
||||||
|
java.io.File cpuDir = new java.io.File(cpuDirPath);
|
||||||
|
java.io.File[] files = cpuDir.listFiles((dir, name) -> name.matches("cpu\\d+"));
|
||||||
|
if (files == null || files.length == 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<java.io.File> cpuFolders = new ArrayList<>();
|
||||||
|
Collections.addAll(cpuFolders, files);
|
||||||
|
cpuFolders.sort(Comparator.comparingInt(GameBarCpuInfo::extractCpuNumber));
|
||||||
|
|
||||||
|
for (java.io.File cpu : cpuFolders) {
|
||||||
|
String freqPath = cpu.getAbsolutePath() + "/cpufreq/scaling_cur_freq";
|
||||||
|
String freqStr = readLine(freqPath);
|
||||||
|
if (freqStr != null && !freqStr.isEmpty()) {
|
||||||
|
try {
|
||||||
|
int khz = Integer.parseInt(freqStr.trim());
|
||||||
|
int mhz = khz / 1000;
|
||||||
|
result.add(cpu.getName() + ": " + mhz + " MHz");
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
result.add(cpu.getName() + ": N/A");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.add(cpu.getName() + ": offline or frequency not available");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getCpuTemp() {
|
||||||
|
String line = readLine(CPU_TEMP_PATH);
|
||||||
|
if (line == null) return "N/A";
|
||||||
|
line = line.trim();
|
||||||
|
try {
|
||||||
|
float raw = Float.parseFloat(line);
|
||||||
|
float c = raw / 1000f;
|
||||||
|
return String.format("%.1f", c);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int extractCpuNumber(java.io.File cpuFolder) {
|
||||||
|
String name = cpuFolder.getName().replace("cpu", "");
|
||||||
|
try {
|
||||||
|
return Integer.parseInt(name);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readLine(String path) {
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
|
||||||
|
return br.readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.window.TaskFpsCallback;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class GameBarFpsMeter {
|
||||||
|
|
||||||
|
private static final float TOLERANCE = 0.1f;
|
||||||
|
private static final long STALENESS_THRESHOLD_MS = 2000;
|
||||||
|
private static final long TASK_CHECK_INTERVAL_MS = 1000;
|
||||||
|
|
||||||
|
private static GameBarFpsMeter sInstance;
|
||||||
|
private final Context mContext;
|
||||||
|
private final WindowManager mWindowManager;
|
||||||
|
private final SharedPreferences mPrefs;
|
||||||
|
private float mCurrentFps = 0f;
|
||||||
|
private TaskFpsCallback mTaskFpsCallback;
|
||||||
|
private boolean mCallbackRegistered = false;
|
||||||
|
private int mCurrentTaskId = -1;
|
||||||
|
private long mLastFpsUpdateTime = System.currentTimeMillis();
|
||||||
|
private final android.os.Handler mHandler = new android.os.Handler();
|
||||||
|
|
||||||
|
public static synchronized GameBarFpsMeter getInstance(Context context) {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new GameBarFpsMeter(context.getApplicationContext());
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameBarFpsMeter(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
mPrefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
mTaskFpsCallback = new TaskFpsCallback() {
|
||||||
|
@Override
|
||||||
|
public void onFpsReported(float fps) {
|
||||||
|
if (fps > 0) {
|
||||||
|
mCurrentFps = fps;
|
||||||
|
mLastFpsUpdateTime = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
String method = mPrefs.getString("game_bar_fps_method", "new");
|
||||||
|
if (!"new".equals(method)) return;
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
int taskId = getFocusedTaskId();
|
||||||
|
if (taskId <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mCurrentTaskId = taskId;
|
||||||
|
try {
|
||||||
|
mWindowManager.registerTaskFpsCallback(mCurrentTaskId, Runnable::run, mTaskFpsCallback);
|
||||||
|
mCallbackRegistered = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
mLastFpsUpdateTime = System.currentTimeMillis();
|
||||||
|
mHandler.postDelayed(mTaskCheckRunnable, TASK_CHECK_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
String method = mPrefs.getString("game_bar_fps_method", "new");
|
||||||
|
if ("new".equals(method) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
if (mCallbackRegistered) {
|
||||||
|
try {
|
||||||
|
mWindowManager.unregisterTaskFpsCallback(mTaskFpsCallback);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
mCallbackRegistered = false;
|
||||||
|
}
|
||||||
|
mHandler.removeCallbacks(mTaskCheckRunnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFps() {
|
||||||
|
String method = mPrefs.getString("game_bar_fps_method", "new");
|
||||||
|
if ("legacy".equals(method)) {
|
||||||
|
return readLegacyFps();
|
||||||
|
} else {
|
||||||
|
return mCurrentFps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float readLegacyFps() {
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader("/sys/class/drm/sde-crtc-0/measured_fps"))) {
|
||||||
|
String line = br.readLine();
|
||||||
|
if (line != null && line.startsWith("fps:")) {
|
||||||
|
String[] parts = line.split("\\s+");
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
return Float.parseFloat(parts[1].trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException | NumberFormatException e) {
|
||||||
|
}
|
||||||
|
return -1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Runnable mTaskCheckRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
int newTaskId = getFocusedTaskId();
|
||||||
|
if (newTaskId > 0 && newTaskId != mCurrentTaskId) {
|
||||||
|
reinitCallback();
|
||||||
|
} else {
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
if (now - mLastFpsUpdateTime > STALENESS_THRESHOLD_MS) {
|
||||||
|
reinitCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mHandler.postDelayed(this, TASK_CHECK_INTERVAL_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private int getFocusedTaskId() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Class<?> atmClass = Class.forName("android.app.ActivityTaskManager");
|
||||||
|
Method getServiceMethod = atmClass.getDeclaredMethod("getService");
|
||||||
|
Object atmService = getServiceMethod.invoke(null);
|
||||||
|
Method getFocusedRootTaskInfoMethod = atmService.getClass().getMethod("getFocusedRootTaskInfo");
|
||||||
|
Object taskInfo = getFocusedRootTaskInfoMethod.invoke(atmService);
|
||||||
|
if (taskInfo != null) {
|
||||||
|
try {
|
||||||
|
Field taskIdField = taskInfo.getClass().getField("taskId");
|
||||||
|
return taskIdField.getInt(taskInfo);
|
||||||
|
} catch (NoSuchFieldException nsfe) {
|
||||||
|
try {
|
||||||
|
Field taskIdField = taskInfo.getClass().getField("mTaskId");
|
||||||
|
return taskIdField.getInt(taskInfo);
|
||||||
|
} catch (NoSuchFieldException nsfe2) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reinitCallback() {
|
||||||
|
stop();
|
||||||
|
mHandler.postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,394 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.preference.ListPreference;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
|
import androidx.preference.SeekBarPreference;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
|
import androidx.preference.SwitchPreferenceCompat;
|
||||||
|
|
||||||
|
import com.android.settingslib.widget.MainSwitchPreference;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
public class GameBarFragment extends PreferenceFragmentCompat {
|
||||||
|
|
||||||
|
private GameBar mGameBar;
|
||||||
|
private MainSwitchPreference mMasterSwitch;
|
||||||
|
private SwitchPreferenceCompat mAutoEnableSwitch;
|
||||||
|
private SwitchPreferenceCompat mFpsSwitch;
|
||||||
|
private SwitchPreferenceCompat mBatteryTempSwitch;
|
||||||
|
private SwitchPreferenceCompat mCpuUsageSwitch;
|
||||||
|
private SwitchPreferenceCompat mCpuClockSwitch;
|
||||||
|
private SwitchPreferenceCompat mCpuTempSwitch;
|
||||||
|
private SwitchPreferenceCompat mRamSwitch;
|
||||||
|
private SwitchPreferenceCompat mGpuUsageSwitch;
|
||||||
|
private SwitchPreferenceCompat mGpuClockSwitch;
|
||||||
|
private SwitchPreferenceCompat mGpuTempSwitch;
|
||||||
|
private Preference mCaptureStartPref;
|
||||||
|
private Preference mCaptureStopPref;
|
||||||
|
private Preference mCaptureExportPref;
|
||||||
|
private SwitchPreferenceCompat mDoubleTapCapturePref;
|
||||||
|
private SwitchPreferenceCompat mSingleTapTogglePref;
|
||||||
|
private SwitchPreferenceCompat mLongPressEnablePref;
|
||||||
|
private ListPreference mLongPressTimeoutPref;
|
||||||
|
private SeekBarPreference mTextSizePref;
|
||||||
|
private SeekBarPreference mBgAlphaPref;
|
||||||
|
private SeekBarPreference mCornerRadiusPref;
|
||||||
|
private SeekBarPreference mPaddingPref;
|
||||||
|
private SeekBarPreference mItemSpacingPref;
|
||||||
|
private ListPreference mUpdateIntervalPref;
|
||||||
|
private ListPreference mTextColorPref;
|
||||||
|
private ListPreference mTitleColorPref;
|
||||||
|
private ListPreference mValueColorPref;
|
||||||
|
private ListPreference mPositionPref;
|
||||||
|
private ListPreference mSplitModePref;
|
||||||
|
private ListPreference mOverlayFormatPref;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||||
|
setPreferencesFromResource(R.xml.game_bar_preferences, rootKey);
|
||||||
|
|
||||||
|
mGameBar = GameBar.getInstance(getContext());
|
||||||
|
|
||||||
|
// Initialize all preferences.
|
||||||
|
mMasterSwitch = findPreference("game_bar_enable");
|
||||||
|
mAutoEnableSwitch = findPreference("game_bar_auto_enable");
|
||||||
|
mFpsSwitch = findPreference("game_bar_fps_enable");
|
||||||
|
mBatteryTempSwitch = findPreference("game_bar_temp_enable");
|
||||||
|
mCpuUsageSwitch = findPreference("game_bar_cpu_usage_enable");
|
||||||
|
mCpuClockSwitch = findPreference("game_bar_cpu_clock_enable");
|
||||||
|
mCpuTempSwitch = findPreference("game_bar_cpu_temp_enable");
|
||||||
|
mRamSwitch = findPreference("game_bar_ram_enable");
|
||||||
|
mGpuUsageSwitch = findPreference("game_bar_gpu_usage_enable");
|
||||||
|
mGpuClockSwitch = findPreference("game_bar_gpu_clock_enable");
|
||||||
|
mGpuTempSwitch = findPreference("game_bar_gpu_temp_enable");
|
||||||
|
|
||||||
|
mCaptureStartPref = findPreference("game_bar_capture_start");
|
||||||
|
mCaptureStopPref = findPreference("game_bar_capture_stop");
|
||||||
|
mCaptureExportPref = findPreference("game_bar_capture_export");
|
||||||
|
|
||||||
|
mDoubleTapCapturePref = findPreference("game_bar_doubletap_capture");
|
||||||
|
mSingleTapTogglePref = findPreference("game_bar_single_tap_toggle");
|
||||||
|
mLongPressEnablePref = findPreference("game_bar_longpress_enable");
|
||||||
|
mLongPressTimeoutPref = findPreference("game_bar_longpress_timeout");
|
||||||
|
|
||||||
|
mTextSizePref = findPreference("game_bar_text_size");
|
||||||
|
mBgAlphaPref = findPreference("game_bar_background_alpha");
|
||||||
|
mCornerRadiusPref = findPreference("game_bar_corner_radius");
|
||||||
|
mPaddingPref = findPreference("game_bar_padding");
|
||||||
|
mItemSpacingPref = findPreference("game_bar_item_spacing");
|
||||||
|
|
||||||
|
mUpdateIntervalPref = findPreference("game_bar_update_interval");
|
||||||
|
mTextColorPref = findPreference("game_bar_text_color");
|
||||||
|
mTitleColorPref = findPreference("game_bar_title_color");
|
||||||
|
mValueColorPref = findPreference("game_bar_value_color");
|
||||||
|
mPositionPref = findPreference("game_bar_position");
|
||||||
|
mSplitModePref = findPreference("game_bar_split_mode");
|
||||||
|
mOverlayFormatPref = findPreference("game_bar_format");
|
||||||
|
|
||||||
|
Preference appSelectorPref = findPreference("game_bar_app_selector");
|
||||||
|
if (appSelectorPref != null) {
|
||||||
|
appSelectorPref.setOnPreferenceClickListener(pref -> {
|
||||||
|
Intent intent = new Intent(getContext(), GameBarAppSelectorActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Preference appRemoverPref = findPreference("game_bar_app_remover");
|
||||||
|
if (appRemoverPref != null) {
|
||||||
|
appRemoverPref.setOnPreferenceClickListener(pref -> {
|
||||||
|
Intent intent = new Intent(getContext(), GameBarAppRemoverActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMasterSwitch != null) {
|
||||||
|
mMasterSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
boolean enabled = (boolean) newValue;
|
||||||
|
if (enabled) {
|
||||||
|
if (Settings.canDrawOverlays(getContext())) {
|
||||||
|
mGameBar.applyPreferences();
|
||||||
|
mGameBar.show();
|
||||||
|
getContext().startService(new Intent(getContext(), GameBarMonitorService.class));
|
||||||
|
} else {
|
||||||
|
Toast.makeText(getContext(), R.string.overlay_permission_required, Toast.LENGTH_SHORT).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mGameBar.hide();
|
||||||
|
if (mAutoEnableSwitch == null || !mAutoEnableSwitch.isChecked()) {
|
||||||
|
getContext().stopService(new Intent(getContext(), GameBarMonitorService.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAutoEnableSwitch != null) {
|
||||||
|
mAutoEnableSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
boolean autoEnabled = (boolean) newValue;
|
||||||
|
if (autoEnabled) {
|
||||||
|
getContext().startService(new Intent(getContext(), GameBarMonitorService.class));
|
||||||
|
} else {
|
||||||
|
if (mMasterSwitch == null || !mMasterSwitch.isChecked()) {
|
||||||
|
getContext().stopService(new Intent(getContext(), GameBarMonitorService.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mFpsSwitch != null) {
|
||||||
|
mFpsSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowFps((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mBatteryTempSwitch != null) {
|
||||||
|
mBatteryTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowBatteryTemp((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mCpuUsageSwitch != null) {
|
||||||
|
mCpuUsageSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowCpuUsage((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mCpuClockSwitch != null) {
|
||||||
|
mCpuClockSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowCpuClock((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mCpuTempSwitch != null) {
|
||||||
|
mCpuTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowCpuTemp((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mRamSwitch != null) {
|
||||||
|
mRamSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowRam((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mGpuUsageSwitch != null) {
|
||||||
|
mGpuUsageSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowGpuUsage((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mGpuClockSwitch != null) {
|
||||||
|
mGpuClockSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowGpuClock((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mGpuTempSwitch != null) {
|
||||||
|
mGpuTempSwitch.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setShowGpuTemp((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mCaptureStartPref != null) {
|
||||||
|
mCaptureStartPref.setOnPreferenceClickListener(pref -> {
|
||||||
|
GameDataExport.getInstance().startCapture();
|
||||||
|
Toast.makeText(getContext(), "Started logging Data", Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mCaptureStopPref != null) {
|
||||||
|
mCaptureStopPref.setOnPreferenceClickListener(pref -> {
|
||||||
|
GameDataExport.getInstance().stopCapture();
|
||||||
|
Toast.makeText(getContext(), "Stopped logging Data", Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mCaptureExportPref != null) {
|
||||||
|
mCaptureExportPref.setOnPreferenceClickListener(pref -> {
|
||||||
|
GameDataExport.getInstance().exportDataToCsv();
|
||||||
|
Toast.makeText(getContext(), "Exported log data to file", Toast.LENGTH_SHORT).show();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mDoubleTapCapturePref != null) {
|
||||||
|
mDoubleTapCapturePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setDoubleTapCaptureEnabled((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mSingleTapTogglePref != null) {
|
||||||
|
mSingleTapTogglePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setSingleTapToggleEnabled((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mLongPressEnablePref != null) {
|
||||||
|
mLongPressEnablePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
mGameBar.setLongPressEnabled((boolean) newValue);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mLongPressTimeoutPref != null) {
|
||||||
|
mLongPressTimeoutPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof String) {
|
||||||
|
long ms = Long.parseLong((String) newValue);
|
||||||
|
mGameBar.setLongPressThresholdMs(ms);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mTextSizePref != null) {
|
||||||
|
mTextSizePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof Integer) {
|
||||||
|
mGameBar.updateTextSize((Integer) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mBgAlphaPref != null) {
|
||||||
|
mBgAlphaPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof Integer) {
|
||||||
|
mGameBar.updateBackgroundAlpha((Integer) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mCornerRadiusPref != null) {
|
||||||
|
mCornerRadiusPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof Integer) {
|
||||||
|
mGameBar.updateCornerRadius((Integer) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mPaddingPref != null) {
|
||||||
|
mPaddingPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof Integer) {
|
||||||
|
mGameBar.updatePadding((Integer) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mItemSpacingPref != null) {
|
||||||
|
mItemSpacingPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof Integer) {
|
||||||
|
mGameBar.updateItemSpacing((Integer) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mUpdateIntervalPref != null) {
|
||||||
|
mUpdateIntervalPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof String) {
|
||||||
|
mGameBar.updateUpdateInterval((String) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mTextColorPref != null) {
|
||||||
|
mTextColorPref.setOnPreferenceChangeListener((pref, newValue) -> true);
|
||||||
|
}
|
||||||
|
if (mTitleColorPref != null) {
|
||||||
|
mTitleColorPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof String) {
|
||||||
|
mGameBar.updateTitleColor((String) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mValueColorPref != null) {
|
||||||
|
mValueColorPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof String) {
|
||||||
|
mGameBar.updateValueColor((String) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mPositionPref != null) {
|
||||||
|
mPositionPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof String) {
|
||||||
|
mGameBar.updatePosition((String) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mSplitModePref != null) {
|
||||||
|
mSplitModePref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof String) {
|
||||||
|
mGameBar.updateSplitMode((String) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (mOverlayFormatPref != null) {
|
||||||
|
mOverlayFormatPref.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
|
if (newValue instanceof String) {
|
||||||
|
mGameBar.updateOverlayFormat((String) newValue);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
if (!hasUsageStatsPermission(requireContext())) {
|
||||||
|
requestUsageStatsPermission();
|
||||||
|
}
|
||||||
|
Context context = getContext();
|
||||||
|
if (context != null) {
|
||||||
|
if ((mMasterSwitch != null && mMasterSwitch.isChecked()) ||
|
||||||
|
(mAutoEnableSwitch != null && mAutoEnableSwitch.isChecked())) {
|
||||||
|
context.startService(new Intent(context, GameBarMonitorService.class));
|
||||||
|
} else {
|
||||||
|
context.stopService(new Intent(context, GameBarMonitorService.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasUsageStatsPermission(Context context) {
|
||||||
|
android.app.AppOpsManager appOps = (android.app.AppOpsManager)
|
||||||
|
context.getSystemService(Context.APP_OPS_SERVICE);
|
||||||
|
if (appOps == null) return false;
|
||||||
|
int mode = appOps.checkOpNoThrow(
|
||||||
|
android.app.AppOpsManager.OPSTR_GET_USAGE_STATS,
|
||||||
|
android.os.Process.myUid(),
|
||||||
|
context.getPackageName()
|
||||||
|
);
|
||||||
|
return (mode == android.app.AppOpsManager.MODE_ALLOWED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestUsageStatsPermission() {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GameBarGpuInfo {
|
||||||
|
|
||||||
|
private static final String GPU_USAGE_PATH = "/sys/class/kgsl/kgsl-3d0/gpu_busy_percentage";
|
||||||
|
private static final String GPU_CLOCK_PATH = "/sys/class/kgsl/kgsl-3d0/gpuclk";
|
||||||
|
private static final String GPU_TEMP_PATH = "/sys/class/kgsl/kgsl-3d0/temp";
|
||||||
|
|
||||||
|
public static String getGpuUsage() {
|
||||||
|
String line = readLine(GPU_USAGE_PATH);
|
||||||
|
if (line == null) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
line = line.replace("%", "").trim();
|
||||||
|
try {
|
||||||
|
int val = Integer.parseInt(line);
|
||||||
|
return String.valueOf(val);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getGpuClock() {
|
||||||
|
String line = readLine(GPU_CLOCK_PATH);
|
||||||
|
if (line == null) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
line = line.trim();
|
||||||
|
try {
|
||||||
|
long hz = Long.parseLong(line);
|
||||||
|
long mhz = hz / 1_000_000;
|
||||||
|
return String.valueOf(mhz);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getGpuTemp() {
|
||||||
|
String line = readLine(GPU_TEMP_PATH);
|
||||||
|
if (line == null) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
line = line.trim();
|
||||||
|
try {
|
||||||
|
float raw = Float.parseFloat(line);
|
||||||
|
float c = raw / 1000f;
|
||||||
|
return String.format("%.1f", c);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readLine(String path) {
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
|
||||||
|
return br.readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class GameBarMemInfo {
|
||||||
|
|
||||||
|
public static String getRamUsage() {
|
||||||
|
long memTotal = 0;
|
||||||
|
long memAvailable = 0;
|
||||||
|
|
||||||
|
try (BufferedReader br = new BufferedReader(new FileReader("/proc/meminfo"))) {
|
||||||
|
String line;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
if (line.startsWith("MemTotal:")) {
|
||||||
|
memTotal = parseMemValue(line);
|
||||||
|
} else if (line.startsWith("MemAvailable:")) {
|
||||||
|
memAvailable = parseMemValue(line);
|
||||||
|
}
|
||||||
|
if (memTotal > 0 && memAvailable > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memTotal == 0) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
|
||||||
|
long usedKb = (memTotal - memAvailable);
|
||||||
|
long usedMb = usedKb / 1024;
|
||||||
|
return String.valueOf(usedMb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long parseMemValue(String line) {
|
||||||
|
String[] parts = line.split("\\s+");
|
||||||
|
if (parts.length < 3) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Long.parseLong(parts[1]);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class GameBarMonitorService extends Service {
|
||||||
|
|
||||||
|
private Handler mHandler;
|
||||||
|
private Runnable mMonitorRunnable;
|
||||||
|
private static final long MONITOR_INTERVAL = 2000; // 2 seconds
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
mHandler = new Handler();
|
||||||
|
mMonitorRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
monitorForegroundApp();
|
||||||
|
mHandler.postDelayed(this, MONITOR_INTERVAL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mHandler.post(mMonitorRunnable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void monitorForegroundApp() {
|
||||||
|
var prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
boolean masterEnabled = prefs.getBoolean("game_bar_enable", false);
|
||||||
|
if (masterEnabled) {
|
||||||
|
GameBar.getInstance(this).applyPreferences();
|
||||||
|
GameBar.getInstance(this).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean autoEnabled = prefs.getBoolean("game_bar_auto_enable", false);
|
||||||
|
if (!autoEnabled) {
|
||||||
|
GameBar.getInstance(this).hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String foreground = ForegroundAppDetector.getForegroundPackageName(this);
|
||||||
|
Set<String> autoApps = prefs.getStringSet(GameBarAppSelectorFragment.PREF_AUTO_APPS, new HashSet<>());
|
||||||
|
if (autoApps.contains(foreground)) {
|
||||||
|
GameBar.getInstance(this).applyPreferences();
|
||||||
|
GameBar.getInstance(this).show();
|
||||||
|
} else {
|
||||||
|
GameBar.getInstance(this).hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
mHandler.removeCallbacks(mMonitorRunnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
public class GameBarSettingsActivity extends CollapsingToolbarBaseActivity {
|
||||||
|
private static final int OVERLAY_PERMISSION_REQUEST_CODE = 1234;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_game_bar);
|
||||||
|
setTitle(getString(R.string.game_bar_title));
|
||||||
|
|
||||||
|
if (!Settings.canDrawOverlays(this)) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
|
||||||
|
Uri.parse("package:" + getPackageName()));
|
||||||
|
startActivityForResult(intent, OVERLAY_PERMISSION_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
if (requestCode == OVERLAY_PERMISSION_REQUEST_CODE) {
|
||||||
|
if (Settings.canDrawOverlays(this)) {
|
||||||
|
Toast.makeText(this, R.string.overlay_permission_granted, Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
Toast.makeText(this, R.string.overlay_permission_denied, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 kenway214
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.service.quicksettings.Tile;
|
||||||
|
import android.service.quicksettings.TileService;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.lineageos.device.DeviceSettings.R;
|
||||||
|
|
||||||
|
public class GameBarTileService extends TileService {
|
||||||
|
private GameBar mGameBar;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
mGameBar = GameBar.getInstance(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStartListening() {
|
||||||
|
boolean enabled = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
.getBoolean("game_bar_enable", false);
|
||||||
|
updateTileState(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick() {
|
||||||
|
boolean currentlyEnabled = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
.getBoolean("game_bar_enable", false);
|
||||||
|
boolean newState = !currentlyEnabled;
|
||||||
|
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
.edit()
|
||||||
|
.putBoolean("game_bar_enable", newState)
|
||||||
|
.commit();
|
||||||
|
|
||||||
|
updateTileState(newState);
|
||||||
|
|
||||||
|
if (newState) {
|
||||||
|
mGameBar.applyPreferences();
|
||||||
|
mGameBar.show();
|
||||||
|
} else {
|
||||||
|
mGameBar.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTileState(boolean enabled) {
|
||||||
|
Tile tile = getQsTile();
|
||||||
|
if (tile == null) return;
|
||||||
|
|
||||||
|
tile.setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||||
|
tile.setLabel(getString(R.string.game_bar_tile_label));
|
||||||
|
tile.setContentDescription(getString(R.string.game_bar_tile_description));
|
||||||
|
tile.updateTile();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.device.DeviceSettings.gamebar;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class GameDataExport {
|
||||||
|
|
||||||
|
private static GameDataExport sInstance;
|
||||||
|
public static synchronized GameDataExport getInstance() {
|
||||||
|
if (sInstance == null) {
|
||||||
|
sInstance = new GameDataExport();
|
||||||
|
}
|
||||||
|
return sInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mCapturing = false;
|
||||||
|
|
||||||
|
private final List<String[]> mStatsRows = new ArrayList<>();
|
||||||
|
|
||||||
|
private static final String[] CSV_HEADER = {
|
||||||
|
"DateTime",
|
||||||
|
"PackageName",
|
||||||
|
"FPS",
|
||||||
|
"Battery_Temp",
|
||||||
|
"CPU_Usage",
|
||||||
|
"CPU_Temp",
|
||||||
|
"GPU_Usage",
|
||||||
|
"GPU_Clock",
|
||||||
|
"GPU_Temp"
|
||||||
|
};
|
||||||
|
|
||||||
|
private GameDataExport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startCapture() {
|
||||||
|
mCapturing = true;
|
||||||
|
mStatsRows.clear();
|
||||||
|
mStatsRows.add(CSV_HEADER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopCapture() {
|
||||||
|
mCapturing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCapturing() {
|
||||||
|
return mCapturing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addOverlayData(String dateTime,
|
||||||
|
String packageName,
|
||||||
|
String fps,
|
||||||
|
String batteryTemp,
|
||||||
|
String cpuUsage,
|
||||||
|
String cpuTemp,
|
||||||
|
String gpuUsage,
|
||||||
|
String gpuClock,
|
||||||
|
String gpuTemp) {
|
||||||
|
if (!mCapturing) return;
|
||||||
|
|
||||||
|
String[] row = {
|
||||||
|
dateTime,
|
||||||
|
packageName,
|
||||||
|
fps,
|
||||||
|
batteryTemp,
|
||||||
|
cpuUsage,
|
||||||
|
cpuTemp,
|
||||||
|
gpuUsage,
|
||||||
|
gpuClock,
|
||||||
|
gpuTemp
|
||||||
|
};
|
||||||
|
mStatsRows.add(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exportDataToCsv() {
|
||||||
|
if (mStatsRows.size() <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date());
|
||||||
|
File outFile = new File(Environment.getExternalStorageDirectory(), "GameBar_log_" + timeStamp + ".csv");
|
||||||
|
|
||||||
|
BufferedWriter bw = null;
|
||||||
|
try {
|
||||||
|
bw = new BufferedWriter(new FileWriter(outFile, true));
|
||||||
|
for (String[] row : mStatsRows) {
|
||||||
|
bw.write(toCsvLine(row));
|
||||||
|
bw.newLine();
|
||||||
|
}
|
||||||
|
bw.flush();
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
} finally {
|
||||||
|
if (bw != null) {
|
||||||
|
try { bw.close(); } catch (IOException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toCsvLine(String[] columns) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < columns.length; i++) {
|
||||||
|
sb.append(columns[i]);
|
||||||
|
if (i < columns.length - 1) {
|
||||||
|
sb.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 The CyanogenMod Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.lineageos.device.DeviceSettings.utils;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public final class FileUtils {
|
||||||
|
private static final String TAG = "FileUtils";
|
||||||
|
|
||||||
|
private FileUtils() {
|
||||||
|
// This class is not supposed to be instantiated
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the first line of text from the given file.
|
||||||
|
* Reference {@link BufferedReader#readLine()} for clarification on what a line is
|
||||||
|
*
|
||||||
|
* @return the read line contents, or null on failure
|
||||||
|
*/
|
||||||
|
public static String readOneLine(String fileName) {
|
||||||
|
String line = null;
|
||||||
|
BufferedReader reader = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
reader = new BufferedReader(new FileReader(fileName), 512);
|
||||||
|
line = reader.readLine();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.w(TAG, "No such file " + fileName + " for reading", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Could not read from file " + fileName, e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (reader != null) {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignored, not much we can do anyway
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the given value into the given file
|
||||||
|
*
|
||||||
|
* @return true on success, false on failure
|
||||||
|
*/
|
||||||
|
public static boolean writeLine(String fileName, String value) {
|
||||||
|
BufferedWriter writer = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
writer = new BufferedWriter(new FileWriter(fileName));
|
||||||
|
writer.write(value);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
Log.w(TAG, "No such file " + fileName + " for writing", e);
|
||||||
|
return false;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Could not write to file " + fileName, e);
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (writer != null) {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// Ignored, not much we can do anyway
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given file exists
|
||||||
|
*
|
||||||
|
* @return true if exists, false if not
|
||||||
|
*/
|
||||||
|
public static boolean fileExists(String fileName) {
|
||||||
|
final File file = new File(fileName);
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given file is readable
|
||||||
|
*
|
||||||
|
* @return true if readable, false if not
|
||||||
|
*/
|
||||||
|
public static boolean isFileReadable(String fileName) {
|
||||||
|
final File file = new File(fileName);
|
||||||
|
return file.exists() && file.canRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given file is writable
|
||||||
|
*
|
||||||
|
* @return true if writable, false if not
|
||||||
|
*/
|
||||||
|
public static boolean isFileWritable(String fileName) {
|
||||||
|
final File file = new File(fileName);
|
||||||
|
return file.exists() && file.canWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes an existing file
|
||||||
|
*
|
||||||
|
* @return true if the delete was successful, false if not
|
||||||
|
*/
|
||||||
|
public static boolean delete(String fileName) {
|
||||||
|
final File file = new File(fileName);
|
||||||
|
boolean ok = false;
|
||||||
|
try {
|
||||||
|
ok = file.delete();
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.w(TAG, "SecurityException trying to delete " + fileName, e);
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renames an existing file
|
||||||
|
*
|
||||||
|
* @return true if the rename was successful, false if not
|
||||||
|
*/
|
||||||
|
public static boolean rename(String srcPath, String dstPath) {
|
||||||
|
final File srcFile = new File(srcPath);
|
||||||
|
final File dstFile = new File(dstPath);
|
||||||
|
boolean ok = false;
|
||||||
|
try {
|
||||||
|
ok = srcFile.renameTo(dstFile);
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
Log.w(TAG, "SecurityException trying to rename " + srcPath + " to " + dstPath, e);
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
Log.e(TAG, "NullPointerException trying to rename " + srcPath + " to " + dstPath, e);
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getFileValueAsBoolean(String filename, boolean defValue) {
|
||||||
|
String fileValue = readOneLine(filename);
|
||||||
|
if(fileValue!=null){
|
||||||
|
return (fileValue.equals("0")?false:true);
|
||||||
|
}
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFileValue(String filename, String defValue) {
|
||||||
|
String fileValue = readOneLine(filename);
|
||||||
|
if(fileValue!=null){
|
||||||
|
return fileValue;
|
||||||
|
}
|
||||||
|
return defValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,8 +5,5 @@ audio.offload.min.duration.secs=30
|
|||||||
audio.offload.video=true
|
audio.offload.video=true
|
||||||
ro.af.client_heap_size_kbyte=7168
|
ro.af.client_heap_size_kbyte=7168
|
||||||
|
|
||||||
# Device name
|
|
||||||
ro.product.marketname=OnePlus 11 5G
|
|
||||||
|
|
||||||
# GMS
|
# GMS
|
||||||
ro.opa.device_model_id=ga-oplus-skill-os121-211011
|
ro.opa.device_model_id=ga-oplus-skill-os121-211011
|
||||||
|
|||||||
Reference in New Issue
Block a user