PixelParts: Initial commit

This branch will ONLY be configured for pixel 6 & 7 series.

Co-authored-by: Pranav Vashi <neobuddy89@gmail.com>
Co-authored-by: LorDClockaN <lordclockan@gmail.com>
Co-authored-by: AmeChanRain <downloadbot007@gmail.com>
Co-authored-by: Ramii Ahmed <ramy@ahmedramy.com>
Co-authored-by: Max Weninger <max.weninger@gmail.com>
Co-authored-by: Hikari-no-Tenshi <kyryljan.serhij@gmail.com>
Co-authored-by: EmanuelCN <emanuelghub@gmail.com>
Signed-off-by: AnierinB <anierin@evolution-x.org>
This commit is contained in:
2023-05-26 19:13:37 -07:00
commit a0170747c7
48 changed files with 2457 additions and 0 deletions

35
Android.bp Normal file
View File

@@ -0,0 +1,35 @@
//
// Copyright (C) 2023 The Evolution X Project
// SPDX-License-Identifier: Apache-2.0
//
android_app {
name: "PixelParts",
defaults: [
"SettingsLibDefaults",
],
srcs: [
"src/**/*.java",
"src/**/*.kt",
],
certificate: "platform",
platform_apis: true,
system_ext_specific: true,
privileged: true,
static_libs: [
"androidx.core_core",
"androidx.preference_preference",
"particles",
],
resource_dirs: ["res"],
optimize: {
proguard_flags_files: ["proguard.flags"],
},
}
java_import {
name: "particles",
jars: [
"libs/LeonidsLib.jar",
],
}

131
AndroidManifest.xml Normal file
View File

@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Evolution X Project
SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:sharedUserId="android.uid.system"
package="org.evolution.pixelparts"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.INJECT_EVENTS"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application
android:icon="@drawable/ic_launcher_settings"
android:label="@string/pixel_parts_title"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
android:theme="@style/Theme.SubSettingsBase"
android:exported="true">
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:replace="android:authorities"/>
<!-- PixelParts -->
<activity
android:name=".PixelPartsActivity"
android:label="@string/pixel_parts_title"
android:exported="true">
<intent-filter>
<action android:name="com.android.settings.action.EXTRA_SETTINGS" />
</intent-filter>
<meta-data
android:name="com.android.settings.icon"
android:resource="@drawable/ic_pixel_parts" />
<meta-data
android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.homepage" />
<meta-data android:name="com.android.settings.summary"
android:resource="@string/pixel_parts_summary" />
</activity>
<activity
android:name=".PixelParts"
android:exported="false" />
<!-- PixelParts boot completed receiver -->
<receiver
android:name=".Startup"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>
<!-- HBM service -->
<service
android:name=".services.HBMService"
android:exported="false" />
<!-- Auto HBM service -->
<service
android:name=".services.AutoHBMService"
android:exported="false" />
<!-- Jitter test activity -->
<activity
android:name=".uibench.JitterTestActivity"
android:label="@string/jitter_test_title"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Power efficient workqueue tile service -->
<service
android:name=".services.PEWQTileSerice"
android:label="@string/power_efficient_workqueue_title"
android:icon="@drawable/ic_power_efficient_workqueue_tile"
android:exported="true"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<!-- HBM tile service -->
<service
android:name=".services.HBMTileService"
android:label="@string/hbm_title"
android:icon="@drawable/ic_hbm_tile"
android:exported="true"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<!-- USB 2.0 Fastcharge tile service -->
<service
android:name=".services.USB2FCTileService"
android:label="@string/usb2_fast_charge_title"
android:icon="@drawable/ic_usb2_fc_tile"
android:exported="true"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<!-- Search Provider -->
<provider
android:name=".ConfigPanelSearchIndexablesProvider"
android:authorities="org.evolution.pixelparts"
android:multiprocess="false"
android:grantUriPermissions="true"
android:permission="android.permission.READ_SEARCH_INDEXABLES"
android:exported="true">
<intent-filter>
<action android:name="android.content.action.SEARCH_INDEXABLES_PROVIDER" />
</intent-filter>
</provider>
</application>
</manifest>

3
crowdin.yml Normal file
View File

@@ -0,0 +1,3 @@
files:
- source: /**/values/strings.xml
translation: /%original_path%-%android_code%/%original_file_name%

10
device.mk Normal file
View File

@@ -0,0 +1,10 @@
# PixelParts app
PRODUCT_PACKAGES += \
PixelParts
# PixelParts sepolicy
BOARD_SEPOLICY_DIRS += packages/apps/PixelParts/sepolicy
# PixelParts init rc
PRODUCT_COPY_FILES += \
packages/apps/PixelParts/init/init.pixelparts.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.pixelparts.rc

13
init/init.pixelparts.rc Normal file
View File

@@ -0,0 +1,13 @@
on property:sys.boot_completed=1
# Power Efficient Workqueue
chown system system /sys/module/workqueue/parameters/power_efficient
chmod 0666 /sys/module/workqueue/parameters/power_efficient
# HBM
chown system system /sys/class/backlight/panel0-backlight/hbm_mode
chmod 0666 /sys/class/backlight/panel0-backlight/hbm_mode
# USB 2.0 Force Fast Charge
chown system system /sys/kernel/fast_charge/force_fast_charge
chmod 0666 /sys/kernel/fast_charge/force_fast_charge

BIN
libs/LeonidsLib.jar Normal file

Binary file not shown.

3
proguard.flags Normal file
View File

