spes: parts: import Refresh Rate tile
This commit is contained in:
@@ -573,3 +573,10 @@ $(call inherit-product, vendor/xiaomi/miuicamera/config.mk)
|
||||
# Remove unnecessary system apps (e.g., AudioFX)
|
||||
PRODUCT_PACKAGES += \
|
||||
RemovePackages
|
||||
|
||||
# Refreshrate
|
||||
PRODUCT_PACKAGES += \
|
||||
RefreshRateParts
|
||||
|
||||
PRODUCT_COPY_FILES += \
|
||||
$(LOCAL_PATH)/refreshrate/privapp-permissions-refresh-rate-parts.xml:$(TARGET_COPY_OUT_SYSTEM_EXT)/etc/permissions/privapp-permissions-refresh-rate-parts.xml
|
||||
|
||||
22
refreshrate/Android.bp
Normal file
22
refreshrate/Android.bp
Normal file
@@ -0,0 +1,22 @@
|
||||
android_app {
|
||||
name: "RefreshRateParts",
|
||||
|
||||
srcs: ["src/**/*.java"],
|
||||
|
||||
certificate: "platform",
|
||||
platform_apis: true,
|
||||
system_ext_specific: true,
|
||||
privileged: true,
|
||||
|
||||
static_libs: [
|
||||
"androidx.core_core",
|
||||
"androidx.preference_preference",
|
||||
"org.lineageos.settings.resources",
|
||||
"SettingsLib",
|
||||
],
|
||||
|
||||
optimize: {
|
||||
proguard_flags_files: ["proguard.flags"],
|
||||
},
|
||||
|
||||
}
|
||||
73
refreshrate/AndroidManifest.xml
Normal file
73
refreshrate/AndroidManifest.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="co.aospa.settings"
|
||||
android:versionCode="4"
|
||||
android:versionName="4.0"
|
||||
android:sharedUserId="android.uid.system">
|
||||
<uses-permission android:name="android.permission.DEVICE_POWER" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
|
||||
<uses-permission android:name="android.permission.GET_TASKS" />
|
||||
|
||||
<application
|
||||
android:label="@string/device_settings_app_name"
|
||||
android:persistent="true"
|
||||
android:directBootAware="true">
|
||||
<!-- TODO after package rename in U:
|
||||
android:defaultToDeviceProtectedStorage="true" -->
|
||||
|
||||
<receiver
|
||||
android:name=".BootCompletedReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter android:priority="1000">
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".refreshrate.RefreshActivity"
|
||||
android:label="@string/refresh_title"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.SubSettingsBase">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.settings.action.IA_SETTINGS" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="com.android.settings.category"
|
||||
android:value="com.android.settings.category.ia.display" />
|
||||
<meta-data
|
||||
android:name="com.android.settings.summary"
|
||||
android:resource="@string/refresh_summary" />
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".refreshrate.RefreshService"
|
||||
android:permission="RefreshService">
|
||||
</service>
|
||||
|
||||
<service
|
||||
android:name=".refreshrate.RefreshTileService"
|
||||
android:exported="true"
|
||||
android:icon="@drawable/ic_refresh_tile"
|
||||
android:label="@string/refresh_rate_tile_title"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<activity
|
||||
android:name=".TileEntryActivity"
|
||||
android:label="@string/device_settings_app_name"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.SubSettingsBase">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
22
refreshrate/privapp-permissions-refresh-rate-parts.xml
Normal file
22
refreshrate/privapp-permissions-refresh-rate-parts.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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="co.aospa.settings">
|
||||
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
|
||||
</privapp-permissions>
|
||||
</permissions>
|
||||
3
refreshrate/proguard.flags
Normal file
3
refreshrate/proguard.flags
Normal file
@@ -0,0 +1,3 @@
|
||||
-keep class co.aospa.settings.* {
|
||||
*;
|
||||
}
|
||||
16
refreshrate/res/drawable/ic_refresh_60.xml
Normal file
16
refreshrate/res/drawable/ic_refresh_60.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M6.55 8c-0.4 0-0.8 0.16-1.1 0.46C5.17 8.75 5 9.14 5 9.56v4.66c0 0.4 0.16 0.8 0.46 1.1 0.29 0.29 0.68 0.45 1.1 0.45H8.1c0.41 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1v-1.55c0-0.41-0.16-0.8-0.45-1.1-0.3-0.29-0.69-0.45-1.1-0.45H6.55V9.55h3.11V8h-3.1Zm0 4.66h1.56v1.56H6.55v-1.56Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M12 8c-0.42 0-0.81 0.16-1.1 0.46-0.3 0.29-0.46 0.68-0.46 1.1v4.66c0 0.4 0.16 0.8 0.45 1.1 0.3 0.29 0.69 0.45 1.1 0.45h1.56c0.4 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1V9.56c0-0.4-0.16-0.8-0.46-1.1C14.35 8.17 13.96 8 13.54 8H12Zm0 1.55h1.55v4.67h-1.56V9.55Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M17 1.01L7 1C5.9 1 5 1.9 5 3v4h2V3h10v18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99Z"/>
|
||||
</vector>
|
||||
16
refreshrate/res/drawable/ic_refresh_90.xml
Normal file
16
refreshrate/res/drawable/ic_refresh_90.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M17 1.01L7 1C5.9 1 5 1.9 5 3v4h2V3h10v18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2V3c0-1.1-0.9-1.99-2-1.99Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M8.1 15.77c0.42 0 0.82-0.16 1.1-0.46 0.3-0.29 0.46-0.68 0.46-1.1V9.56c0-0.4-0.16-0.8-0.45-1.1C8.9 8.17 8.52 8 8.1 8H6.55c-0.4 0-0.8 0.16-1.1 0.46C5.17 8.75 5 9.14 5 9.56v1.55c0 0.41 0.16 0.8 0.46 1.1 0.29 0.29 0.68 0.45 1.1 0.45H8.1v1.56H5v1.55h3.1Zm0-4.66H6.56V9.55h1.56v1.56Z"/>
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M12 8c-0.42 0-0.81 0.16-1.1 0.46-0.3 0.29-0.46 0.68-0.46 1.1v4.66c0 0.4 0.16 0.8 0.45 1.1 0.3 0.29 0.69 0.45 1.1 0.45h1.56c0.4 0 0.8-0.16 1.1-0.46 0.29-0.29 0.45-0.68 0.45-1.1V9.56c0-0.4-0.16-0.8-0.46-1.1C14.35 8.17 13.96 8 13.54 8H12Zm0 1.55h1.55v4.67h-1.56V9.55Z"/>
|
||||
</vector>
|
||||
10
refreshrate/res/drawable/ic_refresh_default.xml
Normal file
10
refreshrate/res/drawable/ic_refresh_default.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/colorAccent">
|
||||
<path
|
||||
android:fillColor="#ff000000"
|
||||
android:pathData="M17 3.01V15l2 2V3.01c0-1.1-0.9-1.99-2-1.99L7 1C6 0.99 5 1.99 5 2.99L7 5V3.01h10Zm4.2 18.19L19 19.01l-2-2-10-10-2-2-2.19-2.19L1.4 4.23 5 7.84v13.17c0 1.1 0.9 2 2 2h10c0.85 0 1.58-0.55 1.87-1.3l0.91 0.91 1.41-1.42ZM17 21.01H7L17 21v-0.99 1Zm-10 0V9.84l10 10.17V21L7 21.01Z"/>
|
||||
</vector>
|
||||
10
refreshrate/res/drawable/ic_refresh_tile.xml
Normal file
10
refreshrate/res/drawable/ic_refresh_tile.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<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="#ff000000"
|
||||
android:pathData="M7 3h10v4h2V3c0-1.1-0.9-1.99-2-1.99L7 1C5.9 1 5 1.9 5 3v5 4H2l4 4 4-4H7V3Zm10 18H7v-4H5v4c0 1.1 0.9 2 2 2h10c1.1 0 2-0.9 2-2v-5-4h3l-4-4-4 4h3v0.22V21Z"/>
|
||||
</vector>
|
||||
18
refreshrate/res/drawable/refresh_layout.xml
Normal file
18
refreshrate/res/drawable/refresh_layout.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/refresh_rv_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
73
refreshrate/res/drawable/refresh_list_item.xml
Normal file
73
refreshrate/res/drawable/refresh_list_item.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingTop="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="@android:dimen/app_icon_size"
|
||||
android:layout_height="@android:dimen/app_icon_size"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
style="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/app_mode"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/state"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_refresh_default" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
18
refreshrate/res/layout/refresh_layout.xml
Normal file
18
refreshrate/res/layout/refresh_layout.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/refresh_rv_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
73
refreshrate/res/layout/refresh_list_item.xml
Normal file
73
refreshrate/res/layout/refresh_list_item.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2020 The LineageOS Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
android:paddingBottom="4dp"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||
android:paddingTop="4dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/app_icon"
|
||||
android:layout_width="@android:dimen/app_icon_size"
|
||||
android:layout_height="@android:dimen/app_icon_size"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/app_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
style="?android:attr/textAppearanceMedium" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/app_mode"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/state"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="8dp"
|
||||
android:scaleType="centerInside"
|
||||
android:src="@drawable/ic_refresh_default" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
21
refreshrate/res/values/integers.xml
Normal file
21
refreshrate/res/values/integers.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 20 The LineageOS Project
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Refresh Rate -->
|
||||
<integer-array name="refresh_rate_tile_blocklist">
|
||||
</integer-array>
|
||||
|
||||
</resources>
|
||||
12
refreshrate/res/values/strings.xml
Normal file
12
refreshrate/res/values/strings.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<resources>
|
||||
<!-- Add other string resources here -->
|
||||
|
||||
<!-- Add the missing string resources -->
|
||||
<!-- Refresh Rate -->
|
||||
<string name="refresh_title">Refresh rate per-app</string>
|
||||
<string name="refresh_summary">Set a specific refresh rate for each application</string>
|
||||
<string name="refresh_rate_tile_title">Refresh Rate</string>
|
||||
<string name="refresh_medium">(60 Hz)</string>
|
||||
<string name="refresh_high">(90 Hz)</string>
|
||||
<string name="refresh_default">(60/90 Hz)</string>
|
||||
</resources>
|
||||
20
refreshrate/res/values/styles.xml
Normal file
20
refreshrate/res/values/styles.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015-2016 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.
|
||||
-->
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<style name="TextAppearance.Medium" parent="@android:style/TextAppearance.Material.Medium" />
|
||||
</resources>
|
||||
37
refreshrate/src/co/aospa/settings/BootCompletedReceiver.java
Normal file
37
refreshrate/src/co/aospa/settings/BootCompletedReceiver.java
Normal file
@@ -0,0 +1,37 @@
|
||||
package co.aospa.settings;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
|
||||
import co.aospa.settings.refreshrate.RefreshUtils;
|
||||
|
||||
public class BootCompletedReceiver extends BroadcastReceiver {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "RefreshRateParts";
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
Log.i(TAG, "Received intent: " + intent.getAction());
|
||||
|
||||
switch (intent.getAction()) {
|
||||
case Intent.ACTION_LOCKED_BOOT_COMPLETED:
|
||||
onLockedBootCompleted(context);
|
||||
break;
|
||||
case Intent.ACTION_BOOT_COMPLETED:
|
||||
onBootCompleted(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void onLockedBootCompleted(Context context) {
|
||||
// Services that don't require reading from data.
|
||||
}
|
||||
|
||||
private static void onBootCompleted(Context context) {
|
||||
// Data is now accessible (user has just unlocked).
|
||||
RefreshUtils.initialize(context);
|
||||
}
|
||||
}
|
||||
58
refreshrate/src/co/aospa/settings/TileEntryActivity.java
Normal file
58
refreshrate/src/co/aospa/settings/TileEntryActivity.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2021 Chaldeaprjkt
|
||||
*
|
||||
* 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 co.aospa.settings;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import co.aospa.settings.refreshrate.RefreshActivity;
|
||||
|
||||
public class TileEntryActivity extends Activity {
|
||||
private static final String TAG = "TileEntryActivity";
|
||||
private static final String REFRESH_TILE = "co.aospa.settings.refreshrate.RefreshTileService";
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ComponentName sourceClass = getIntent().getParcelableExtra(Intent.EXTRA_COMPONENT_NAME);
|
||||
switch (sourceClass.getClassName()) {
|
||||
case REFRESH_TILE:
|
||||
openActivitySafely(new Intent(this, RefreshActivity.class));
|
||||
break;
|
||||
default:
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void openActivitySafely(Intent dest) {
|
||||
try {
|
||||
dest.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
|
||||
finish();
|
||||
startActivity(dest);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "No activity found for " + dest);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package co.aospa.settings.refreshrate;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity;
|
||||
import com.android.settingslib.collapsingtoolbar.R;
|
||||
|
||||
public class RefreshActivity extends CollapsingToolbarBaseActivity {
|
||||
|
||||
private static final String TAG_REFRESH = "refresh";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getFragmentManager().beginTransaction().replace(R.id.content_frame,
|
||||
new RefreshSettingsFragment(), TAG_REFRESH).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package co.aospa.settings.refreshrate;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.ActivityTaskManager.RootTaskInfo;
|
||||
import android.app.IActivityTaskManager;
|
||||
import android.app.Service;
|
||||
import android.app.TaskStackListener;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
import android.os.RemoteException;
|
||||
|
||||
public class RefreshService extends Service {
|
||||
|
||||
private static final String TAG = "RefreshService";
|
||||
private static final boolean DEBUG = true;
|
||||
|
||||
private String mPreviousApp;
|
||||
private RefreshUtils mRefreshUtils;
|
||||
private IActivityTaskManager mActivityTaskManager;
|
||||
private final TaskStackListener mTaskListener = new TaskStackListener() {
|
||||
@Override
|
||||
public void onTaskStackChanged() {
|
||||
try {
|
||||
final RootTaskInfo info = mActivityTaskManager.getFocusedRootTaskInfo();
|
||||
if (info == null || info.topActivity == null) {
|
||||
return;
|
||||
}
|
||||
String foregroundApp = info.topActivity.getPackageName();
|
||||
if (!foregroundApp.equals(mPreviousApp)) {
|
||||
mRefreshUtils.setRefreshRate(foregroundApp);
|
||||
mPreviousApp = foregroundApp;
|
||||
}
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
};
|
||||
|
||||
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mPreviousApp = "";
|
||||
mRefreshUtils.setDefaultRefreshRate(context);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
if (DEBUG) Log.d(TAG, "Creating service");
|
||||
mRefreshUtils = new RefreshUtils(this);
|
||||
mRefreshUtils.setDefaultRefreshRate(this);
|
||||
try {
|
||||
mActivityTaskManager = ActivityTaskManager.getService();
|
||||
mActivityTaskManager.registerTaskStackListener(mTaskListener);
|
||||
} catch (RemoteException e) {
|
||||
// Do nothing
|
||||
}
|
||||
registerReceiver();
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (DEBUG) Log.d(TAG, "Destroying service");
|
||||
unregisterReceiver();
|
||||
try {
|
||||
ActivityTaskManager.getService().unregisterTaskStackListener(mTaskListener);
|
||||
} catch (RemoteException e) {
|
||||
// Do nothing
|
||||
}
|
||||
mRefreshUtils.setDefaultRefreshRate(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (DEBUG) Log.d(TAG, "Starting service");
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void registerReceiver() {
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
filter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
this.registerReceiver(mIntentReceiver, filter);
|
||||
}
|
||||
|
||||
private void unregisterReceiver() {
|
||||
this.unregisterReceiver(mIntentReceiver);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,412 @@
|
||||
/**
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package co.aospa.settings.refreshrate;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.SectionIndexer;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.PreferenceFragment;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import com.android.settingslib.applications.ApplicationsState;
|
||||
|
||||
import co.aospa.settings.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RefreshSettingsFragment extends PreferenceFragment
|
||||
implements ApplicationsState.Callbacks {
|
||||
|
||||
private AllPackagesAdapter mAllPackagesAdapter;
|
||||
private ApplicationsState mApplicationsState;
|
||||
private ApplicationsState.Session mSession;
|
||||
private ActivityFilter mActivityFilter;
|
||||
|
||||
private RefreshUtils mRefreshUtils;
|
||||
private RecyclerView mAppsRecyclerView;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mApplicationsState = ApplicationsState.getInstance(getActivity().getApplication());
|
||||
mSession = mApplicationsState.newSession(this);
|
||||
mSession.onResume();
|
||||
mActivityFilter = new ActivityFilter(getActivity().getPackageManager());
|
||||
|
||||
mAllPackagesAdapter = new AllPackagesAdapter(getActivity());
|
||||
|
||||
mRefreshUtils = new RefreshUtils(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.refresh_layout, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
mAppsRecyclerView = view.findViewById(R.id.refresh_rv_view);
|
||||
mAppsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
mAppsRecyclerView.setAdapter(mAllPackagesAdapter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
mSession.onPause();
|
||||
mSession.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageListChanged() {
|
||||
mActivityFilter.updateLauncherInfoList();
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> entries) {
|
||||
if (entries != null) {
|
||||
handleAppEntries(entries);
|
||||
mAllPackagesAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadEntriesCompleted() {
|
||||
rebuild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllSizesComputed() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLauncherInfoChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageIconChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageSizeChanged(String packageName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRunningStateChanged(boolean running) {
|
||||
}
|
||||
|
||||
private void handleAppEntries(List<ApplicationsState.AppEntry> entries) {
|
||||
final ArrayList<String> sections = new ArrayList<String>();
|
||||
final ArrayList<Integer> positions = new ArrayList<Integer>();
|
||||
final PackageManager pm = getActivity().getPackageManager();
|
||||
String lastSectionIndex = null;
|
||||
int offset = 0;
|
||||
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
final ApplicationInfo info = entries.get(i).info;
|
||||
final String label = (String) info.loadLabel(pm);
|
||||
final String sectionIndex;
|
||||
|
||||
if (!info.enabled) {
|
||||
sectionIndex = "--"; // XXX
|
||||
} else if (TextUtils.isEmpty(label)) {
|
||||
sectionIndex = "";
|
||||
} else {
|
||||
sectionIndex = label.substring(0, 1).toUpperCase();
|
||||
}
|
||||
|
||||
if (lastSectionIndex == null ||
|
||||
!TextUtils.equals(sectionIndex, lastSectionIndex)) {
|
||||
sections.add(sectionIndex);
|
||||
positions.add(offset);
|
||||
lastSectionIndex = sectionIndex;
|
||||
}
|
||||
|
||||
offset++;
|
||||
}
|
||||
|
||||
mAllPackagesAdapter.setEntries(entries, sections, positions);
|
||||
}
|
||||
|
||||
private void rebuild() {
|
||||
mSession.rebuild(mActivityFilter, ApplicationsState.ALPHA_COMPARATOR);
|
||||
}
|
||||
|
||||
private int getStateDrawable(int state) {
|
||||
switch (state) {
|
||||
case RefreshUtils.STATE_MEDIUM:
|
||||
return R.drawable.ic_refresh_60;
|
||||
case RefreshUtils.STATE_HIGH:
|
||||
return R.drawable.ic_refresh_90;
|
||||
case RefreshUtils.STATE_DEFAULT:
|
||||
default:
|
||||
return R.drawable.ic_refresh_default;
|
||||
}
|
||||
}
|
||||
|
||||
private class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private TextView title;
|
||||
private Spinner mode;
|
||||
private ImageView icon;
|
||||
private View rootView;
|
||||
private ImageView stateIcon;
|
||||
|
||||
private ViewHolder(View view) {
|
||||
super(view);
|
||||
this.title = view.findViewById(R.id.app_name);
|
||||
this.mode = view.findViewById(R.id.app_mode);
|
||||
this.icon = view.findViewById(R.id.app_icon);
|
||||
this.stateIcon = view.findViewById(R.id.state);
|
||||
this.rootView = view;
|
||||
|
||||
view.setTag(this);
|
||||
}
|
||||
}
|
||||
|
||||
private class ModeAdapter extends BaseAdapter {
|
||||
|
||||
private final LayoutInflater inflater;
|
||||
private final int[] items = {
|
||||
R.string.refresh_default,
|
||||
R.string.refresh_medium,
|
||||
R.string.refresh_high
|
||||
};
|
||||
|
||||
private ModeAdapter(Context context) {
|
||||
inflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return items.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return items[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
TextView view;
|
||||
if (convertView != null) {
|
||||
view = (TextView) convertView;
|
||||
} else {
|
||||
view = (TextView) inflater.inflate(android.R.layout.simple_spinner_dropdown_item,
|
||||
parent, false);
|
||||
}
|
||||
|
||||
view.setText(items[position]);
|
||||
view.setTextSize(14f);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
private class AllPackagesAdapter extends RecyclerView.Adapter<ViewHolder>
|
||||
implements AdapterView.OnItemSelectedListener, SectionIndexer {
|
||||
|
||||
private List<ApplicationsState.AppEntry> mEntries = new ArrayList<>();
|
||||
private String[] mSections;
|
||||
private int[] mPositions;
|
||||
|
||||
public AllPackagesAdapter(Context context) {
|
||||
mActivityFilter = new ActivityFilter(context.getPackageManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mEntries.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mEntries.get(position).id;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.refresh_list_item, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
Context context = holder.itemView.getContext();
|
||||
ApplicationsState.AppEntry entry = mEntries.get(position);
|
||||
if (entry == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
holder.mode.setAdapter(new ModeAdapter(context));
|
||||
holder.mode.setOnItemSelectedListener(this);
|
||||
holder.title.setText(entry.label);
|
||||
holder.title.setOnClickListener(v -> holder.mode.performClick());
|
||||
mApplicationsState.ensureIcon(entry);
|
||||
holder.icon.setImageDrawable(entry.icon);
|
||||
int packageState = mRefreshUtils.getStateForPackage(entry.info.packageName);
|
||||
holder.mode.setSelection(packageState, false);
|
||||
holder.mode.setTag(entry);
|
||||
holder.stateIcon.setImageResource(getStateDrawable(packageState));
|
||||
holder.stateIcon.setOnClickListener(v -> holder.mode.performClick());
|
||||
}
|
||||
|
||||
private void setEntries(List<ApplicationsState.AppEntry> entries,
|
||||
List<String> sections, List<Integer> positions) {
|
||||
mEntries = entries;
|
||||
mSections = sections.toArray(new String[sections.size()]);
|
||||
mPositions = new int[positions.size()];
|
||||
for (int i = 0; i < positions.size(); i++) {
|
||||
mPositions[i] = positions.get(i);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||
final ApplicationsState.AppEntry entry = (ApplicationsState.AppEntry) parent.getTag();
|
||||
int currentState = mRefreshUtils.getStateForPackage(entry.info.packageName);
|
||||
if (currentState != position) {
|
||||
mRefreshUtils.writePackage(entry.info.packageName, position);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionForSection(int section) {
|
||||
if (section < 0 || section >= mSections.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return mPositions[section];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionForPosition(int position) {
|
||||
if (position < 0 || position >= getItemCount()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final int index = Arrays.binarySearch(mPositions, position);
|
||||
|
||||
/*
|
||||
* Consider this example: section positions are 0, 3, 5; the supplied
|
||||
* position is 4. The section corresponding to position 4 starts at
|
||||
* position 3, so the expected return value is 1. Binary search will not
|
||||
* find 4 in the array and thus will return -insertPosition-1, i.e. -3.
|
||||
* To get from that number to the expected value of 1 we need to negate
|
||||
* and subtract 2.
|
||||
*/
|
||||
return index >= 0 ? index : -index - 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSections() {
|
||||
return mSections;
|
||||
}
|
||||
}
|
||||
|
||||
private class ActivityFilter implements ApplicationsState.AppFilter {
|
||||
|
||||
private final PackageManager mPackageManager;
|
||||
private final List<String> mLauncherResolveInfoList = new ArrayList<String>();
|
||||
|
||||
private ActivityFilter(PackageManager packageManager) {
|
||||
this.mPackageManager = packageManager;
|
||||
|
||||
updateLauncherInfoList();
|
||||
}
|
||||
|
||||
public void updateLauncherInfoList() {
|
||||
Intent i = new Intent(Intent.ACTION_MAIN);
|
||||
i.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
List<ResolveInfo> resolveInfoList = mPackageManager.queryIntentActivities(i, 0);
|
||||
|
||||
synchronized (mLauncherResolveInfoList) {
|
||||
mLauncherResolveInfoList.clear();
|
||||
for (ResolveInfo ri : resolveInfoList) {
|
||||
mLauncherResolveInfoList.add(ri.activityInfo.packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filterApp(ApplicationsState.AppEntry entry) {
|
||||
boolean show = !mAllPackagesAdapter.mEntries.contains(entry.info.packageName);
|
||||
if (show) {
|
||||
synchronized (mLauncherResolveInfoList) {
|
||||
show = mLauncherResolveInfoList.contains(entry.info.packageName);
|
||||
}
|
||||
}
|
||||
return show;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (C) 2021 crDroid Android Project
|
||||
* Copyright (C) 2021 Chaldeaprjkt
|
||||
*
|
||||
* 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 co.aospa.settings.refreshrate;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.service.quicksettings.TileService;
|
||||
import android.view.Display;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class RefreshTileService extends TileService {
|
||||
private static final String KEY_MIN_REFRESH_RATE = "min_refresh_rate";
|
||||
private static final String KEY_PEAK_REFRESH_RATE = "peak_refresh_rate";
|
||||
|
||||
private Context context;
|
||||
private Tile tile;
|
||||
|
||||
private final List<Integer> availableRates = new ArrayList<>();
|
||||
private int activeRateMin;
|
||||
private int activeRateMax;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
context = getApplicationContext();
|
||||
Display.Mode mode = context.getDisplay().getMode();
|
||||
Display.Mode[] modes = context.getDisplay().getSupportedModes();
|
||||
for (Display.Mode m : modes) {
|
||||
int rate = (int) Math.round(m.getRefreshRate());
|
||||
if (m.getPhysicalWidth() == mode.getPhysicalWidth() &&
|
||||
m.getPhysicalHeight() == mode.getPhysicalHeight()) {
|
||||
availableRates.add(rate);
|
||||
}
|
||||
}
|
||||
syncFromSettings();
|
||||
}
|
||||
|
||||
private int getSettingOf(String key) {
|
||||
float rate = Settings.System.getFloat(context.getContentResolver(), key, 90);
|
||||
int active = availableRates.indexOf((int) Math.round(rate));
|
||||
return Math.max(active, 0);
|
||||
}
|
||||
|
||||
private void syncFromSettings() {
|
||||
activeRateMin = getSettingOf(KEY_MIN_REFRESH_RATE);
|
||||
activeRateMax = getSettingOf(KEY_PEAK_REFRESH_RATE);
|
||||
}
|
||||
|
||||
private void cycleRefreshRate() {
|
||||
if (activeRateMax == 0) {
|
||||
if(activeRateMin == 0) {
|
||||
activeRateMin = availableRates.size();
|
||||
}
|
||||
activeRateMax = activeRateMin;
|
||||
float rate = availableRates.get(activeRateMin - 1);
|
||||
Settings.System.putFloat(context.getContentResolver(), KEY_MIN_REFRESH_RATE, rate);
|
||||
}
|
||||
float rate = availableRates.get(activeRateMax - 1);
|
||||
Settings.System.putFloat(context.getContentResolver(), KEY_PEAK_REFRESH_RATE, rate);
|
||||
}
|
||||
|
||||
private void updateTileView() {
|
||||
String displayText;
|
||||
int min = availableRates.get(activeRateMin);
|
||||
int max = availableRates.get(activeRateMax);
|
||||
|
||||
displayText = String.format(Locale.US, min == max ? "%d Hz" : "%d - %d Hz", min, max);
|
||||
tile.setContentDescription(displayText);
|
||||
tile.setSubtitle(displayText);
|
||||
tile.setState(min == max ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
|
||||
tile.updateTile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartListening() {
|
||||
super.onStartListening();
|
||||
tile = getQsTile();
|
||||
syncFromSettings();
|
||||
updateTileView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
super.onClick();
|
||||
cycleRefreshRate();
|
||||
syncFromSettings();
|
||||
updateTileView();
|
||||
}
|
||||
}
|
||||
168
refreshrate/src/co/aospa/settings/refreshrate/RefreshUtils.java
Normal file
168
refreshrate/src/co/aospa/settings/refreshrate/RefreshUtils.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The LineageOS Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package co.aospa.settings.refreshrate;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.UserHandle;
|
||||
import android.view.Display;
|
||||
|
||||
import android.provider.Settings;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
public final class RefreshUtils {
|
||||
|
||||
private static final String REFRESH_CONTROL = "refresh_control";
|
||||
private static final String REFRESH_SERVICE = "refresh_service";
|
||||
|
||||
private static final String KEY_PEAK_REFRESH_RATE = "peak_refresh_rate";
|
||||
private static final String KEY_MIN_REFRESH_RATE = "min_refresh_rate";
|
||||
private Context mContext;
|
||||
|
||||
protected static final int STATE_DEFAULT = 0;
|
||||
protected static final int STATE_MEDIUM = 1;
|
||||
protected static final int STATE_HIGH = 2;
|
||||
|
||||
private static final float REFRESH_STATE_DEFAULT = 90f;
|
||||
private static final float REFRESH_STATE_MEDIUM = 60f;
|
||||
private static final float REFRESH_STATE_HIGH = 90f;
|
||||
|
||||
private static final String REFRESH_MEDIUM = "refresh.medium=";
|
||||
private static final String REFRESH_HIGH = "refresh.high=";
|
||||
|
||||
private static boolean isAppInList = false;
|
||||
private static float defaultMaxRate;
|
||||
private static float defaultMinRate;
|
||||
|
||||
private SharedPreferences mSharedPrefs;
|
||||
|
||||
protected RefreshUtils(Context context) {
|
||||
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public static void initialize(Context context) {
|
||||
defaultMaxRate = Settings.System.getFloat(context.getContentResolver(), KEY_PEAK_REFRESH_RATE, REFRESH_STATE_DEFAULT);
|
||||
defaultMinRate = Settings.System.getFloat(context.getContentResolver(), KEY_MIN_REFRESH_RATE, REFRESH_STATE_DEFAULT);
|
||||
|
||||
if (isServiceEnabled(context))
|
||||
startService(context);
|
||||
else
|
||||
setDefaultRefreshRate(context);
|
||||
}
|
||||
|
||||
public static void startService(Context context) {
|
||||
context.startServiceAsUser(new Intent(context, RefreshService.class),
|
||||
UserHandle.CURRENT);
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(REFRESH_SERVICE, "true").apply();
|
||||
}
|
||||
|
||||
protected static void stopService(Context context) {
|
||||
context.stopService(new Intent(context, RefreshService.class));
|
||||
PreferenceManager.getDefaultSharedPreferences(context).edit().putString(REFRESH_SERVICE, "false").apply();
|
||||
}
|
||||
|
||||
protected static boolean isServiceEnabled(Context context) {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void writeValue(String profiles) {
|
||||
mSharedPrefs.edit().putString(REFRESH_CONTROL, profiles).apply();
|
||||
}
|
||||
|
||||
private String getValue() {
|
||||
String value = mSharedPrefs.getString(REFRESH_CONTROL, null);
|
||||
|
||||
if (value == null || value.isEmpty()) {
|
||||
value = REFRESH_MEDIUM + ":" + REFRESH_HIGH;
|
||||
writeValue(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected void writePackage(String packageName, int mode) {
|
||||
String value = getValue();
|
||||
value = value.replace(packageName + ",", "");
|
||||
String[] modes = value.split(":");
|
||||
String finalString;
|
||||
|
||||
switch (mode) {
|
||||
case STATE_MEDIUM:
|
||||
modes[0] = modes[0] + packageName + ",";
|
||||
break;
|
||||
case STATE_HIGH:
|
||||
modes[1] = modes[1] + packageName + ",";
|
||||
break;
|
||||
}
|
||||
|
||||
finalString = modes[0] + ":" + modes[1];
|
||||
|
||||
writeValue(finalString);
|
||||
}
|
||||
|
||||
protected int getStateForPackage(String packageName) {
|
||||
String value = getValue();
|
||||
String[] modes = value.split(":");
|
||||
int state = STATE_DEFAULT;
|
||||
if (modes[0].contains(packageName + ",")) {
|
||||
state = STATE_MEDIUM;
|
||||
} else if (modes[1].contains(packageName + ",")) {
|
||||
state = STATE_HIGH;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
protected static void setDefaultRefreshRate(Context context) {
|
||||
Settings.System.putFloat(context.getContentResolver(), KEY_PEAK_REFRESH_RATE, defaultMaxRate);
|
||||
Settings.System.putFloat(context.getContentResolver(), KEY_MIN_REFRESH_RATE, defaultMinRate);
|
||||
}
|
||||
|
||||
protected void setRefreshRate(String packageName) {
|
||||
String value = getValue();
|
||||
String modes[];
|
||||
|
||||
if (!isAppInList) {
|
||||
defaultMaxRate = Settings.System.getFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, REFRESH_STATE_DEFAULT);
|
||||
defaultMinRate = Settings.System.getFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, REFRESH_STATE_DEFAULT);
|
||||
}
|
||||
|
||||
float minrate = defaultMinRate;
|
||||
float maxrate = defaultMaxRate;
|
||||
|
||||
if (value != null) {
|
||||
modes = value.split(":");
|
||||
if (modes[0].contains(packageName + ",")) {
|
||||
maxrate = REFRESH_STATE_MEDIUM;
|
||||
if ( minrate > maxrate){
|
||||
minrate = maxrate;
|
||||
}
|
||||
isAppInList = true;
|
||||
} else if (modes[1].contains(packageName + ",")) {
|
||||
maxrate = REFRESH_STATE_HIGH;
|
||||
if ( minrate > maxrate){
|
||||
minrate = maxrate;
|
||||
}
|
||||
isAppInList = true;
|
||||
} else {
|
||||
isAppInList = false;
|
||||
}
|
||||
}
|
||||
Settings.System.putFloat(mContext.getContentResolver(), KEY_PEAK_REFRESH_RATE, maxrate);
|
||||
Settings.System.putFloat(mContext.getContentResolver(), KEY_MIN_REFRESH_RATE, minrate);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user