@@ -0,0 +1,3 @@
-keep class org.evolution.pixelparts.** {
*;
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019-2023 The Evolution X Project
SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#005eff"
android:fillType="evenOdd"
android:pathData="M15,24c-0.2,0 -0.5,-0.1 -0.6,-0.2L4.1,14.7c-0.3,-0.2 -0.4,-0.6 -0.3,-1l0.9,-3.4c0.1,-0.4 0.5,-0.7 0.9,-0.7h10.1c0.3,0 0.6,0.1 0.7,0.4l2.8,3.4c0.2,0.3 0.3,0.7 0.1,1c-0.2,0.3 -0.5,0.5 -0.9,0.5h-5.8l3.8,3.4c0.3,0.2 0.4,0.6 0.3,0.9l-0.9,4c-0.1,0.3 -0.3,0.6 -0.6,0.7C15.2,24 15.1,24 15,24zM5.8,13.7l8.6,7.6l0.4,-1.9l-5.3,-4.7c-0.3,-0.3 -0.4,-0.7 -0.3,-1.1c0.1,-0.4 0.5,-0.6 0.9,-0.6h6.4l-1.2,-1.5H6.4L5.8,13.7z" />
<path
android:fillColor="#005eff"
android:fillType="evenOdd"
android:pathData="M17.6,7.4H8.9c-0.2,0 -0.5,-0.1 -0.7,-0.3L4.6,3.7C4.3,3.4 4.2,3 4.3,2.6C4.5,2.2 4.8,2 5.2,2h13.3c0.3,0 0.6,0.1 0.8,0.4c0.2,0.2 0.2,0.5 0.2,0.8l-0.9,3.4C18.4,7.1 18,7.4 17.6,7.4zM9.3,5.4h7.6l0.4,-1.5H7.6L9.3,5.4z" />
</vector>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018-2022 crDroid Android Project
SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0" >
<path
android:fillColor="?android:attr/colorControlNormal"
android:pathData="M24 4C12.972 4 4 12.972 4 24s8.972 20 20 20s20 -8.972 20 -20S35.028 4 24 4zM32.5 25.5h-17c-0.829 0 -1.5 -0.671 -1.5 -1.5s0.671 -1.5 1.5 -1.5h17c0.829 0 1.5 0.671 1.5 1.5S33.329 25.5 32.5 25.5z" />
</vector>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018-2022 crDroid Android Project
SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0" >
<path
android:fillColor="?android:attr/colorControlNormal"
android:pathData="M24 4C12.972 4 4 12.972 4 24s8.972 20 20 20s20 -8.972 20 -20S35.028 4 24 4zM32.5 25.5h-7v7c0 0.829 -0.672 1.5 -1.5 1.5s-1.5 -0.671 -1.5 -1.5v-7h-7c-0.828 0 -1.5 -0.671 -1.5 -1.5s0.672 -1.5 1.5 -1.5h7v-7c0 -0.829 0.672 -1.5 1.5 -1.5s1.5 0.671 1.5 1.5v7h7c0.828 0 1.5 0.671 1.5 1.5S33.328 25.5 32.5 25.5z" />
</vector>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2019 Havoc-OS
2022 DerpFest
SPDX-License-Identifier: Apache-2.0
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0" >
<path
android:fillColor="?android:attr/colorControlNormal"
android:pathData="M14.123456746339798,12.042328000068665 c0,-0.7430335164070133 -0.6079365134239197,-1.3509700298309326 -1.3509700298309326,-1.3509700298309326 s-1.3509700298309326,0.6079365134239197 -1.3509700298309326,1.3509700298309326 s0.6079365134239197,1.3509700298309326 1.3509700298309326,1.3509700298309326 s1.3509700298309326,-0.6079365134239197 1.3509700298309326,-1.3509700298309326 zM12.772486716508865,5.962962865829468 c-3.3571605241298674,0 -6.079365134239197,2.7222046101093293 -6.079365134239197,6.079365134239197 L4.66666653752327,12.042328000068665 l2.7019400596618652,2.7019400596618652 l2.7019400596618652,-2.7019400596618652 L8.044091612100601,12.042328000068665 c0,-2.6141270077228547 2.1142680966854095,-4.728395104408264 4.728395104408264,-4.728395104408264 s4.728395104408264,2.1142680966854095 4.728395104408264,4.728395104408264 s-2.1142680966854095,4.728395104408264 -4.728395104408264,4.728395104408264 c-1.0199823725223542,0 -1.965661393404007,-0.3309876573085789 -2.742469160556793,-0.8781305193901066 l-0.9591887211799618,0.9726984214782719 C10.097566057443618,17.648853623867033 11.380987585783004,18.12169313430786 12.772486716508865,18.12169313430786 c3.3571605241298674,0 6.079365134239197,-2.7222046101093293 6.079365134239197,-6.079365134239197 s-2.7222046101093293,-6.079365134239197 -6.079365134239197,-6.079365134239197 z" />
</vector>

View File

@@ -0,0 +1,11 @@
<!-- drawable/ic_hbm_tile.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#000"
android:pathData="M11,4V1H13V4ZM11,23V20H13V23ZM20,13V11H23V13ZM1,13V11H4V13ZM18.7,6.7 L17.3,5.3 19.05,3.5 20.5,4.95ZM4.95,20.5 L3.5,19.05 5.3,17.3 6.7,18.7ZM19.05,20.5 L17.3,18.7 18.7,17.3 20.5,19.05ZM5.3,6.7 L3.5,4.95 4.95,3.5 6.7,5.3ZM12,18Q9.5,18 7.75,16.25Q6,14.5 6,12Q6,9.5 7.75,7.75Q9.5,6 12,6Q14.5,6 16.25,7.75Q18,9.5 18,12Q18,14.5 16.25,16.25Q14.5,18 12,18ZM12,16Q13.675,16 14.838,14.837Q16,13.675 16,12Q16,10.325 14.838,9.162Q13.675,8 12,8Q10.325,8 9.163,9.162Q8,10.325 8,12Q8,13.675 9.163,14.837Q10.325,16 12,16ZM12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Q12,12 12,12Z"/>
</vector>

View File

@@ -0,0 +1,11 @@
<!-- drawable/ic_info_outline.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#000"
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z" />
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/icon_launcher_setting_color"/>
<foreground android:drawable="@mipmap/ic_launcher_settings"/>
</adaptive-icon>

View File

@@ -0,0 +1,10 @@
<!-- drawable/ic_pixel_parts.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="?android:attr/colorPrimary"
android:pathData="M21.81 12.74l-0.82 -0.63c0 -0.09 0 -0.13 0 -0.22l0.8 -0.63c0.16 -0.12 0.2 -0.34 0.1 -0.51l-0.85 -1.48c-0.07 -0.13 -0.21 -0.2 -0.35 -0.2c-0.05 0 -0.1 0.01 -0.15 0.03l-0.95 0.38c-0.08 -0.05 -0.11 -0.07 -0.19 -0.11l-0.15 -1.01C19.22 8.15 19.05 8 18.85 8h-1.71c-0.2 0 -0.37 0.15 -0.4 0.34L16.6 9.35c-0.03 0.02 -0.07 0.03 -0.1 0.05c-0.03 0.02 -0.06 0.04 -0.09 0.06l-0.95 -0.38c-0.05 -0.02 -0.1 -0.03 -0.15 -0.03c-0.14 0 -0.27 0.07 -0.35 0.2l-0.85 1.48c-0.1 0.17 -0.06 0.39 0.1 0.51l0.8 0.63c0 0.09 0 0.13 0 0.23l-0.8 0.63c-0.16 0.12 -0.2 0.34 -0.1 0.51l0.85 1.48c0.07 0.13 0.21 0.2 0.35 0.2c0.05 0 0.1 -0.01 0.15 -0.03l0.95 -0.37c0.08 0.05 0.12 0.07 0.2 0.11l0.15 1.01c0.03 0.2 0.2 0.34 0.4 0.34h1.71c0.2 0 0.37 -0.15 0.4 -0.34l0.15 -1.01c0.03 -0.02 0.07 -0.03 0.1 -0.05c0.03 -0.02 0.06 -0.04 0.09 -0.06l0.95 0.38c0.05 0.02 0.1 0.03 0.15 0.03c0.14 0 0.27 -0.07 0.35 -0.2l0.85 -1.48C22.01 13.08 21.97 12.86 21.81 12.74zM18 13.5c-0.83 0 -1.5 -0.67 -1.5 -1.5c0 -0.83 0.67 -1.5 1.5 -1.5s1.5 0.67 1.5 1.5C19.5 12.83 18.83 13.5 18 13.5zM17 18H7V6h10v1h2V3c0 -1.1 -0.9 -2 -2 -2H7C5.9 1 5 1.9 5 3v18c0 1.1 0.9 2 2 2h10c1.1 0 2 -0.9 2 -2v-4h-2V18zM7 3h10v1H7V3zM17 21H7v-1h10V21z" />
</vector>

View File

@@ -0,0 +1,11 @@
<!-- drawable/ic_power_efficient_workqueue.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#000"
android:pathData="M600,840L600,720L440,720L440,320L360,320L360,440L80,440L80,120L360,120L360,240L600,240L600,120L880,120L880,440L600,440L600,320L520,320L520,640L600,640L600,520L880,520L880,840L600,840ZM160,200L160,200L160,360L160,360L160,200ZM680,600L680,600L680,760L680,760L680,600ZM680,200L680,200L680,360L680,360L680,200ZM680,360L800,360L800,200L680,200L680,360ZM680,760L800,760L800,600L680,600L680,760ZM160,360L280,360L280,200L160,200L160,360Z"/>
</vector>

View File

@@ -0,0 +1,11 @@
<!-- drawable/ic_usb2_fc_tile -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#000"
android:pathData="M23,11H20V4L15,14H18V22M12,8H4V6H12M12.67,4H11V2H5V4H3.33A1.33,1.33 0 0,0 2,5.33V20.67C2,21.4 2.6,22 3.33,22H12.67C13.4,22 14,21.4 14,20.67V5.33A1.33,1.33 0 0,0 12.67,4Z" />
</vector>

View File

@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017-2022 crDroid Android Project
SPDX-License-Identifier: Apache-2.0
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:background="?android:attr/activatedBackgroundIndicator"
android:clipToPadding="false">
<LinearLayout
android:id="@android:id/icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="-4dp"
android:minWidth="60dp"
android:gravity="start|center_vertical"
android:orientation="horizontal"
android:paddingEnd="12dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<com.android.internal.widget.PreferenceImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="48dp"
android:maxHeight="48dp" />
</LinearLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee" />
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="10"
android:ellipsize="end" />
<RelativeLayout
android:id="@+id/value_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/summary"
android:layout_alignStart="@android:id/title" >
<TextView
android:id="@+id/value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="1"
android:ellipsize="end" />
<ImageView
android:id="@+id/reset"
android:src="@drawable/ic_custom_seekbar_reset"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_toEndOf="@id/value"
android:layout_centerVertical="true" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/seekbar_frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/value_frame"
android:layout_alignStart="@android:id/title" >
<ImageView
android:id="@+id/minus"
android:src="@drawable/ic_custom_seekbar_minus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true" />
<ImageView
android:id="@+id/plus"
android:src="@drawable/ic_custom_seekbar_plus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true" />
<LinearLayout
android:id="@+id/seekbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_toEndOf="@id/minus"
android:layout_toStartOf="@id/plus"
android:layout_centerVertical="true" />
</RelativeLayout>
</RelativeLayout>
<!-- Preference should place its actual preference widget here. -->
<LinearLayout android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="end|center_vertical"
android:paddingStart="16dp"
android:orientation="vertical" />
</LinearLayout>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016 The Android Open Source Project
SPDX-License-Identifier: Apache-2.0
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView android:id="@+id/jitter_mma"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true" />
<TextView android:id="@+id/totalish_mma"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true" />
<TextView android:id="@+id/ui_frametime_mma"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true" />
<TextView android:id="@+id/rt_frametime_mma"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true" />
<TextView android:id="@+id/total_mma"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true" />
<View android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1" />
<view class="org.evolution.pixelparts.uibench.JitterTestActivity$PointGraphView"
android:id="@+id/graph"
android:layout_height="200dp"
android:layout_width="match_parent" />
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

17
res/values/attrs.xml Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2018-2022 crDroid Android Project
SPDX-License-Identifier: Apache-2.0
-->
<resources>
<!-- Base attributes available to CustomSeekBarPreference. -->
<declare-styleable name="CustomSeekBarPreference">
<attr name="defaultValueText" format="string" />
<attr name="interval" format="integer" />
<attr name="showSign" format="boolean" />
<attr name="units" format="string|reference" />
<attr name="continuousUpdates" format="boolean" />
</declare-styleable>
</resources>

12
res/values/colors.xml Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2016-2022 crDroid Android Project
2023 The Evolution X Project
SPDX-License-Identifier: Apache-2.0
-->
<resources>
<color name="icon_launcher_setting_color">@*android:color/accent_device_default_light</color>
<color name="disabled_text_color">#66000000</color> <!-- 38% black -->
</resources>

48
res/values/strings.xml Normal file
View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Evolution X Project
2016-2022 crDroid Android Project
SPDX-License-Identifier: Apache-2.0
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- PixelParts -->
<string name="pixel_parts_title">Pixel Parts</string>
<string name="pixel_parts_summary">Configure device specific settings</string>
<string name="pixel_parts_warning_title">Warning</string>
<string name="pixel_parts_warning_text">Most of these features rely on specific kernel nodes in order to function. When flashing a custom kernel, you risk the possibility of losing access to some of these features. You have been warned!</string>
<string name="pixel_parts_dialog">OK</string>
<!-- CPU -->
<string name="category_cpu">CPU</string>
<string name="power_efficient_workqueue_title">Power efficient workqueue</string>
<string name="power_efficient_workqueue_summary">Save power by rescheduling work to a core that is already awake</string>
<!-- Display -->
<string name="category_display">Display</string>
<string name="hbm_title">High brightness mode (HBM)</string>
<string name="hbm_summary">Enable peak luminance</string>
<string name="auto_hbm_title">Automatic HBM</string>
<string name="auto_hbm_summary">Enable peak luminance based on sunlight</string>
<string name="auto_hbm_threshold_title"></string>
<string name="auto_hbm_threshold_summary">threshold (lux)</string>
<string name="hbm_info">Long time usage of High brightness mode may damage your display!</string>
<!-- UiBench -->
<string name="category_uibench">UiBench</string>
<string name="jitter_test_title">Jitter</string>
<string name="jitter_test_summary">Calculate rendering jitter</string>
<!-- USB -->
<string name="category_usb">USB</string>
<string name="usb2_fast_charge_title">USB 2.0 fast charge</string>
<string name="usb2_fast_charge_summary">Enable CDP mode for fast charging on USB 2.0 ports</string>
<string name="usb2_fast_charge_info">Not all USB 2.0 ports support CDP mode, use with caution!</string>
<!-- Custom seekbar -->
<string name="custom_seekbar_value">Value: <xliff:g id="v">%s</xliff:g></string>
<string name="custom_seekbar_default_value">by default</string>
<string name="custom_seekbar_default_value_to_set">Default value: <xliff:g id="v">%s</xliff:g>\nLong tap to set</string>
<string name="custom_seekbar_default_value_is_set">Default value is set</string>
</resources>

84
res/xml/main.xml Normal file
View File

@@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2023 The Evolution X Project
SPDX-License-Identifier: Apache-2.0
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res/org.evolution.pixelparts">
<com.android.settingslib.widget.TopIntroPreference
android:key="pixel_parts_intro"
android:title="@string/pixel_parts_summary"/>
<!-- Start of CPU category -->
<PreferenceCategory
android:key="category_cpu"
android:title="@string/category_cpu">
<SwitchPreference
android:key="power_efficient_workqueue"
android:title="@string/power_efficient_workqueue_title"
android:summary="@string/power_efficient_workqueue_summary" />
</PreferenceCategory>
<!-- Start of display category -->
<PreferenceCategory
android:key="category_display"
android:title="@string/category_display">
<SwitchPreference
android:key="hbm"
android:title="@string/hbm_title"
android:summary="@string/hbm_summary" />
<SwitchPreference
android:key="auto_hbm"
android:title="@string/auto_hbm_title"
android:summary="@string/auto_hbm_summary" />
<org.evolution.pixelparts.preferences.AutoHBMThresholdPreference
android:key="auto_hbm_threshold"
android:dependency="auto_hbm"
android:title="@string/auto_hbm_threshold_title"
android:summary="@string/auto_hbm_threshold_summary" />
<Preference
android:key="hbm_info"
android:icon="@drawable/ic_info_outline"
android:summary="@string/hbm_info"
android:persistent="false" />
</PreferenceCategory>
<!-- Start of UiBench Category -->
<PreferenceCategory
android:key="category_uibench"
android:title="@string/category_uibench">
<Preference
android:key="jitter"
android:title="@string/jitter_test_title"
android:summary="@string/jitter_test_summary"
android:persistent="false" >
<intent android:action="android.intent.action.MAIN"
android:targetPackage="org.evolution.pixelparts"
android:targetClass="org.evolution.pixelparts.uibench.JitterTestActivity" />
</Preference>
</PreferenceCategory>
<!-- Start of usb category -->
<PreferenceCategory
android:key="category_usb"
android:title="@string/category_usb">
<SwitchPreference
android:key="usb2_fast_charge"
android:title="@string/usb2_fast_charge_title"
android:summary="@string/usb2_fast_charge_summary" />
<Preference
android:key="usb2_fast_charge_info"
android:icon="@drawable/ic_info_outline"
android:summary="@string/usb2_fast_charge_info"
android:persistent="false" />
</PreferenceCategory>
</PreferenceScreen>

5
sepolicy/file.te Normal file
View File

@@ -0,0 +1,5 @@
# USB 2.0 force fast charge
type sysfs_fastcharge, fs_type, sysfs_type;
# Workqueue
type sysfs_workqueue, fs_type, sysfs_type;

2
sepolicy/file_contexts Normal file
View File

@@ -0,0 +1,2 @@
/sys/kernel/fast_charge/force_fast_charge u:object_r:sysfs_fastcharge:s0
/sys/module/workqueue/parameters/power_efficient u:object_r:sysfs_workqueue:s0

View File

@@ -0,0 +1,33 @@
type pixelparts_app, domain;
typeattribute pixelparts_app mlstrustedsubject;
app_domain(pixelparts_app)
allow pixelparts_app {
activity_service
activity_task_service
audio_service
autofill_service
content_capture_service
game_service
gpu_service
hint_service
media_session_service
netstats_service
permission_checker_service
surfaceflinger_service
}:service_manager find;
allow pixelparts_app system_app_data_file:dir create_dir_perms;
allow pixelparts_app system_app_data_file:{ file lnk_file } create_file_perms;
allow pixelparts_app system_data_file:dir search;
allow pixelparts_app {
sysfs_fastcharge
sysfs_leds
sysfs_workqueue
}:file rw_file_perms;
allow pixelparts_app {
sysfs_leds
}:dir r_dir_perms;

1
sepolicy/seapp_contexts Normal file
View File

@@ -0,0 +1 @@
user=system seinfo=platform name=org.evolution.pixelparts domain=pixelparts_app type=system_app_data_file

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2016 The CyanogenMod project
* 2017 The LineageOS Project
* 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.provider.SearchIndexableResource;
import android.provider.SearchIndexablesProvider;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_ICON_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_ACTION;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RANK;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
import static android.provider.SearchIndexablesContract.INDEXABLES_RAW_COLUMNS;
import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
import static android.provider.SearchIndexablesContract.NON_INDEXABLES_KEYS_COLUMNS;
public class ConfigPanelSearchIndexablesProvider extends SearchIndexablesProvider {
private static final String TAG = "ConfigPanelSearchIndexablesProvider";
public static final int SEARCH_IDX_BUTTON_PANEL = 0;
public static final int SEARCH_IDX_GESTURE_PANEL = 1;
public static final int SEARCH_IDX_OCLICK_PANEL = 2;
private static SearchIndexableResource[] INDEXABLE_RES = new SearchIndexableResource[]{
new SearchIndexableResource(1, R.xml.main,
PixelPartsActivity.class.getName(),
R.drawable.ic_pixel_parts),
};
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor queryXmlResources(String[] projection) {
MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
return cursor;
}
private static Object[] generateResourceRef(SearchIndexableResource sir) {
Object[] ref = new Object[7];
ref[COLUMN_INDEX_XML_RES_RANK] = sir.rank;
ref[COLUMN_INDEX_XML_RES_RESID] = sir.xmlResId;
ref[COLUMN_INDEX_XML_RES_CLASS_NAME] = null;
ref[COLUMN_INDEX_XML_RES_ICON_RESID] = sir.iconResId;
ref[COLUMN_INDEX_XML_RES_INTENT_ACTION] = "com.android.settings.action.EXTRA_SETTINGS";
ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_PACKAGE] = "org.evolution.pixelparts;";
ref[COLUMN_INDEX_XML_RES_INTENT_TARGET_CLASS] = sir.className;
return ref;
}
@Override
public Cursor queryRawData(String[] projection) {
MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
return cursor;
}
@Override
public Cursor queryNonIndexableKeys(String[] projection) {
MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS);
return cursor;
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (C) 2018-2022 crDroid Android Project
* 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import androidx.preference.PreferenceFragment;
import androidx.preference.PreferenceManager;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
import org.evolution.pixelparts.misc.Constants;
import org.evolution.pixelparts.R;
import org.evolution.pixelparts.services.HBMService;
import org.evolution.pixelparts.utils.AutoHBMUtils;
import org.evolution.pixelparts.utils.Utils;
public class PixelParts extends PreferenceFragment
implements Preference.OnPreferenceChangeListener {
private static final String TAG = PixelParts.class.getSimpleName();
// Power efficient workqueue switch
private SwitchPreference mPowerEfficientWorkqueueModeSwitch;
// High brightness mode switches
private SwitchPreference mHBMSwitch;
private SwitchPreference mAutoHBMSwitch;
// USB 2.0 fast charge switch
private SwitchPreference mUSB2FastChargeSwitch;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.main);
SharedPreferences prefs = getActivity().getSharedPreferences("main",
Activity.MODE_PRIVATE);
if (savedInstanceState == null && !prefs.getBoolean("first_warning_shown", false)) {
showWarning();
}
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
Context context = getContext();
// Power efficient workqueue switch
mPowerEfficientWorkqueueModeSwitch = (SwitchPreference) findPreference(Constants.KEY_POWER_EFFICIENT_WORKQUEUE);
if (Utils.isFileWritable(Constants.NODE_POWER_EFFICIENT_WORKQUEUE)) {
mPowerEfficientWorkqueueModeSwitch.setEnabled(true);
mPowerEfficientWorkqueueModeSwitch.setChecked(sharedPrefs.getBoolean(Constants.KEY_POWER_EFFICIENT_WORKQUEUE, false));
mPowerEfficientWorkqueueModeSwitch.setOnPreferenceChangeListener(this);
} else {
mPowerEfficientWorkqueueModeSwitch.setEnabled(false);
}
// High brightness mode switches
mHBMSwitch = (SwitchPreference) findPreference(Constants.KEY_HBM);
mAutoHBMSwitch = (SwitchPreference) findPreference(Constants.KEY_AUTO_HBM);
if (Utils.isFileWritable(Constants.NODE_HBM)) {
mHBMSwitch.setEnabled(true);
mHBMSwitch.setChecked(sharedPrefs.getBoolean(Constants.KEY_HBM, false));
mHBMSwitch.setOnPreferenceChangeListener(this);
mAutoHBMSwitch.setChecked(PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean(Constants.KEY_AUTO_HBM, false));
mAutoHBMSwitch.setOnPreferenceChangeListener(this);
} else {
mHBMSwitch.setEnabled(false);
mAutoHBMSwitch.setEnabled(false);
}
// USB 2.0 fast charge switch
mUSB2FastChargeSwitch = (SwitchPreference) findPreference(Constants.KEY_USB2_FAST_CHARGE);
if (Utils.isFileWritable(Constants.NODE_USB2_FAST_CHARGE)) {
mUSB2FastChargeSwitch.setEnabled(true);
mUSB2FastChargeSwitch.setChecked(sharedPrefs.getBoolean(Constants.KEY_USB2_FAST_CHARGE, false));
mUSB2FastChargeSwitch.setOnPreferenceChangeListener(this);
} else {
mUSB2FastChargeSwitch.setEnabled(false);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Power efficient workqueue switch
if (preference == mPowerEfficientWorkqueueModeSwitch) {
boolean enabled = (Boolean) newValue;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
sharedPrefs.edit().putBoolean(Constants.KEY_POWER_EFFICIENT_WORKQUEUE, enabled).commit();
Utils.writeValue(Constants.NODE_POWER_EFFICIENT_WORKQUEUE, enabled ? "1" : "0");
return true;
// High brightness mode switch
} else if (preference == mHBMSwitch) {
boolean enabled = (Boolean) newValue;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
sharedPrefs.edit().putBoolean(Constants.KEY_HBM, enabled).commit();
Utils.writeValue(Constants.NODE_HBM, enabled ? "1" : "0");
Intent hbmServiceIntent = new Intent(this.getContext(), HBMService.class);
if (enabled) {
this.getContext().startService(hbmServiceIntent);
} else {
this.getContext().stopService(hbmServiceIntent);
}
return true;
// Auto HBM switch
} else if (preference == mAutoHBMSwitch) {
Boolean enabled = (Boolean) newValue;
SharedPreferences.Editor prefChange = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
prefChange.putBoolean(Constants.KEY_AUTO_HBM, enabled).commit();
AutoHBMUtils.enableAutoHBM(getContext());
return true;
// USB 2.0 fast charge switch
} else if (preference == mUSB2FastChargeSwitch) {
boolean enabled = (Boolean) newValue;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
sharedPrefs.edit().putBoolean(Constants.KEY_USB2_FAST_CHARGE, enabled).commit();
Utils.writeValue(Constants.NODE_USB2_FAST_CHARGE, enabled ? "1" : "0");
return true;
}
return false;
}
public static boolean isAutoHBMEnabled(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(Constants.KEY_AUTO_HBM, false);
}
// Power efficient workqueue switch
public static void restorePowerEfficientWorkqueueSetting(Context context) {
if (Utils.isFileWritable(Constants.NODE_POWER_EFFICIENT_WORKQUEUE)) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean value = sharedPrefs.getBoolean(Constants.KEY_POWER_EFFICIENT_WORKQUEUE, false);
Utils.writeValue(Constants.NODE_POWER_EFFICIENT_WORKQUEUE, value ? "1" : "0");
}
}
// High brightness mode switch
public static void restoreHBMSetting(Context context) {
if (Utils.isFileWritable(Constants.NODE_HBM)) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean value = sharedPrefs.getBoolean(Constants.KEY_HBM, false);
Utils.writeValue(Constants.NODE_HBM, value ? "1" : "0");
}
}
// USB 2.0 fast charge switch
public static void restoreUSB2FastChargeSetting(Context context) {
if (Utils.isFileWritable(Constants.NODE_USB2_FAST_CHARGE)) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean value = sharedPrefs.getBoolean(Constants.KEY_USB2_FAST_CHARGE, false);
Utils.writeValue(Constants.NODE_USB2_FAST_CHARGE, value ? "1" : "0");
}
}
// First launch warning dialog
public static class WarningDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.pixel_parts_warning_title)
.setMessage(R.string.pixel_parts_warning_text)
.setNegativeButton(R.string.pixel_parts_dialog, (dialog, which) -> dialog.cancel())
.create();
}
@Override
public void onCancel(DialogInterface dialog) {
getActivity().getSharedPreferences("main", Activity.MODE_PRIVATE)
.edit()
.putBoolean("first_warning_shown", true)
.commit();
}
}
private void showWarning() {
WarningDialogFragment fragment = new WarningDialogFragment();
fragment.show(getFragmentManager(), "warning_dialog");
}
}

View File

@@ -0,0 +1,92 @@
/*
* Copyright (C) 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts;
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.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.Menu;
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.widget.R;
import java.util.Arrays;
import java.util.Random;
import com.plattysoft.leonids.ParticleSystem;
import org.evolution.pixelparts.utils.ShakeUtils;
public class PixelPartsActivity extends CollapsingToolbarBaseActivity
implements ShakeUtils.OnShakeListener {
private static final String TAG = "PixelParts";
private ShakeUtils mShakeUtils;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(R.id.content_frame,
new PixelParts(), TAG).commit();
mShakeUtils = new ShakeUtils(this);
}
@Override
protected void onResume() {
super.onResume();
mShakeUtils.bindShakeListener(this);
}
@Override
protected void onStop() {
super.onStop();
mShakeUtils.unBindShakeListener(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
mShakeUtils.unBindShakeListener(this);
}
@Override
public void onShake(double speed) {
Random rand = new Random();
int firstRandom = rand.nextInt(91-0);
int secondRandom = rand.nextInt(181-90)+90;
int thirdRandom = rand.nextInt(181-0);
Drawable easteregg = getResources().getDrawable(R.drawable.easteregg,null);
int randomColor;
randomColor = Color.rgb(
Color.red(rand.nextInt(0xFFFFFF)),
Color.green(rand.nextInt(0xFFFFFF)),
Color.blue(rand.nextInt(0xFFFFFF)));
easteregg.setTint(randomColor);
ParticleSystem ps = new ParticleSystem(this, 50, easteregg, 2000);
ps.setScaleRange(0.7f,1.3f);
ps.setSpeedRange(0.1f,0.25f);
ps.setAcceleration(0.0001f,thirdRandom);
ps.setRotationSpeedRange(firstRandom,secondRandom);
ps.setFadeOut(300);
ps.oneShot(this.findViewById(android.R.id.content),50);
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2018-2022 crDroid Android Project
* 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
public class Startup extends BroadcastReceiver {
private static final String TAG = Startup.class.getSimpleName();
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
// PixelParts
PixelParts.restorePowerEfficientWorkqueueSetting(context);
PixelParts.restoreHBMSetting(context);
PixelParts.restoreUSB2FastChargeSetting(context);
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts.misc;
public class Constants {
// Power efficient workqueue switch
public static final String KEY_POWER_EFFICIENT_WORKQUEUE = "power_efficient_workqueue";
public static final String NODE_POWER_EFFICIENT_WORKQUEUE = "/sys/module/workqueue/parameters/power_efficient";
// High brightness mode switches
public static final String KEY_HBM = "hbm";
public static final String KEY_AUTO_HBM = "auto_hbm";
public static final String KEY_AUTO_HBM_THRESHOLD = "auto_hbm_threshold";
public static final String NODE_HBM = "/sys/class/backlight/panel0-backlight/hbm_mode";
// USB 2.0 fast charge switch
public static final String KEY_USB2_FAST_CHARGE = "usb2_fast_charge";
public static final String NODE_USB2_FAST_CHARGE = "/sys/kernel/fast_charge/force_fast_charge";
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2016 The OmniROM Project
* SPDX-License-Identifier: GPL-2.0-or-later
*/
package org.evolution.pixelparts.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceViewHolder;
import org.evolution.pixelparts.misc.Constants;
public class AutoHBMThresholdPreference extends CustomSeekBarPreference {
private static int mMinVal = 2000;
private static int mMaxVal = 60000;
private static int mDefVal = 20000;
public AutoHBMThresholdPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mInterval = 1000;
mShowSign = false;
mUnits = "";
mContinuousUpdates = false;
mMinValue = mMinVal;
mMaxValue = mMaxVal;
mDefaultValueExists = true;
mDefaultValue = mDefVal;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
mValue = Integer.parseInt(sharedPrefs.getString(Constants.KEY_AUTO_HBM_THRESHOLD, "20000"));
setPersistent(false);
}
@Override
protected void changeValue(int newValue) {
SharedPreferences.Editor prefChange = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
prefChange.putString(Constants.KEY_AUTO_HBM_THRESHOLD, String.valueOf(newValue)).commit();
}
}

View File

@@ -0,0 +1,357 @@
/*
* Copyright (C) 2016-2022 crDroid Android Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts.preferences;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PorterDuff;
import androidx.core.content.res.TypedArrayUtils;
import androidx.preference.*;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import org.evolution.pixelparts.R;
public class CustomSeekBarPreference extends Preference implements SeekBar.OnSeekBarChangeListener {
protected final String TAG = getClass().getName();
private static final String SETTINGS_NS = "http://schemas.android.com/apk/res/com.android.settings";
protected static final String ANDROIDNS = "http://schemas.android.com/apk/res/android";
protected int mInterval = 1;
protected boolean mShowSign = false;
protected String mUnits = "";
protected boolean mContinuousUpdates = false;
protected int mMinValue = 0;
protected int mMaxValue = 100;
protected boolean mDefaultValueExists = false;
protected int mDefaultValue;
protected boolean mDefaultValueTextExists = false;
protected String mDefaultValueText;
protected int mValue;
protected TextView mValueTextView;
protected ImageView mResetImageView;
protected ImageView mMinusImageView;
protected ImageView mPlusImageView;
protected SeekBar mSeekBar;
protected boolean mTrackingTouch = false;
protected int mTrackingValue;
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomSeekBarPreference);
try {
mShowSign = a.getBoolean(R.styleable.CustomSeekBarPreference_showSign, mShowSign);
String units = a.getString(R.styleable.CustomSeekBarPreference_units);
if (units != null)
mUnits = " " + units;
mContinuousUpdates = a.getBoolean(R.styleable.CustomSeekBarPreference_continuousUpdates, mContinuousUpdates);
String defaultValueText = a.getString(R.styleable.CustomSeekBarPreference_defaultValueText);
mDefaultValueTextExists = defaultValueText != null && !defaultValueText.isEmpty();
if (mDefaultValueTextExists) {
mDefaultValueText = defaultValueText;
}
} finally {
a.recycle();
}
try {
String newInterval = attrs.getAttributeValue(SETTINGS_NS, "interval");
if (newInterval != null)
mInterval = Integer.parseInt(newInterval);
} catch (Exception e) {
Log.e(TAG, "Invalid interval value", e);
}
mMinValue = attrs.getAttributeIntValue(SETTINGS_NS, "min", mMinValue);
mMaxValue = attrs.getAttributeIntValue(ANDROIDNS, "max", mMaxValue);
if (mMaxValue < mMinValue)
mMaxValue = mMinValue;
String defaultValue = attrs.getAttributeValue(ANDROIDNS, "defaultValue");
mDefaultValueExists = defaultValue != null && !defaultValue.isEmpty();
if (mDefaultValueExists) {
mDefaultValue = getLimitedValue(Integer.parseInt(defaultValue));
mValue = mDefaultValue;
} else {
mValue = mMinValue;
}
mSeekBar = new SeekBar(context, attrs);
setLayoutResource(R.layout.preference_custom_seekbar);
}
public CustomSeekBarPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CustomSeekBarPreference(Context context, AttributeSet attrs) {
this(context, attrs, TypedArrayUtils.getAttr(context,
androidx.preference.R.attr.preferenceStyle,
android.R.attr.preferenceStyle));
}
public CustomSeekBarPreference(Context context) {
this(context, null);
}
@Override
public void onDependencyChanged(Preference dependency, boolean disableDependent) {
super.onDependencyChanged(dependency, disableDependent);
this.setShouldDisableView(true);
if (mSeekBar != null)
mSeekBar.setEnabled(!disableDependent);
if (mResetImageView != null)
mResetImageView.setEnabled(!disableDependent);
if (mPlusImageView != null)
mPlusImageView.setEnabled(!disableDependent);
if (mMinusImageView != null)
mMinusImageView.setEnabled(!disableDependent);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
try
{
// move our seekbar to the new view we've been given
ViewParent oldContainer = mSeekBar.getParent();
ViewGroup newContainer = (ViewGroup) holder.findViewById(R.id.seekbar);
if (oldContainer != newContainer) {
// remove the seekbar from the old view
if (oldContainer != null) {
((ViewGroup) oldContainer).removeView(mSeekBar);
}
// remove the existing seekbar (there may not be one) and add ours
newContainer.removeAllViews();
newContainer.addView(mSeekBar, ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
} catch (Exception ex) {
Log.e(TAG, "Error binding view: " + ex.toString());
}
mSeekBar.setMax(getSeekValue(mMaxValue));
mSeekBar.setProgress(getSeekValue(mValue));
mSeekBar.setEnabled(isEnabled());
mValueTextView = (TextView) holder.findViewById(R.id.value);
mResetImageView = (ImageView) holder.findViewById(R.id.reset);
mMinusImageView = (ImageView) holder.findViewById(R.id.minus);
mPlusImageView = (ImageView) holder.findViewById(R.id.plus);
updateValueViews();
mSeekBar.setOnSeekBarChangeListener(this);
mResetImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getContext(), getContext().getString(R.string.custom_seekbar_default_value_to_set, getTextValue(mDefaultValue)),
Toast.LENGTH_LONG).show();
}
});
mResetImageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
setValue(mDefaultValue, true);
return true;
}
});
mMinusImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setValue(mValue - mInterval, true);
}
});
mMinusImageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
setValue(mMaxValue - mMinValue > mInterval * 2 && mMaxValue + mMinValue < mValue * 2 ? Math.floorDiv(mMaxValue + mMinValue, 2) : mMinValue, true);
return true;
}
});
mPlusImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
setValue(mValue + mInterval, true);
}
});
mPlusImageView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
setValue(mMaxValue - mMinValue > mInterval * 2 && mMaxValue + mMinValue > mValue * 2 ? -1 * Math.floorDiv(-1 * (mMaxValue + mMinValue), 2) : mMaxValue, true);
return true;
}
});
}
protected int getLimitedValue(int v) {
return v < mMinValue ? mMinValue : (v > mMaxValue ? mMaxValue : v);
}
protected int getSeekValue(int v) {
return 0 - Math.floorDiv(mMinValue - v, mInterval);
}
protected String getTextValue(int v) {
if (mDefaultValueTextExists && mDefaultValueExists && v == mDefaultValue) {
return mDefaultValueText;
}
return (mShowSign && v > 0 ? "+" : "") + String.valueOf(v) + mUnits;
}
protected void updateValueViews() {
if (mValueTextView != null) {
if (!mTrackingTouch || mContinuousUpdates) {
if (mDefaultValueTextExists && mDefaultValueExists && mValue == mDefaultValue) {
mValueTextView.setText(mDefaultValueText + " (" +
getContext().getString(R.string.custom_seekbar_default_value) + ")");
} else {
mValueTextView.setText(getContext().getString(R.string.custom_seekbar_value, getTextValue(mValue)) +
(mDefaultValueExists && mValue == mDefaultValue ? " (" +
getContext().getString(R.string.custom_seekbar_default_value) + ")" : ""));
}
} else {
if (mDefaultValueTextExists && mDefaultValueExists && mTrackingValue == mDefaultValue) {
mValueTextView.setText("[" + mDefaultValueText + "]");
} else {
mValueTextView.setText(getContext().getString(R.string.custom_seekbar_value, "[" + getTextValue(mTrackingValue) + "]"));
}
}
}
if (mResetImageView != null) {
if (!mDefaultValueExists || mValue == mDefaultValue || mTrackingTouch)
mResetImageView.setVisibility(View.INVISIBLE);
else
mResetImageView.setVisibility(View.VISIBLE);
}
if (mMinusImageView != null) {
if (mValue == mMinValue || mTrackingTouch) {
mMinusImageView.setClickable(false);
mMinusImageView.setColorFilter(getContext().getColor(R.color.disabled_text_color),
PorterDuff.Mode.MULTIPLY);
} else {
mMinusImageView.setClickable(true);
mMinusImageView.clearColorFilter();
}
}
if (mPlusImageView != null) {
if (mValue == mMaxValue || mTrackingTouch) {
mPlusImageView.setClickable(false);
mPlusImageView.setColorFilter(getContext().getColor(R.color.disabled_text_color), PorterDuff.Mode.MULTIPLY);
} else {
mPlusImageView.setClickable(true);
mPlusImageView.clearColorFilter();
}
}
}
protected void changeValue(int newValue) {
// for subclasses
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int newValue = getLimitedValue(mMinValue + (progress * mInterval));
if (mTrackingTouch && !mContinuousUpdates) {
mTrackingValue = newValue;
updateValueViews();
} else if (mValue != newValue) {
// change rejected, revert to the previous value
if (!callChangeListener(newValue)) {
mSeekBar.setProgress(getSeekValue(mValue));
return;
}
// change accepted, store it
changeValue(newValue);
persistInt(newValue);
mValue = newValue;
updateValueViews();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
mTrackingValue = mValue;
mTrackingTouch = true;
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
mTrackingTouch = false;
if (!mContinuousUpdates)
onProgressChanged(mSeekBar, getSeekValue(mTrackingValue), false);
notifyChanged();
}
@Override
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
if (restoreValue)
mValue = getPersistedInt(mValue);
}
@Override
public void setDefaultValue(Object defaultValue) {
if (defaultValue instanceof Integer)
setDefaultValue((Integer) defaultValue, mSeekBar != null);
else
setDefaultValue(defaultValue == null ? (String) null : defaultValue.toString(), mSeekBar != null);
}
public void setDefaultValue(int newValue, boolean update) {
newValue = getLimitedValue(newValue);
if (!mDefaultValueExists || mDefaultValue != newValue) {
mDefaultValueExists = true;
mDefaultValue = newValue;
if (update)
updateValueViews();
}
}
public void setDefaultValue(String newValue, boolean update) {
if (mDefaultValueExists && (newValue == null || newValue.isEmpty())) {
mDefaultValueExists = false;
if (update)
updateValueViews();
} else if (newValue != null && !newValue.isEmpty()) {
setDefaultValue(Integer.parseInt(newValue), update);
}
}
public void setValue(int newValue) {
mValue = getLimitedValue(newValue);
if (mSeekBar != null) mSeekBar.setProgress(getSeekValue(mValue));
}
public void setValue(int newValue, boolean update) {
newValue = getLimitedValue(newValue);
if (mValue != newValue) {
if (update)
mSeekBar.setProgress(getSeekValue(newValue));
else
mValue = newValue;
}
}
public int getValue() {
return mValue;
}
public void refresh(int newValue) {
// this will ...
setValue(newValue, mSeekBar != null);
}
}

View File

@@ -0,0 +1,125 @@
package org.evolution.pixelparts.services;
import android.app.KeyguardManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.IBinder;
import android.os.PowerManager;
import androidx.preference.PreferenceManager;
import org.evolution.pixelparts.misc.Constants;
import org.evolution.pixelparts.utils.Utils;
public class AutoHBMService extends Service {
private static boolean mAutoHBMActive = false;
private SensorManager mSensorManager;
Sensor mLightSensor;
private SharedPreferences mSharedPrefs;
public void activateLightSensorRead() {
mSensorManager = (SensorManager) getApplicationContext().getSystemService(Context.SENSOR_SERVICE);
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
mSensorManager.registerListener(mSensorEventListener, mLightSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
public void deactivateLightSensorRead() {
mSensorManager.unregisterListener(mSensorEventListener);
mAutoHBMActive = false;
enableHBM(false);
}
private void enableHBM(boolean enable) {
if (enable) {
Utils.writeValue(Constants.NODE_HBM, "1");
} else {
Utils.writeValue(Constants.NODE_HBM, "0");
}
}
private boolean isCurrentlyEnabled() {
String fileValue = Utils.getFileValue(Constants.NODE_HBM, "0");
return fileValue.equals("1") ? true : false;
}
SensorEventListener mSensorEventListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
float lux = event.values[0];
KeyguardManager km =
(KeyguardManager) getSystemService(getApplicationContext().KEYGUARD_SERVICE);
boolean keyguardShowing = km.inKeyguardRestrictedInputMode();
float threshold = Float.parseFloat(mSharedPrefs.getString(Constants.KEY_AUTO_HBM_THRESHOLD, "20000"));
if (lux > threshold) {
if ((!mAutoHBMActive | !isCurrentlyEnabled()) && !keyguardShowing) {
mAutoHBMActive = true;
enableHBM(true);
}
}
if (lux < threshold) {
if (mAutoHBMActive) {
mAutoHBMActive = false;
enableHBM(false);
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// do nothing
}
};
private BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
activateLightSensorRead();
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
deactivateLightSensorRead();
}
}
};
@Override
public void onCreate() {
IntentFilter screenStateFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenStateReceiver, screenStateFilter);
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm.isInteractive()) {
activateLightSensorRead();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mScreenStateReceiver);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm.isInteractive()) {
deactivateLightSensorRead();
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts.services;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.preference.PreferenceManager;
import org.evolution.pixelparts.misc.Constants;
public class HBMService extends Service {
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF)) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(Constants.KEY_HBM, false);
editor.commit();
stopSelf();
}
}
};
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(mReceiver, intentFilter);
return START_REDELIVER_INTENT;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
unregisterReceiver(mReceiver);
super.onDestroy();
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts.services;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.BroadcastReceiver;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import androidx.preference.PreferenceManager;
import org.evolution.pixelparts.misc.Constants;
import org.evolution.pixelparts.utils.Utils;
public class HBMTileService extends TileService {
private BroadcastReceiver screenStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
sharedPrefs.edit().putBoolean(Constants.KEY_HBM, false).commit();
updateTile(false);
}
}
};
private void updateTile(boolean enabled) {
final Tile tile = getQsTile();
tile.setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
tile.updateTile();
}
@Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(screenStateReceiver, filter);
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(screenStateReceiver);
}
@Override
public void onStartListening() {
super.onStartListening();
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
updateTile(sharedPrefs.getBoolean(Constants.KEY_HBM, false));
}
@Override
public void onStopListening() {
super.onStopListening();
}
@Override
public void onClick() {
super.onClick();
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
final boolean enabled = !(sharedPrefs.getBoolean(Constants.KEY_HBM, false));
Utils.writeValue(Constants.NODE_HBM, enabled ? "1" : "0");
sharedPrefs.edit().putBoolean(Constants.KEY_HBM, enabled).commit();
updateTile(enabled);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts.services;
import android.content.SharedPreferences;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import androidx.preference.PreferenceManager;
import org.evolution.pixelparts.misc.Constants;
import org.evolution.pixelparts.utils.Utils;
public class PEWQTileSerice extends TileService {
private void updateTile(boolean enabled) {
final Tile tile = getQsTile();
tile.setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
tile.updateTile();
}
@Override
public void onStartListening() {
super.onStartListening();
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
updateTile(sharedPrefs.getBoolean(Constants.KEY_POWER_EFFICIENT_WORKQUEUE, false));
}
@Override
public void onStopListening() {
super.onStopListening();
}
@Override
public void onClick() {
super.onClick();
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
final boolean enabled = !(sharedPrefs.getBoolean(Constants.KEY_POWER_EFFICIENT_WORKQUEUE, false));
Utils.writeValue(Constants.NODE_POWER_EFFICIENT_WORKQUEUE, enabled ? "1" : "0");
sharedPrefs.edit().putBoolean(Constants.KEY_POWER_EFFICIENT_WORKQUEUE, enabled).commit();
updateTile(enabled);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 The Evolution X Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts.services;
import android.content.SharedPreferences;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import androidx.preference.PreferenceManager;
import org.evolution.pixelparts.misc.Constants;
import org.evolution.pixelparts.utils.Utils;
public class USB2FCTileService extends TileService {
private void updateTile(boolean enabled) {
final Tile tile = getQsTile();
tile.setState(enabled ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
tile.updateTile();
}
@Override
public void onStartListening() {
super.onStartListening();
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
updateTile(sharedPrefs.getBoolean(Constants.KEY_USB2_FAST_CHARGE, false));
}
@Override
public void onStopListening() {
super.onStopListening();
}
@Override
public void onClick() {
super.onClick();
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
final boolean enabled = !(sharedPrefs.getBoolean(Constants.KEY_USB2_FAST_CHARGE, false));
Utils.writeValue(Constants.NODE_USB2_FAST_CHARGE, enabled ? "1" : "0");
sharedPrefs.edit().putBoolean(Constants.KEY_USB2_FAST_CHARGE, enabled).commit();
updateTile(enabled);
}
}

View File

@@ -0,0 +1,357 @@
/*
* Copyright (C) 2016 The Android Open Source Project
* SPDX-License-Identifier: GPL-2.0-or-later
*/
package org.evolution.pixelparts.uibench;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.util.AttributeSet;
import android.view.FrameMetrics;
import android.view.View;
import android.view.Window;
import android.view.Window.OnFrameMetricsAvailableListener;
import android.view.animation.AnimationUtils;
import android.widget.TextView;
import org.evolution.pixelparts.R;
public class JitterTestActivity extends Activity {
private TextView mJitterReport;
private TextView mUiFrameTimeReport;
private TextView mRenderThreadTimeReport;
private TextView mTotalFrameTimeReport;
private TextView mMostlyTotalFrameTimeReport;
private PointGraphView mGraph;
private static Handler sMetricsHandler;
static {
HandlerThread thread = new HandlerThread("frameMetricsListener");
thread.start();
sMetricsHandler = new Handler(thread.getLooper());
}
private Handler mUpdateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case R.id.jitter_mma:
mJitterReport.setText((CharSequence) msg.obj);
break;
case R.id.totalish_mma:
mMostlyTotalFrameTimeReport.setText((CharSequence) msg.obj);
break;
case R.id.ui_frametime_mma:
mUiFrameTimeReport.setText((CharSequence) msg.obj);
break;
case R.id.rt_frametime_mma:
mRenderThreadTimeReport.setText((CharSequence) msg.obj);
break;
case R.id.total_mma:
mTotalFrameTimeReport.setText((CharSequence) msg.obj);
break;
case R.id.graph:
mGraph.addJitterSample(msg.arg1, msg.arg2);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.rendering_jitter);
View content = findViewById(android.R.id.content);
content.setBackground(new AnimatedBackgroundDrawable());
content.setKeepScreenOn(true);
mJitterReport = findViewById(R.id.jitter_mma);
mMostlyTotalFrameTimeReport = findViewById(R.id.totalish_mma);
mUiFrameTimeReport = findViewById(R.id.ui_frametime_mma);
mRenderThreadTimeReport = findViewById(R.id.rt_frametime_mma);
mTotalFrameTimeReport = findViewById(R.id.total_mma);
mGraph = findViewById(R.id.graph);
mJitterReport.setText("abcdefghijklmnopqrstuvwxyz");
mMostlyTotalFrameTimeReport.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
mUiFrameTimeReport.setText("0123456789");
mRenderThreadTimeReport.setText(",.!()[]{};");
getWindow().addOnFrameMetricsAvailableListener(mMetricsListener, sMetricsHandler);
}
public static final class PointGraphView extends View {
private static final float[] JITTER_LINES_MS = {
.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 5.0f
};
private static final String[] JITTER_LINES_LABELS = makeLabels(JITTER_LINES_MS);
private static final int[] JITTER_LINES_COLORS = new int[] {
0xFF00E676, 0xFFFFF176, 0xFFFDD835, 0xFFFBC02D, 0xFFF9A825,
0xFFF57F17, 0xFFDD2C00
};
private Paint mPaint = new Paint();
private float[] mJitterYs = new float[JITTER_LINES_MS.length];
private float mLabelWidth;
private float mLabelHeight;
private float mDensity;
private float mGraphScale;
private float mGraphMaxMs;
private float[] mJitterPoints;
private float[] mJitterAvgPoints;
public PointGraphView(Context context, AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
mDensity = context.getResources().getDisplayMetrics().density;
mPaint.setTextSize(dp(10));
Rect textBounds = new Rect();
mPaint.getTextBounds("8.8", 0, 3, textBounds);
mLabelWidth = textBounds.width() + dp(2);
mLabelHeight = textBounds.height();
}
public void addJitterSample(int jitterUs, int jitterUsAvg) {
for (int i = 1; i < mJitterPoints.length - 2; i += 2) {
mJitterPoints[i] = mJitterPoints[i + 2];
mJitterAvgPoints[i] = mJitterAvgPoints[i + 2];
}
mJitterPoints[mJitterPoints.length - 1] =
getHeight() - mGraphScale * (jitterUs / 1000.0f);
mJitterAvgPoints[mJitterAvgPoints.length - 1] =
getHeight() - mGraphScale * (jitterUsAvg / 1000.0f);
invalidate();
}
private float dp(float dp) {
return mDensity * dp;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(0x90000000);
int h = getHeight();
int w = getWidth();
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(dp(1));
canvas.drawLine(mLabelWidth, 0, mLabelWidth, h, mPaint);
for (int i = 0; i < JITTER_LINES_LABELS.length; i++) {
canvas.drawText(JITTER_LINES_LABELS[i],
0, (float) Math.floor(mJitterYs[i] + mLabelHeight * .5f), mPaint);
}
for (int i = 0; i < JITTER_LINES_LABELS.length; i++) {
mPaint.setColor(JITTER_LINES_COLORS[i]);
canvas.drawLine(mLabelWidth, mJitterYs[i], w, mJitterYs[i], mPaint);
}
mPaint.setStrokeWidth(dp(2));
mPaint.setColor(Color.WHITE);
canvas.drawPoints(mJitterPoints, mPaint);
mPaint.setColor(0xFF2196F3);
canvas.drawPoints(mJitterAvgPoints, mPaint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int graphWidth = (int) ((w - mLabelWidth - dp(1)) / mDensity);
float[] oldJitterPoints = mJitterPoints;
float[] oldJitterAvgPoints = mJitterAvgPoints;
mJitterPoints = new float[graphWidth * 2];
mJitterAvgPoints = new float[graphWidth * 2];
for (int i = 0; i < mJitterPoints.length; i += 2) {
mJitterPoints[i] = mLabelWidth + (i / 2 + 1) * mDensity;
mJitterAvgPoints[i] = mJitterPoints[i];
}
if (oldJitterPoints != null) {
int newIndexShift = Math.max(mJitterPoints.length - oldJitterPoints.length, 0);
int oldIndexShift = oldJitterPoints.length - mJitterPoints.length;
for (int i = 1 + newIndexShift; i < mJitterPoints.length; i += 2) {
mJitterPoints[i] = oldJitterPoints[i + oldIndexShift];
mJitterAvgPoints[i] = oldJitterAvgPoints[i + oldIndexShift];
}
}
mGraphMaxMs = JITTER_LINES_MS[JITTER_LINES_MS.length - 1] + .5f;
mGraphScale = (h / mGraphMaxMs);
for (int i = 0; i < JITTER_LINES_MS.length; i++) {
mJitterYs[i] = (float) Math.floor(h - mGraphScale * JITTER_LINES_MS[i]);
}
}
private static String[] makeLabels(float[] divisions) {
String[] ret = new String[divisions.length];
for (int i = 0; i < divisions.length; i++) {
ret[i] = Float.toString(divisions[i]);
}
return ret;
}
}
private final OnFrameMetricsAvailableListener mMetricsListener = new OnFrameMetricsAvailableListener() {
private final static double WEIGHT = 40;
private long mPreviousFrameTotal;
private double mJitterMma;
private double mUiFrametimeMma;
private double mRtFrametimeMma;
private double mTotalFrametimeMma;
private double mMostlyTotalFrametimeMma;
private boolean mNeedsFirstValues = true;
@Override
public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
int dropCountSinceLastInvocation) {
if (frameMetrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1) {
return;
}
long uiDuration = frameMetrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION)
+ frameMetrics.getMetric(FrameMetrics.ANIMATION_DURATION)
+ frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)
+ frameMetrics.getMetric(FrameMetrics.DRAW_DURATION);
long rtDuration = frameMetrics.getMetric(FrameMetrics.SYNC_DURATION)
+ frameMetrics.getMetric(FrameMetrics.COMMAND_ISSUE_DURATION);
long totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION);
long jitter = Math.abs(totalDuration - mPreviousFrameTotal);
if (mNeedsFirstValues) {
mJitterMma = 0;
mUiFrametimeMma = uiDuration;
mRtFrametimeMma = rtDuration;
mTotalFrametimeMma = totalDuration;
mMostlyTotalFrametimeMma = uiDuration + rtDuration;
mNeedsFirstValues = false;
} else {
mJitterMma = add(mJitterMma, jitter);
mUiFrametimeMma = add(mUiFrametimeMma, uiDuration);
mRtFrametimeMma = add(mRtFrametimeMma, rtDuration);
mTotalFrametimeMma = add(mTotalFrametimeMma, totalDuration);
mMostlyTotalFrametimeMma = add(mMostlyTotalFrametimeMma, uiDuration + rtDuration);
}
mPreviousFrameTotal = totalDuration;
mUpdateHandler.obtainMessage(R.id.jitter_mma,
String.format("Jitter: %.3fms", toMs(mJitterMma))).sendToTarget();
mUpdateHandler.obtainMessage(R.id.totalish_mma,
String.format("CPU-total duration: %.3fms", toMs(mMostlyTotalFrametimeMma))).sendToTarget();
mUpdateHandler.obtainMessage(R.id.ui_frametime_mma,
String.format("UI duration: %.3fms", toMs(mUiFrametimeMma))).sendToTarget();
mUpdateHandler.obtainMessage(R.id.rt_frametime_mma,
String.format("RT duration: %.3fms", toMs(mRtFrametimeMma))).sendToTarget();
mUpdateHandler.obtainMessage(R.id.total_mma,
String.format("Total duration: %.3fms", toMs(mTotalFrametimeMma))).sendToTarget();
mUpdateHandler.obtainMessage(R.id.graph, (int) (jitter / 1000),
(int) (mJitterMma / 1000)).sendToTarget();
}
double add(double previous, double today) {
return (((WEIGHT - 1) * previous) + today) / WEIGHT;
}
double toMs(double val) {
return val / 1000000;
}
};
private static final class AnimatedBackgroundDrawable extends Drawable {
private static final int FROM_COLOR = 0xFF18FFFF;
private static final int TO_COLOR = 0xFF40C4FF;
private static final int DURATION = 1400;
private final Paint mPaint;
private boolean mReverse;
private long mStartTime;
private int mColor;
private boolean mReverseX;
private boolean mReverseY;
private float mX;
private float mY;
private float mRadius;
private float mMoveStep = 10.0f;
public AnimatedBackgroundDrawable() {
mPaint = new Paint();
mPaint.setColor(0xFFFFFF00);
mPaint.setAntiAlias(true);
}
@Override
public void draw(Canvas canvas) {
stepColor();
canvas.drawColor(mColor);
mX += (mReverseX ? -mMoveStep : mMoveStep);
mY += (mReverseY ? -mMoveStep : mMoveStep);
clampXY();
canvas.drawCircle(mX, mY, mRadius, mPaint);
invalidateSelf();
}
private void clampXY() {
if (mX <= mRadius) {
mReverseX = false;
mX = mRadius;
}
if (mY <= mRadius) {
mReverseY = false;
mY = mRadius;
}
float maxX = getBounds().width() - mRadius;
if (mX >= maxX) {
mReverseX = true;
mX = maxX;
}
float maxY = getBounds().height() - mRadius;
if (mY >= maxY) {
mReverseY = true;
mY = maxY;
}
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mMoveStep = Math.min(bounds.width(), bounds.height()) / 130.0f;
mRadius = Math.min(bounds.width(), bounds.height()) / 20.0f;
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
private void stepColor() {
if (mStartTime == 0) {
mStartTime = AnimationUtils.currentAnimationTimeMillis();
}
float frac = (AnimationUtils.currentAnimationTimeMillis() - mStartTime)
/ (float) DURATION;
if (frac > 1.0f) frac = 1.0f;
int dest = mReverse ? FROM_COLOR : TO_COLOR;
int src = mReverse ? TO_COLOR : FROM_COLOR;
int r = (int) (Color.red(src) + (Color.red(dest) - Color.red(src)) * frac);
int g = (int) (Color.green(src) + (Color.green(dest) - Color.green(src)) * frac);
int b = (int) (Color.blue(src) + (Color.blue(dest) - Color.blue(src)) * frac);
mColor = Color.rgb(r, g, b);
if (frac == 1.0f) {
mStartTime = 0;
mReverse = !mReverse;
}
}
}
}

View File

@@ -0,0 +1,33 @@
package org.evolution.pixelparts.utils;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import org.evolution.pixelparts.services.AutoHBMService;
import org.evolution.pixelparts.PixelParts;
public class AutoHBMUtils {
private static boolean mAutoHBMEnabled = false;
private static void startAutoHBM(Context context) {
context.startServiceAsUser(new Intent(context, AutoHBMService.class),
UserHandle.CURRENT);
mAutoHBMEnabled = true;
}
private static void stopAutoHBM(Context context) {
mAutoHBMEnabled = false;
context.stopServiceAsUser(new Intent(context, AutoHBMService.class),
UserHandle.CURRENT);
}
public static void enableAutoHBM(Context context) {
if (PixelParts.isAutoHBMEnabled(context) && !mAutoHBMEnabled) {
startAutoHBM(context);
} else if (!PixelParts.isAutoHBMEnabled(context) && mAutoHBMEnabled) {
stopAutoHBM(context);
}
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2021-2022 Miku UI
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts.utils;
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import kotlin.math.sqrt
class ShakeUtils(context: Context) : SensorEventListener {
private var mOnShakeListeners: ArrayList<OnShakeListener>? = null
// Last time we triggered shake
private var mLastShakeTime = 0L
private var mLastUpdateTime = 0L
// Last position we triggered shake
private var mLastX = 0f
private var mLastY = 0f
private var mLastZ = 0f
interface OnShakeListener {
fun onShake(speed: Double)
}
fun bindShakeListener(listener: OnShakeListener?) {
if (listener != null) {
mOnShakeListeners?.add(listener)
}
}
fun unBindShakeListener(listener: OnShakeListener) {
mOnShakeListeners?.remove(listener)
}
override fun onSensorChanged(event: SensorEvent) {
if (event == null) {
return
}
val curUpdateTime = System.currentTimeMillis()
// Times between two shakes
val timeInterval = curUpdateTime - mLastUpdateTime
if (timeInterval < SHAKE_INTERVAL_MILLISECOND) {
return
}
if (event.values.size < 3) {
return
}
mLastUpdateTime = curUpdateTime
val x = event.values[0]
val y = event.values[1]
val z = event.values[2]
val deltaX = x - mLastX
val deltaY = y - mLastY
val deltaZ = z - mLastZ
mLastX = x
mLastY = y
mLastZ = z
val speed =
sqrt((deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ).toDouble()) * 1000.0 / timeInterval
if (speed >= SPEED_SHAKE_MILLISECONDS) {
startShake(speed)
}
}
private fun startShake(speed: Double) {
val curShakeTime = System.currentTimeMillis()
if (curShakeTime - mLastShakeTime < MIN_SHAKE_INTERVAL) {
return
}
mLastShakeTime = curShakeTime
mOnShakeListeners?.let {
for (i in it.indices) {
it[i].onShake(speed)
}
}
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
companion object {
// Minimal time interval of position changes
private const val MIN_SHAKE_INTERVAL = 1024
// Minimal shake speed
private const val SPEED_SHAKE_MILLISECONDS = 400
// Minimal time interval between two shakes
private const val SHAKE_INTERVAL_MILLISECOND = 55
}
init {
val mSensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI)
mOnShakeListeners = ArrayList()
}
}

View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* 2018-2022 crDroid Android Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.evolution.pixelparts.utils;
import android.content.Context;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
import org.evolution.pixelparts.R;
import android.util.Log;
public class Utils {
private static final String TAG = Utils.class.getSimpleName();
/**
* 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;
}
/**
* Write a string value to the specified file.
* @param filename The filename
* @param value The value
*/
public static void writeValue(String filename, String value) {
if (filename == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(new File(filename));
fos.write(value.getBytes());
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the contents of the file with the given filename, or the specified default value if the file cannot be read.
*
* @param filename the name of the file to read
* @param defValue the default value to return if the file cannot be read
* @return the contents of the file as a String, or the default value if the file cannot be read
*/
public static String getFileValue(String filename, String defValue) {
String fileValue = readOneLine(filename);
if (fileValue != null) {
return fileValue;
}
return defValue;
}
/**
* 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();
}
}