Compare commits
172 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7d360415b3 | |||
|
|
fe4412bb0a | ||
| 4e809bad82 | |||
|
|
3a67714e73 | ||
|
|
7e3ba94d63 | ||
|
|
30213e2d7d | ||
|
|
ef8fe6b810 | ||
|
|
d0197cd72f | ||
|
|
2b53411014 | ||
|
|
d8cb024d17 | ||
|
|
67136ee52e | ||
|
|
7cd00758e3 | ||
|
|
547c534e78 | ||
|
|
d415ac0ee6 | ||
|
|
c6473358e2 | ||
|
|
b8724aa866 | ||
|
|
914817d98a | ||
|
|
f07d367656 | ||
|
|
89d6684342 | ||
|
|
190ae7f321 | ||
|
|
26c913ccf8 | ||
|
|
a0995b6e0a | ||
|
|
15f18a41a4 | ||
|
|
989b6ba659 | ||
|
|
9dd8c18207 | ||
|
|
a6b49ee233 | ||
|
|
632f3b911c | ||
|
|
1eba7d34b1 | ||
|
|
198ba59f78 | ||
|
|
f4ec6bf221 | ||
|
|
04e927cc2b | ||
|
|
2a0aa8bc2f | ||
|
|
7ae38ca1be | ||
|
|
ce36f84afa | ||
|
|
f0548bef78 | ||
|
|
71ce131ef7 | ||
|
|
5e83463f05 | ||
|
|
c5a2cb2eb0 | ||
|
|
4b0fdb9d0d | ||
|
|
1c66bbfeeb | ||
|
|
9e9b0fe2fa | ||
|
|
fb0c0864fa | ||
|
|
5c416f8e40 | ||
|
|
3513c6826a | ||
|
|
126f7853e0 | ||
|
|
7d6707f4c0 | ||
|
|
0cad8a424d | ||
|
|
6604548518 | ||
|
|
d8d3c133fb | ||
|
|
3edb8fe6e9 | ||
|
|
2c82644337 | ||
|
|
8738bcd8ae | ||
|
|
9f60507abc | ||
|
|
43a27ff0b8 | ||
|
|
c0a67cae2b | ||
|
|
db91ce039b | ||
|
|
9a1f70d171 | ||
|
|
824602c65f | ||
|
|
32308a2cc3 | ||
|
|
7aa2810650 | ||
|
|
c9363253e9 | ||
|
|
b5a8e6c32a | ||
|
|
464b1d35eb | ||
|
|
0c554081c2 | ||
|
|
9582ba05f9 | ||
|
|
81fa629d76 | ||
|
|
6f268cde54 | ||
|
|
ac5f626358 | ||
|
|
768b9a517e | ||
|
|
1bab687397 | ||
|
|
09a9918362 | ||
|
|
3e90c6d758 | ||
|
|
baeef85734 | ||
|
|
03e2ea4da3 | ||
|
|
d80f587aa0 | ||
|
|
105ddc3159 | ||
|
|
64d9d1da29 | ||
|
|
14641e5c16 | ||
|
|
8bbf9c4146 | ||
|
|
19793f68d5 | ||
|
|
881fa7ab5f | ||
|
|
f8ef7eae09 | ||
|
|
91123cb96a | ||
|
|
88ba34dba5 | ||
|
|
4add258572 | ||
|
|
507e831020 | ||
|
|
6788b965d2 | ||
|
|
55fecc58e7 | ||
|
|
f549d68095 | ||
|
|
1adb147c70 | ||
|
|
8e78ae9adb | ||
|
|
fe717b29aa | ||
|
|
34f36e2f7f | ||
|
|
b759d9e88b | ||
|
|
3216027fe1 | ||
|
|
af9087a995 | ||
|
|
80fe8c3c7d | ||
|
|
5c3146f7b0 | ||
|
|
b3a4339f74 | ||
|
|
593f97fade | ||
|
|
08742df8f6 | ||
|
|
410aa3511d | ||
|
|
144646e6ec | ||
|
|
ed88bdc5cc | ||
|
|
285eccf3de | ||
|
|
a5621a3541 | ||
|
|
e9f090f2a6 | ||
|
|
f362a930ea | ||
|
|
74306993ea | ||
|
|
bc1b861c9c | ||
|
|
244c88cb10 | ||
|
|
01689599c6 | ||
|
|
e67b5c7075 | ||
|
|
6044b3541f | ||
|
|
a73d6486f0 | ||
|
|
ed4caad386 | ||
|
|
d292aa03ba | ||
|
|
090d5f2b5c | ||
|
|
403ddc3d92 | ||
|
|
0eff57e0e6 | ||
|
|
95ad0c188e | ||
|
|
45a45e8eeb | ||
|
|
8dfc2b9662 | ||
|
|
481fb35dce | ||
|
|
471f49b51d | ||
|
|
bfbb9381b4 | ||
|
|
b4a2a6b744 | ||
|
|
77a47a0df2 | ||
|
|
88b4e237fc | ||
|
|
5e1bf232a7 | ||
|
|
eafb8b4a7e | ||
|
|
81bd03c42f | ||
|
|
93353b7fe4 | ||
|
|
e0ed208f22 | ||
|
|
3fc8912155 | ||
|
|
34a24318a8 | ||
|
|
495cfb6640 | ||
|
|
7a643a4105 | ||
|
|
8ae5447fc5 | ||
|
|
20b9ca79d6 | ||
|
|
b7e4686284 | ||
|
|
641f44934c | ||
|
|
d2e134e7c0 | ||
|
|
860533d2bb | ||
|
|
70168c51f2 | ||
|
|
c0d70dc0f9 | ||
|
|
e8d95112d7 | ||
|
|
8c1e19bdb8 | ||
|
|
a9438581bb | ||
|
|
63795ed4d4 | ||
|
|
8acb73ff6a | ||
|
|
3633fe6cbe | ||
|
|
b122025d2d | ||
|
|
8ecfa3412a | ||
|
|
826524b2cb | ||
|
|
8393454ee6 | ||
|
|
0b09eeb4b7 | ||
|
|
23a4f0c429 | ||
|
|
0ad31fba1e | ||
|
|
9b27b2665b | ||
|
|
1477e8b42e | ||
|
|
4af7f26d3f | ||
|
|
04441ff343 | ||
|
|
93e8cfc069 | ||
|
|
17d525da8f | ||
|
|
af977627d4 | ||
|
|
00c112c97a | ||
|
|
9914060348 | ||
|
|
abe43816a2 | ||
|
|
655f8c1814 | ||
|
|
8da66b3786 | ||
|
|
19cd98ab96 |
39
DSPVolumeSynchronizer/Android.bp
Normal file
39
DSPVolumeSynchronizer/Android.bp
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright (C) 2024-2025 The LineageOS Project
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
android_app {
|
||||
name: "DSPVolumeSynchronizer",
|
||||
certificate: "platform",
|
||||
srcs: ["src/**/*.java"],
|
||||
platform_apis: true,
|
||||
privileged: true,
|
||||
system_ext_specific: true,
|
||||
static_libs: [
|
||||
"androidx.core_core",
|
||||
"SettingsLib",
|
||||
],
|
||||
|
||||
required: [
|
||||
"privapp-permissions-dspvolume",
|
||||
"config-dspvolume",
|
||||
],
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "privapp-permissions-dspvolume",
|
||||
relative_install_path: "permissions",
|
||||
src: "privapp-permissions-dspvolume.xml",
|
||||
system_ext_specific: true,
|
||||
filename_from_src: true,
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "config-dspvolume",
|
||||
relative_install_path: "sysconfig",
|
||||
src: "config-dspvolume.xml",
|
||||
system_ext_specific: true,
|
||||
filename_from_src: true,
|
||||
}
|
||||
30
DSPVolumeSynchronizer/AndroidManifest.xml
Normal file
30
DSPVolumeSynchronizer/AndroidManifest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.lineageos.dspvolume.xiaomi"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
android:sharedUserId="android.uid.system">
|
||||
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:persistent="true"
|
||||
android:defaultToDeviceProtectedStorage="true"
|
||||
android:directBootAware="true">
|
||||
|
||||
<receiver
|
||||
android:name=".BootReceiver"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
|
||||
<intent-filter android:priority="999">
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".VolumeListenerService" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
5
DSPVolumeSynchronizer/config-dspvolume.xml
Normal file
5
DSPVolumeSynchronizer/config-dspvolume.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<config>
|
||||
<allow-in-power-save package="org.lineageos.dspvolume.xiaomi" />
|
||||
<hidden-api-whitelisted-app package="org.lineageos.dspvolume.xiaomi" />
|
||||
</config>
|
||||
9
DSPVolumeSynchronizer/privapp-permissions-dspvolume.xml
Normal file
9
DSPVolumeSynchronizer/privapp-permissions-dspvolume.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<permissions>
|
||||
<privapp-permissions package="org.lineageos.dspvolume.xiaomi">
|
||||
<permission name="android.permission.INTERACT_ACROSS_USERS" />
|
||||
<permission name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||
<permission name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<permission name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
</privapp-permissions>
|
||||
</permissions>
|
||||
5
DSPVolumeSynchronizer/res/values/strings.xml
Normal file
5
DSPVolumeSynchronizer/res/values/strings.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- App Name -->
|
||||
<string name="app_name">DSP Volume Synchronizer</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.lineageos.dspvolume.xiaomi;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
context.startService(new Intent(context, VolumeListenerService.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.lineageos.dspvolume.xiaomi;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.util.Log;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class VolumeListenerReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(intent.getIntExtra("android.media.EXTRA_VOLUME_STREAM_TYPE", 0) == AudioManager.STREAM_MUSIC) {
|
||||
AudioManager audioManager = context.getSystemService(AudioManager.class);
|
||||
int current = intent.getIntExtra(
|
||||
"android.media.EXTRA_VOLUME_STREAM_VALUE",
|
||||
0
|
||||
);
|
||||
audioManager.setParameters("volume_change=" + current + ";flags=8");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.lineageos.dspvolume.xiaomi;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class VolumeListenerService extends Service {
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction("android.media.VOLUME_CHANGED_ACTION");
|
||||
registerReceiver(new VolumeListenerReceiver(), intentFilter);
|
||||
|
||||
AudioManager audioManager = getSystemService(AudioManager.class);
|
||||
int current = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
|
||||
audioManager.setParameters("volume_change=" + current + ";flags=8");
|
||||
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (C) 2023 The LineageOS Project
|
||||
// Copyright (C) 2023-2025 The LineageOS Project
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
@@ -13,24 +13,16 @@ android_app {
|
||||
product_specific: true,
|
||||
certificate: "platform",
|
||||
privileged: true,
|
||||
privapp_allowlist: "org.lineageos.euicc.xml",
|
||||
|
||||
optimize: {
|
||||
proguard_flags_files: ["proguard.flags"],
|
||||
},
|
||||
required: [
|
||||
"org.lineageos.euicc.xml",
|
||||
"hidden-api-whitelist-org.lineageos.euicc.xml",
|
||||
],
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "org.lineageos.euicc.xml",
|
||||
relative_install_path: "permissions",
|
||||
filename: "org.lineageos.euicc.xml",
|
||||
src: "org.lineageos.euicc.xml",
|
||||
product_specific: true,
|
||||
}
|
||||
|
||||
prebuilt_etc {
|
||||
name: "hidden-api-whitelist-org.lineageos.euicc.xml",
|
||||
relative_install_path: "sysconfig",
|
||||
|
||||
@@ -1,9 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023 The LineageOS Project
|
||||
SPDX-FileCopyrightText: 2023-2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="sim_illustration_lottie_mappings_json">{\"sim_illustration_lottie_mappings\":[{\"devices\":[\"OP594DL1\",\"OP595DL1\",\"OP5D55L1\"],\"illustration_lottie\":\"sim_illustration_lottie_bottom\"}]}</string>
|
||||
<string name="sim_slot_mappings_json">{\"sim-slot-mappings\":[{\"devices\":[\"OP594DL1\",\"OP595DL1\",\"OP5D55L1\"],\"esim-slot-ids\":[1],\"psim-slot-ids\":[0]}]}</string>
|
||||
<string name="sim_illustration_lottie_mappings_json" translatable="false">
|
||||
{
|
||||
\"sim_illustration_lottie_mappings\": [
|
||||
{
|
||||
\"devices\": [
|
||||
\"OP591BL1\",
|
||||
\"OP5929L1\",
|
||||
\"OP594DL1\",
|
||||
\"OP595DL1\",
|
||||
\"OP5CF9L1\",
|
||||
\"OP5D0DL1\",
|
||||
\"OP5D35L1\",
|
||||
\"OP5D55L1\"
|
||||
],
|
||||
\"illustration_lottie\": \"sim_illustration_lottie_bottom\"
|
||||
}
|
||||
]
|
||||
}
|
||||
</string>
|
||||
<string name="sim_slot_mappings_json" translatable="false">
|
||||
{
|
||||
\"sim-slot-mappings\": [
|
||||
{
|
||||
\"devices\": [
|
||||
\"OP594DL1\",
|
||||
\"OP595DL1\",
|
||||
\"OP5D35L1\",
|
||||
\"OP5D55L1\"
|
||||
],
|
||||
\"esim-slot-ids\": [
|
||||
1
|
||||
],
|
||||
\"psim-slot-ids\": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
\"devices\": [
|
||||
\"OP591BL1\",
|
||||
\"OP5929L1\",
|
||||
\"OP5CF9L1\",
|
||||
\"OP5D0DL1\"
|
||||
],
|
||||
\"esim-slot-ids\": [],
|
||||
\"psim-slot-ids\": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2018, 2021-2022 The LineageOS Project
|
||||
Copyright (C) 2018, 2021-2025 The LineageOS Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:sharedUserId="android.uid.system"
|
||||
package="org.lineageos.settings.device">
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
|
||||
<application
|
||||
@@ -41,17 +42,19 @@
|
||||
<!-- Additional button settings (Button settings) -->
|
||||
<activity
|
||||
android:name=".ButtonSettingsActivity"
|
||||
android:label="@string/button_panel_title"
|
||||
android:exported="false">
|
||||
android:label="@string/alert_slider_category_title"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.lineageos.settings.device.ADDITIONAL_BUTTONS_SETTINGS" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<action android:name="com.android.settings.action.IA_SETTINGS" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="com.android.settings.category"
|
||||
android:value="com.android.settings.category.ia.sound" />
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".KeyHandler"
|
||||
android:permission="KeyHandlerService"
|
||||
android:exported="false" />
|
||||
android:exported="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
21
KeyHandler/res/values-iw/strings.xml
Normal file
21
KeyHandler/res/values-iw/strings.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="alert_slider_category_title">מתג התראות</string>
|
||||
<string name="alert_slider_selection_dialog_title">פעולה</string>
|
||||
<string name="alert_slider_top_position">ממוקם למעלה</string>
|
||||
<string name="alert_slider_middle_position">ממוקם באמצע</string>
|
||||
<string name="alert_slider_bottom_position">ממוקם למטה</string>
|
||||
<string name="alert_slider_mode_none">ללא</string>
|
||||
<string name="alert_slider_mode_silent">שקט</string>
|
||||
<string name="alert_slider_mode_normal">רגיל</string>
|
||||
<string name="alert_slider_mode_vibration">רטט</string>
|
||||
<string name="alert_slider_mode_dnd_priority_only">עדיפות בלבד</string>
|
||||
<string name="alert_slider_mode_dnd_total_silence">מושתק לחלוטין</string>
|
||||
<string name="alert_slider_mode_dnd_alarms_only">שעון מעורר בלבד</string>
|
||||
<string name="alert_slider_mute_media_title">השתקת מדיה</string>
|
||||
<string name="alert_slider_mute_media_summary">השתקת מדיה במעבר להשתקה</string>
|
||||
</resources>
|
||||
12
KeyHandler/res/values-ta/strings.xml
Normal file
12
KeyHandler/res/values-ta/strings.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="alert_slider_top_position">முதற் நிலை</string>
|
||||
<string name="alert_slider_middle_position">நடு நிலை</string>
|
||||
<string name="alert_slider_bottom_position">கீழ் நிலை</string>
|
||||
<string name="alert_slider_mode_none">இல்லை</string>
|
||||
<string name="alert_slider_mode_silent">ஒலியின்மை</string>
|
||||
</resources>
|
||||
@@ -5,7 +5,7 @@
|
||||
-->
|
||||
<resources>
|
||||
<!-- Alert slider -->
|
||||
<string name="alert_slider_category_title">Alert slider</string>
|
||||
<string name="alert_slider_category_title">Alert slider settings</string>
|
||||
<string name="alert_slider_selection_dialog_title">Action</string>
|
||||
<string name="alert_slider_top_position">Top position</string>
|
||||
<string name="alert_slider_middle_position">Middle position</string>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The LineageOS Project
|
||||
SPDX-FileCopyrightText: 2021-2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory
|
||||
android:title="@string/alert_slider_category_title">
|
||||
|
||||
<SwitchPreference
|
||||
<SwitchPreferenceCompat
|
||||
android:key="config_mute_media"
|
||||
android:title="@string/alert_slider_mute_media_title"
|
||||
android:summary="@string/alert_slider_mute_media_summary"
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2024 The LineageOS Project
|
||||
* SPDX-FileCopyrightText: 2021-2025 The LineageOS Project
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.device
|
||||
|
||||
import android.os.Bundle
|
||||
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity
|
||||
|
||||
class ButtonSettingsActivity : CollapsingToolbarBaseActivity() {
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
fragmentManager.beginTransaction().replace(
|
||||
com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
||||
ButtonSettingsFragment()
|
||||
).commit()
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(
|
||||
com.android.settingslib.collapsingtoolbar.R.id.content_frame,
|
||||
ButtonSettingsFragment(),
|
||||
TAG
|
||||
).commit()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "ButtonSettingsActivity"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The LineageOS Project
|
||||
* SPDX-FileCopyrightText: 2021-2025 The LineageOS Project
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package org.lineageos.settings.device
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.preference.PreferenceFragment
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
|
||||
class ButtonSettingsFragment : PreferenceFragment() {
|
||||
class ButtonSettingsFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.button_panel)
|
||||
activity.actionBar!!.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
override fun addPreferencesFromResource(preferencesResId: Int) {
|
||||
super.addPreferencesFromResource(preferencesResId)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.home -> {
|
||||
activity.finish()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
setPreferencesFromResource(R.xml.button_panel, rootKey)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2023 The LineageOS Project
|
||||
* Copyright (C) 2021-2025 The LineageOS Project
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
@@ -41,10 +41,18 @@ class KeyHandler(context: Context) : DeviceKeyHandler {
|
||||
private var wasMuted = false
|
||||
private val broadcastReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
val stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1)
|
||||
val state = intent.getBooleanExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false)
|
||||
if (stream == AudioSystem.STREAM_MUSIC && !state) {
|
||||
wasMuted = false
|
||||
when (intent.action) {
|
||||
AudioManager.STREAM_MUTE_CHANGED_ACTION -> {
|
||||
val stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1)
|
||||
val state = intent.getBooleanExtra(
|
||||
AudioManager.EXTRA_STREAM_VOLUME_MUTED, false
|
||||
)
|
||||
if (stream == AudioSystem.STREAM_MUSIC && !state) {
|
||||
wasMuted = false
|
||||
}
|
||||
}
|
||||
|
||||
Intent.ACTION_BOOT_COMPLETED -> populateKeyState(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +60,10 @@ class KeyHandler(context: Context) : DeviceKeyHandler {
|
||||
init {
|
||||
context.registerReceiver(
|
||||
broadcastReceiver,
|
||||
IntentFilter(AudioManager.STREAM_MUTE_CHANGED_ACTION)
|
||||
IntentFilter().apply {
|
||||
addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION)
|
||||
addAction(Intent.ACTION_BOOT_COMPLETED)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -67,15 +78,19 @@ class KeyHandler(context: Context) : DeviceKeyHandler {
|
||||
return event
|
||||
}
|
||||
|
||||
when (File("/proc/tristatekey/tri_state").readText().trim()) {
|
||||
"1" -> handleMode(POSITION_TOP)
|
||||
"2" -> handleMode(POSITION_MIDDLE)
|
||||
"3" -> handleMode(POSITION_BOTTOM)
|
||||
}
|
||||
populateKeyState(true)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun populateKeyState(vibrate: Boolean) {
|
||||
when (File("/proc/tristatekey/tri_state").readText().trim()) {
|
||||
"1" -> handleMode(POSITION_TOP, vibrate)
|
||||
"2" -> handleMode(POSITION_MIDDLE, vibrate)
|
||||
"3" -> handleMode(POSITION_BOTTOM, vibrate)
|
||||
}
|
||||
}
|
||||
|
||||
private fun vibrateIfNeeded(mode: Int) {
|
||||
when (mode) {
|
||||
AudioManager.RINGER_MODE_VIBRATE -> vibrator.vibrate(
|
||||
@@ -89,7 +104,7 @@ class KeyHandler(context: Context) : DeviceKeyHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMode(position: Int) {
|
||||
private fun handleMode(position: Int, vibrate: Boolean) {
|
||||
val muteMedia = sharedPreferences.getBoolean(MUTE_MEDIA_WITH_SILENT, false)
|
||||
|
||||
val mode = when (position) {
|
||||
@@ -124,7 +139,10 @@ class KeyHandler(context: Context) : DeviceKeyHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
vibrateIfNeeded(mode)
|
||||
|
||||
if (vibrate) {
|
||||
vibrateIfNeeded(mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ android_app {
|
||||
|
||||
certificate: "platform",
|
||||
platform_apis: true,
|
||||
privileged: true,
|
||||
system_ext_specific: true,
|
||||
|
||||
optimize: {
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.lineageos.pen">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
||||
android:usesPermissionFlags="neverForLocation" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
-->
|
||||
<exceptions>
|
||||
<exception package="org.lineageos.pen">
|
||||
<permission name="android.permission.ACCESS_FINE_LOCATION" fixed="false" />
|
||||
<permission name="android.permission.BLUETOOTH_CONNECT" fixed="false" />
|
||||
<permission name="android.permission.BLUETOOTH_SCAN" fixed="false" />
|
||||
<permission name="android.permission.POST_NOTIFICATIONS" fixed="false" />
|
||||
|
||||
9
Pen/res/values-az/strings.xml
Normal file
9
Pen/res/values-az/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Qələm taxılıb</string>
|
||||
<string name="tap_to_connect">Bağlanmaq üçün toxunun</string>
|
||||
</resources>
|
||||
9
Pen/res/values-bg/strings.xml
Normal file
9
Pen/res/values-bg/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Дигитална писалка е сдвоена</string>
|
||||
<string name="tap_to_connect">Натисни за сдвояване</string>
|
||||
</resources>
|
||||
9
Pen/res/values-ca/strings.xml
Normal file
9
Pen/res/values-ca/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Bolígraf adjunt</string>
|
||||
<string name="tap_to_connect">Toqueu per connectar</string>
|
||||
</resources>
|
||||
9
Pen/res/values-cs/strings.xml
Normal file
9
Pen/res/values-cs/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Pero připojeno</string>
|
||||
<string name="tap_to_connect">Klepnutím připojit</string>
|
||||
</resources>
|
||||
9
Pen/res/values-el/strings.xml
Normal file
9
Pen/res/values-el/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Η γραφίδα προσαρτήθηκε</string>
|
||||
<string name="tap_to_connect">Πατήστε για σύνδεση</string>
|
||||
</resources>
|
||||
9
Pen/res/values-en-rAU/strings.xml
Normal file
9
Pen/res/values-en-rAU/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Pen attached</string>
|
||||
<string name="tap_to_connect">Tap to connect</string>
|
||||
</resources>
|
||||
9
Pen/res/values-en-rCA/strings.xml
Normal file
9
Pen/res/values-en-rCA/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Pen attached</string>
|
||||
<string name="tap_to_connect">Tap to connect</string>
|
||||
</resources>
|
||||
9
Pen/res/values-en-rGB/strings.xml
Normal file
9
Pen/res/values-en-rGB/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Pen attached</string>
|
||||
<string name="tap_to_connect">Tap to connect</string>
|
||||
</resources>
|
||||
9
Pen/res/values-en-rIN/strings.xml
Normal file
9
Pen/res/values-en-rIN/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Pen attached</string>
|
||||
<string name="tap_to_connect">Tap to connect</string>
|
||||
</resources>
|
||||
9
Pen/res/values-es/strings.xml
Normal file
9
Pen/res/values-es/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Bolígrafo adjunto</string>
|
||||
<string name="tap_to_connect">Toca para conectar</string>
|
||||
</resources>
|
||||
9
Pen/res/values-fa/strings.xml
Normal file
9
Pen/res/values-fa/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">قلم متصل شد</string>
|
||||
<string name="tap_to_connect">برای اتصال ضربه بزنید</string>
|
||||
</resources>
|
||||
9
Pen/res/values-fr/strings.xml
Normal file
9
Pen/res/values-fr/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Stylo attaché</string>
|
||||
<string name="tap_to_connect">Appuyer pour connecter</string>
|
||||
</resources>
|
||||
9
Pen/res/values-ga-rIE/strings.xml
Normal file
9
Pen/res/values-ga-rIE/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Peann ceangailte</string>
|
||||
<string name="tap_to_connect">Tapáil chun ceangal</string>
|
||||
</resources>
|
||||
9
Pen/res/values-hu/strings.xml
Normal file
9
Pen/res/values-hu/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Toll mellékelve</string>
|
||||
<string name="tap_to_connect">A csatlakoztatáshoz érintse meg</string>
|
||||
</resources>
|
||||
9
Pen/res/values-it/strings.xml
Normal file
9
Pen/res/values-it/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Penna attaccata</string>
|
||||
<string name="tap_to_connect">Tocca per connettere</string>
|
||||
</resources>
|
||||
9
Pen/res/values-iw/strings.xml
Normal file
9
Pen/res/values-iw/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">עט מצורף</string>
|
||||
<string name="tap_to_connect">נגיעה להתחברות</string>
|
||||
</resources>
|
||||
9
Pen/res/values-ja/strings.xml
Normal file
9
Pen/res/values-ja/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">ペンを装着しました</string>
|
||||
<string name="tap_to_connect">タップして接続</string>
|
||||
</resources>
|
||||
9
Pen/res/values-ka/strings.xml
Normal file
9
Pen/res/values-ka/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">კალამი მიუერთდა</string>
|
||||
<string name="tap_to_connect">შეეხეთ მიერთებისთვის</string>
|
||||
</resources>
|
||||
9
Pen/res/values-pl/strings.xml
Normal file
9
Pen/res/values-pl/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Dołączone pióro</string>
|
||||
<string name="tap_to_connect">Dotknij, aby połączyć</string>
|
||||
</resources>
|
||||
9
Pen/res/values-pt-rBR/strings.xml
Normal file
9
Pen/res/values-pt-rBR/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Caneta anexada</string>
|
||||
<string name="tap_to_connect">Toque para conectar</string>
|
||||
</resources>
|
||||
9
Pen/res/values-pt-rPT/strings.xml
Normal file
9
Pen/res/values-pt-rPT/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Caneta anexada</string>
|
||||
<string name="tap_to_connect">Toque para conectar</string>
|
||||
</resources>
|
||||
9
Pen/res/values-ro/strings.xml
Normal file
9
Pen/res/values-ro/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Stilou atașat</string>
|
||||
<string name="tap_to_connect">Atingeți pentru a conecta</string>
|
||||
</resources>
|
||||
8
Pen/res/values-ru/strings.xml
Normal file
8
Pen/res/values-ru/strings.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="tap_to_connect">Нажмите, чтобы подключить</string>
|
||||
</resources>
|
||||
9
Pen/res/values-sl/strings.xml
Normal file
9
Pen/res/values-sl/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Pisalo priključeno</string>
|
||||
<string name="tap_to_connect">Tapnite za povezavo</string>
|
||||
</resources>
|
||||
9
Pen/res/values-ta/strings.xml
Normal file
9
Pen/res/values-ta/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">எழுத்தாணி இணைக்கப்பட்டது</string>
|
||||
<string name="tap_to_connect">இணைக்கத் தட்டுக</string>
|
||||
</resources>
|
||||
9
Pen/res/values-ug/strings.xml
Normal file
9
Pen/res/values-ug/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">قەلەم ئۇلاندى</string>
|
||||
<string name="tap_to_connect">چېكىلسە باغلىنىدۇ</string>
|
||||
</resources>
|
||||
9
Pen/res/values-vi/strings.xml
Normal file
9
Pen/res/values-vi/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">Đã gắn bút</string>
|
||||
<string name="tap_to_connect">Chạm để kết nối</string>
|
||||
</resources>
|
||||
9
Pen/res/values-zh-rCN/strings.xml
Normal file
9
Pen/res/values-zh-rCN/strings.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="pen_attached">笔已连接</string>
|
||||
<string name="tap_to_connect">轻触以连接</string>
|
||||
</resources>
|
||||
9
Pen/res/values/config.xml
Normal file
9
Pen/res/values/config.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<!-- Max supported refresh rate when using pen. -->
|
||||
<string name="config_penSupportedRefreshRate" translatable="false"></string>
|
||||
</resources>
|
||||
@@ -17,14 +17,24 @@ import android.bluetooth.le.ScanResult
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.database.ContentObserver
|
||||
import android.hardware.input.InputManager
|
||||
import android.os.Handler
|
||||
import android.os.IBinder
|
||||
import android.os.UEventObserver
|
||||
import android.provider.Settings
|
||||
import android.provider.Settings.System.PEAK_REFRESH_RATE
|
||||
import android.util.Log
|
||||
|
||||
class PenService : Service() {
|
||||
private val bluetoothManager by lazy { getSystemService(BluetoothManager::class.java) }
|
||||
private val inputManager by lazy { getSystemService(InputManager::class.java) }
|
||||
private val notificationManager by lazy { getSystemService(NotificationManager::class.java) }
|
||||
|
||||
private val penSupportedRefreshRate by lazy { getString(R.string.config_penSupportedRefreshRate) }
|
||||
|
||||
private val handler by lazy { Handler(mainLooper) }
|
||||
|
||||
private val observer = object : UEventObserver() {
|
||||
private val lock = Any()
|
||||
|
||||
@@ -43,6 +53,30 @@ class PenService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
private val inputObserver = object : InputManager.InputDeviceListener {
|
||||
override fun onInputDeviceAdded(deviceId: Int) {
|
||||
overridePeakRefreshRateIfNeeded()
|
||||
}
|
||||
|
||||
override fun onInputDeviceRemoved(deviceId: Int) {
|
||||
overridePeakRefreshRateIfNeeded()
|
||||
}
|
||||
|
||||
override fun onInputDeviceChanged(deviceId: Int) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
private val peakRefreshRateSettingsObserver by lazy {
|
||||
object : ContentObserver(handler) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
super.onChange(selfChange)
|
||||
|
||||
overridePeakRefreshRateIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
intent?.getStringExtra(EXTRA_PENCIL_ADDR)?.let {
|
||||
bondBtDevice(it)
|
||||
@@ -56,12 +90,28 @@ class PenService : Service() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
if (!penSupportedRefreshRate.isEmpty()) {
|
||||
contentResolver.registerContentObserver(
|
||||
Settings.System.getUriFor(PEAK_REFRESH_RATE),
|
||||
false,
|
||||
peakRefreshRateSettingsObserver
|
||||
)
|
||||
peakRefreshRateSettingsObserver.onChange(true)
|
||||
|
||||
inputManager.registerInputDeviceListener(inputObserver, handler)
|
||||
}
|
||||
|
||||
observer.startObserving("DEVPATH=/devices/virtual/oplus_wireless/pencil")
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
if (!penSupportedRefreshRate.isEmpty()) {
|
||||
contentResolver.unregisterContentObserver(peakRefreshRateSettingsObserver)
|
||||
inputManager.unregisterInputDeviceListener(inputObserver)
|
||||
}
|
||||
|
||||
observer.stopObserving()
|
||||
}
|
||||
|
||||
@@ -69,8 +119,16 @@ class PenService : Service() {
|
||||
val adapter = bluetoothManager.adapter
|
||||
@Suppress("DEPRECATION") adapter.enable()
|
||||
|
||||
val scanner = adapter.bluetoothLeScanner
|
||||
scanner.startScan(
|
||||
val scanner = run {
|
||||
repeat(50) {
|
||||
adapter.bluetoothLeScanner?.let {
|
||||
return@run it
|
||||
}
|
||||
Thread.sleep(100)
|
||||
}
|
||||
return@run null
|
||||
}
|
||||
scanner?.startScan(
|
||||
listOf(ScanFilter.Builder().setDeviceAddress(pencilAddr).build()),
|
||||
ScanSettings.Builder()
|
||||
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
|
||||
@@ -97,6 +155,29 @@ class PenService : Service() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun overridePeakRefreshRateIfNeeded() {
|
||||
val isPenConnected = inputManager.inputDeviceIds.firstOrNull {
|
||||
val device = inputManager.getInputDevice(it) ?: return@firstOrNull false
|
||||
if (device.vendorId != 0x22D9 && device.vendorId != 0x330A) {
|
||||
// Not an OPPO/Maxeye vendor ID
|
||||
return@firstOrNull false
|
||||
}
|
||||
if (device.bluetoothAddress?.startsWith("C0:87:06") == false &&
|
||||
device.bluetoothAddress?.startsWith("F8:6F:DE") == false) {
|
||||
// Not a Maxeye/Goodix MAC prefix
|
||||
return@firstOrNull false
|
||||
}
|
||||
return@firstOrNull true
|
||||
} != null
|
||||
val peakRefreshRate = Settings.System.getString(contentResolver, PEAK_REFRESH_RATE)
|
||||
|
||||
if (isPenConnected && peakRefreshRate == "Infinity") {
|
||||
Settings.System.putString(contentResolver, PEAK_REFRESH_RATE, penSupportedRefreshRate)
|
||||
} else if (!isPenConnected && peakRefreshRate == penSupportedRefreshRate) {
|
||||
Settings.System.putString(contentResolver, PEAK_REFRESH_RATE, "Infinity")
|
||||
}
|
||||
}
|
||||
|
||||
private fun postNotification(pencilAddr: String) {
|
||||
val adapter = bluetoothManager.adapter
|
||||
|
||||
|
||||
@@ -16,4 +16,3 @@
|
||||
| OPLUS_LINEAGE_TOUCH_HAL | USE_OPLUSTOUCH | Use and interface with stock OplusTouch | false |
|
||||
| OPLUS_LINEAGE_VIBRATOR_HAL | INCLUDE_DIR | Device specific include dir path | |
|
||||
| OPLUS_LINEAGE_VIBRATOR_HAL | USE_EFFECT_STREAM | Enable effect stream feature | false |
|
||||
| QTI_GPT_UTILS | USE_BSG_FRAMEWORK | Enable BSG framework feature | true |
|
||||
|
||||
@@ -26,15 +26,15 @@ ConsumerIr::ConsumerIr() : supportedFreqs({{MIN_FREQ, MAX_FREQ}}) {}
|
||||
return ::ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
::ndk::ScopedAStatus ConsumerIr::transmit(int32_t in_carrierFreqHz,
|
||||
const std::vector<int32_t>& in_pattern) {
|
||||
if (in_carrierFreqHz < MIN_FREQ || in_carrierFreqHz > MAX_FREQ) {
|
||||
LOG(ERROR) << "Invalid carrier frequency: " << in_carrierFreqHz;
|
||||
::ndk::ScopedAStatus ConsumerIr::transmit(int32_t carrierFreqHz,
|
||||
const std::vector<int32_t>& pattern) {
|
||||
if (carrierFreqHz < MIN_FREQ || carrierFreqHz > MAX_FREQ) {
|
||||
LOG(ERROR) << "Invalid carrier frequency: " << carrierFreqHz;
|
||||
return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
int32_t totalTime = 0;
|
||||
for (int32_t value : in_pattern) {
|
||||
for (int32_t value : pattern) {
|
||||
if (value < 0) {
|
||||
LOG(ERROR) << "Invalid pattern value: " << value;
|
||||
return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
@@ -53,7 +53,7 @@ ConsumerIr::ConsumerIr() : supportedFreqs({{MIN_FREQ, MAX_FREQ}}) {}
|
||||
return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
size_t paramsSize = sizeof(struct pattern_params) + in_pattern.size() * sizeof(int32_t);
|
||||
size_t paramsSize = sizeof(struct pattern_params) + pattern.size() * sizeof(int32_t);
|
||||
auto params = std::unique_ptr<struct pattern_params, decltype(&free)>(
|
||||
static_cast<pattern_params*>(malloc(paramsSize)), free);
|
||||
if (!params) {
|
||||
@@ -61,9 +61,9 @@ ConsumerIr::ConsumerIr() : supportedFreqs({{MIN_FREQ, MAX_FREQ}}) {}
|
||||
return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
params->carrier_freq = in_carrierFreqHz;
|
||||
params->size = in_pattern.size();
|
||||
memcpy(params->pattern, in_pattern.data(), in_pattern.size() * sizeof(int32_t));
|
||||
params->carrier_freq = carrierFreqHz;
|
||||
params->size = pattern.size();
|
||||
memcpy(params->pattern, pattern.data(), pattern.size() * sizeof(int32_t));
|
||||
|
||||
int result = ioctl(fd, IR_SEND_PATTERN, params.get());
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ class ConsumerIr : public BnConsumerIr {
|
||||
|
||||
private:
|
||||
::ndk::ScopedAStatus getCarrierFreqs(std::vector<ConsumerIrFreqRange>* _aidl_return) override;
|
||||
::ndk::ScopedAStatus transmit(int32_t in_carrierFreqHz,
|
||||
const std::vector<int32_t>& in_pattern) override;
|
||||
::ndk::ScopedAStatus transmit(int32_t carrierFreqHz,
|
||||
const std::vector<int32_t>& pattern) override;
|
||||
|
||||
std::vector<ConsumerIrFreqRange> supportedFreqs;
|
||||
};
|
||||
|
||||
@@ -19,7 +19,9 @@ AntiFlicker::AntiFlicker() : mOplusDisplayFd(open("/dev/oplus_display", O_RDWR))
|
||||
|
||||
ndk::ScopedAStatus AntiFlicker::getEnabled(bool* _aidl_return) {
|
||||
unsigned int value;
|
||||
if (ioctl(mOplusDisplayFd, PANEL_IOCTL_GET_DIMLAYER_BL_EN, &value) != 0) {
|
||||
if (ioctl(mOplusDisplayFd, PANEL_IOCTL_GET_PWM_PULSE, &value) != 0 &&
|
||||
ioctl(mOplusDisplayFd, PANEL_IOCTL_GET_PWM_TURBO, &value) != 0 &&
|
||||
ioctl(mOplusDisplayFd, PANEL_IOCTL_GET_DIMLAYER_BL_EN, &value) != 0) {
|
||||
LOG(ERROR) << "Failed to read current AntiFlicker state";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
}
|
||||
@@ -33,7 +35,8 @@ ndk::ScopedAStatus AntiFlicker::setEnabled(bool enabled) {
|
||||
return status;
|
||||
}
|
||||
unsigned int value = enabled;
|
||||
if (isEnabled != enabled &&
|
||||
if (isEnabled != enabled && ioctl(mOplusDisplayFd, PANEL_IOCTL_SET_PWM_PULSE, &value) != 0 &&
|
||||
ioctl(mOplusDisplayFd, PANEL_IOCTL_SET_PWM_TURBO, &value) != 0 &&
|
||||
ioctl(mOplusDisplayFd, PANEL_IOCTL_SET_DIMLAYER_BL_EN, &value) != 0) {
|
||||
LOG(ERROR) << "Failed to set AntiFlicker state";
|
||||
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
|
||||
|
||||
21
aidl/performance/Android.bp
Normal file
21
aidl/performance/Android.bp
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
cc_binary {
|
||||
name: "vendor.oplus.hardware.performance-service",
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
init_rc: ["vendor.oplus.hardware.performance-service.rc"],
|
||||
vintf_fragments: ["vendor.oplus.hardware.performance-service.xml"],
|
||||
srcs: [
|
||||
"Performance.cpp",
|
||||
"service.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"vendor.oplus.hardware.performance-V1-ndk",
|
||||
],
|
||||
}
|
||||
1079
aidl/performance/Performance.cpp
Normal file
1079
aidl/performance/Performance.cpp
Normal file
File diff suppressed because it is too large
Load Diff
234
aidl/performance/Performance.h
Normal file
234
aidl/performance/Performance.h
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <aidl/vendor/oplus/hardware/performance/BnPerformance.h>
|
||||
|
||||
namespace aidl {
|
||||
namespace vendor {
|
||||
namespace oplus {
|
||||
namespace hardware {
|
||||
namespace performance {
|
||||
|
||||
class Performance : public BnPerformance {
|
||||
ndk::ScopedAStatus addAcmDirName(const std::string& dirname, int64_t flag,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus addAcmNomediaDirName(const std::string& dirname,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus addAcmPkgName(const std::string& pkgname, int64_t flag,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus addTaskTrackPid(int32_t group, int32_t pid, bool clear,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus clearTaskTrackGroup(int32_t group) override;
|
||||
ndk::ScopedAStatus delAcmDirName(const std::string& dirname, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus delAcmNomediaDirName(const std::string& dirname,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus delAcmPkgName(const std::string& pkgname, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus disableDamonReclaim(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus disableKmallocDebug(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus disableMultiThreadOptimize(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus disableProcessReclaim(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus disableTaskCpustats(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus disableTaskPlacementDecision(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus disableVmallocDebug(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus enableAudioPerf(const std::string& value, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus enableDamonReclaim(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus enableKmallocDebug(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus enableMultiThreadOptimize(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus enableProcessReclaim(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus enableTaskCpustats(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus enableTaskPlacementDecision(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus enableVmallocDebug(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus existMemMonitor(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAcmDirFlag(const std::string& dirname, int64_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAcmOpstat(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getAcmPkgFlag(const std::string& pkgname, int64_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getClmMuxSwitch(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getClmThreshold(int32_t threshold_id, std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getDdrResidency(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getDevinfoDDRInfo(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getDevinfoUfsInfo(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getDevinfoUfsVersionInfo(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getExt4FragScore(const std::string& devpath,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getExt4FreefragInfo(const std::string& devpath,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getF2fsMovedBlks(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIAllocWait(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHICpuInfo(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHICpuLoading(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIDState(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIEmcdrvIowait(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIFsyncWait(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIIonWait(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIIowait(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIIowaitHung(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIKswapdLoading(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHISchedLatency(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIScmCall(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getHIUfsFeature(ProcReqHal* _aidl_return) override;
|
||||
ndk::ScopedAStatus getKernelVersion(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getKmallocDebug(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getKmallocOrigin(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getKmallocUsed(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getMemMonitor(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getOswapVersion(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getUfsSignalRecordUpload(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getUfsplusHpbStatus(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getUfsplusTwStatus(int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus getVmallocDebug(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getVmallocHashCal(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getVmallocUsed(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getWakeThreadsAffinityOrdered(const std::string& handle, int32_t size,
|
||||
TaskWakeInfo* _aidl_return) override;
|
||||
ndk::ScopedAStatus getallocwait(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getdstate(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getfsyncwait(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getionwait(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getiowait(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus getschedlatency(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus hybridswap_memcg_para_read(int32_t action, const std::string& cgroup,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus hybridswap_memcg_para_write(int32_t action, const std::string& cgroup,
|
||||
const std::string& str,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus hybridswap_zram_para_read(int32_t action,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus hybridswap_zram_para_write(int32_t action, const std::string& str,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus isJankTaskTrackEnable(bool* _aidl_return) override;
|
||||
ndk::ScopedAStatus perProcessMemReadahead(int32_t uid, int32_t pid, int32_t type,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus perProcessMemReclaim(int32_t uid, int32_t pid, int32_t type,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus readCallStack(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readClmEnable(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readClmHighLoadAll(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readClmHighLoadGrp(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readClmLowLoadGrp(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readCpuTaskstats(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readDBacktrace(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readDConvert(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readFgFreqsThreshold(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readIOBacktrace(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readIomonitorInfo(const std::string& procname,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankCpuIndicator(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankCpuInfo(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankCpuInfoSig(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankCpuLoad(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankCpuLoad32(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankCpuLoad32Scale(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankTaskTrack(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankTaskTrackByPid(int32_t pid, std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readJankVersion(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readKmallocDebugCreate(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readLimitTable(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readMemleakDetectThread(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readMemoryByPids(const std::vector<int32_t>& pids, int32_t flags,
|
||||
ProcMemStatRet* _aidl_return) override;
|
||||
ndk::ScopedAStatus readMemoryByUids(const std::vector<int32_t>& uids, int32_t flags,
|
||||
ProcMemStatRet* _aidl_return) override;
|
||||
ndk::ScopedAStatus readNandswapProc(const std::string& inProc,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readNormalizeRealTime(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readNormalizeRunningTime(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readOplusReserve3(int32_t offset, int32_t len,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readOsvelteVersion(OsvelteVersionRet* _aidl_return) override;
|
||||
ndk::ScopedAStatus readPidsSet(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readRealTime(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readRunningTime(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readSchedInfoThreshold(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readSgeFreqInfo(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readSgeInfo(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readStorageFeature(const std::string& name, const std::string& addr,
|
||||
const std::string& isMulti,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readTargetProcess(const std::string& buffer,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readTaskCpustatsEnable(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readTaskSchedInfo(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readTidsSet(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readTmemoryDirtypages(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readTmemoryErrorStat(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readTmemoryIoLatency(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readTmemorySysdirtypages(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readUxTaskTrack(int32_t uPid, int32_t rPid,
|
||||
std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readVaFeature(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus readVersion(std::string* _aidl_return) override;
|
||||
ndk::ScopedAStatus removeTaskTrackPid(int32_t group, int32_t pid) override;
|
||||
ndk::ScopedAStatus searchAcmNomediaDirName(const std::string& dirname,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setAcmOpstat(int32_t flag, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setClmMuxSwitch(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus setClmThreshold(const std::string& buffer, int32_t threshold_id) override;
|
||||
ndk::ScopedAStatus setDamonReclaimColdTime(int32_t cold_time, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setDamonReclaimMonitoring(int32_t sample, int32_t aggr,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setDamonReclaimQuota(int32_t quota_ms, int32_t quota_sz,
|
||||
int32_t reset_interval, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setDamonReclaimWmarks(int32_t metric, int32_t high, int32_t mid, int32_t low,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setExtSchedProp(const std::string& pid, const std::string& prop) override;
|
||||
ndk::ScopedAStatus setFgUids(const std::string& fg_uid) override;
|
||||
ndk::ScopedAStatus setFrameRate(const std::string& frame_rate) override;
|
||||
ndk::ScopedAStatus setFreqGoverner(const std::string& gov_name,
|
||||
const std::vector<int32_t>& clusters,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setImFlag(const std::string& pid, const std::string& im_flag) override;
|
||||
ndk::ScopedAStatus setProcessReclaim(const std::string& info, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setSchedAssistImptTask(const std::string& impt_info) override;
|
||||
ndk::ScopedAStatus setSchedAssistScene(const std::string& scene_id) override;
|
||||
ndk::ScopedAStatus setSlideboost(const std::string& boost) override;
|
||||
ndk::ScopedAStatus setTpdID(const std::string& param, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setTpdSerialParams(const std::string& params,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus setWakeSeedThread(const std::string& tid, bool identify_type, bool inUid,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeClmEnable(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeClmHighLoadAll(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeClmHighLoadGrp(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeClmLowLoadGrp(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeDBacktrace(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeFgFreqsThreshold(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeIOBacktrace(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeJankTaskTrackEnable(bool enable) override;
|
||||
ndk::ScopedAStatus writeKmallocDebugCreate(int32_t kcreate, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeKmallocDebugCreateWithType(const std::string& type,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeMemMonitor(const std::string& buffer, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeMemleakDetectThread(int32_t memdect, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeMonitorStatus(const std::string& buffer,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeNandswapProc(const std::string& inProc, const std::string& cmd,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeOplusReserve3(int32_t offset, int32_t len, const std::string& info,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writePidsSet(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeSchedInfoThreshold(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeStorageFeature(const std::string& name, const std::string& addr,
|
||||
const std::string& isMulti, const std::string& cmd,
|
||||
int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeTaskSchedInfo(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeTidsSet(const std::string& buffer) override;
|
||||
ndk::ScopedAStatus writeTmemoryCapacity(int32_t param, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeTmemoryFlushBusy(int32_t param, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeTmemoryFlushIdle(int32_t param, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeTmemoryHighWaterRatio(int32_t param, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeTmemoryMemory(const std::string& str, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeTmemorySwitch(int32_t param, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeUxState(const std::string& ux_state, const std::string& pid,
|
||||
const std::string& tid, int32_t* _aidl_return) override;
|
||||
ndk::ScopedAStatus writeVaFeature(int32_t vafeature, int32_t* _aidl_return) override;
|
||||
};
|
||||
|
||||
} // namespace performance
|
||||
} // namespace hardware
|
||||
} // namespace oplus
|
||||
} // namespace vendor
|
||||
} // namespace aidl
|
||||
25
aidl/performance/service.cpp
Normal file
25
aidl/performance/service.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 The LineageOS Project
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "Performance.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
|
||||
using ::aidl::vendor::oplus::hardware::performance::Performance;
|
||||
|
||||
int main() {
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(0);
|
||||
std::shared_ptr<Performance> performance = ndk::SharedRefBase::make<Performance>();
|
||||
|
||||
const std::string instance = std::string() + Performance::descriptor + "/default";
|
||||
binder_status_t status =
|
||||
AServiceManager_addService(performance->asBinder().get(), instance.c_str());
|
||||
CHECK_EQ(status, STATUS_OK);
|
||||
|
||||
ABinderProcess_joinThreadPool();
|
||||
return EXIT_FAILURE; // should not reach
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
service oplus.performance.hal.service /vendor/bin/hw/vendor.oplus.hardware.performance-service
|
||||
class hal
|
||||
user system
|
||||
group system
|
||||
@@ -0,0 +1,7 @@
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>vendor.oplus.hardware.performance</name>
|
||||
<version>1</version>
|
||||
<fqname>IPerformance/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
1
aidl/sensors/.clang-format
Symbolic link
1
aidl/sensors/.clang-format
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../build/soong/scripts/system-clang-format
|
||||
57
aidl/sensors/Android.bp
Normal file
57
aidl/sensors/Android.bp
Normal file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Copyright (C) 2021 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package {
|
||||
// See: http://go/android-license-faq
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
cc_binary {
|
||||
name: "android.hardware.sensors-service.oplus-multihal",
|
||||
vendor: true,
|
||||
relative_install_path: "hw",
|
||||
srcs: [
|
||||
"service.cpp",
|
||||
"HalProxy.cpp",
|
||||
"HalProxyCallback.cpp",
|
||||
],
|
||||
header_libs: [
|
||||
"android.hardware.sensors@2.X-multihal.header",
|
||||
"android.hardware.sensors@2.X-shared-utils",
|
||||
],
|
||||
init_rc: ["android.hardware.sensors-service.oplus-multihal.rc"],
|
||||
vintf_fragments: ["android.hardware.sensors.oplus-multihal.xml"],
|
||||
shared_libs: [
|
||||
"android.hardware.sensors@2.0-ScopedWakelock",
|
||||
"android.hardware.sensors@2.0",
|
||||
"android.hardware.sensors@2.1",
|
||||
"android.hardware.sensors-V3-ndk",
|
||||
"libbase",
|
||||
"libcutils",
|
||||
"libfmq",
|
||||
"liblog",
|
||||
"libpower",
|
||||
"libutils",
|
||||
"libbinder_ndk",
|
||||
"libhidlbase",
|
||||
],
|
||||
static_libs: [
|
||||
"libaidlcommonsupport",
|
||||
"android.hardware.sensors@1.0-convert",
|
||||
"android.hardware.sensors@2.X-multihal",
|
||||
"android.hardware.sensors@aidl-multihal",
|
||||
],
|
||||
}
|
||||
810
aidl/sensors/HalProxy.cpp
Normal file
810
aidl/sensors/HalProxy.cpp
Normal file
@@ -0,0 +1,810 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "HalProxy.h"
|
||||
|
||||
#include <android/hardware/sensors/2.0/types.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include "hardware_legacy/power.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace V2_1 {
|
||||
namespace implementation {
|
||||
|
||||
using ::android::hardware::sensors::V1_0::Result;
|
||||
using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
|
||||
using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
|
||||
using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
|
||||
using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
|
||||
|
||||
typedef V2_0::implementation::ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
|
||||
typedef V2_1::implementation::ISensorsSubHal*(SensorsHalGetSubHalV2_1Func)(uint32_t*);
|
||||
|
||||
static constexpr int32_t kBitsAfterSubHalIndex = 24;
|
||||
|
||||
/**
|
||||
* Set the subhal index as first byte of sensor handle and return this modified version.
|
||||
*
|
||||
* @param sensorHandle The sensor handle to modify.
|
||||
* @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
|
||||
*
|
||||
* @return The modified sensor handle.
|
||||
*/
|
||||
int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
|
||||
return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the subHalIndex from sensorHandle.
|
||||
*
|
||||
* @param sensorHandle The sensorHandle to extract from.
|
||||
*
|
||||
* @return The subhal index.
|
||||
*/
|
||||
size_t extractSubHalIndex(int32_t sensorHandle) {
|
||||
return static_cast<size_t>(sensorHandle >> kBitsAfterSubHalIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert nanoseconds to milliseconds.
|
||||
*
|
||||
* @param nanos The nanoseconds input.
|
||||
*
|
||||
* @return The milliseconds count.
|
||||
*/
|
||||
int64_t msFromNs(int64_t nanos) {
|
||||
constexpr int64_t nanosecondsInAMillsecond = 1000000;
|
||||
return nanos / nanosecondsInAMillsecond;
|
||||
}
|
||||
|
||||
bool patchOplusGlanceSensor(V2_1::SensorInfo& sensor) {
|
||||
if (sensor.typeAsString != "qti.sensor.amd") {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
* Implement only the wake-up version of this sensor.
|
||||
*/
|
||||
if (!(sensor.flags & V1_0::SensorFlagBits::WAKE_UP)) {
|
||||
return false;
|
||||
}
|
||||
sensor.type = V2_1::SensorType::GLANCE_GESTURE;
|
||||
sensor.typeAsString = SENSOR_STRING_TYPE_GLANCE_GESTURE;
|
||||
sensor.maxRange = 2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool patchOplusPickupSensor(V2_1::SensorInfo& sensor) {
|
||||
if (sensor.typeAsString != "android.sensor.tilt_detector") {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement only the wake-up version of this sensor.
|
||||
*/
|
||||
if (!(sensor.flags & V1_0::SensorFlagBits::WAKE_UP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sensor.type = V2_1::SensorType::PICK_UP_GESTURE;
|
||||
sensor.typeAsString = SENSOR_STRING_TYPE_PICK_UP_GESTURE;
|
||||
sensor.maxRange = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
HalProxy::HalProxy() {
|
||||
static const std::string kMultiHalConfigFiles[] = {"/vendor/etc/sensors/hals.conf",
|
||||
"/odm/etc/sensors/hals.conf"};
|
||||
for (const std::string& configFile : kMultiHalConfigFiles) {
|
||||
initializeSubHalListFromConfigFile(configFile.c_str());
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
HalProxy::HalProxy(std::vector<ISensorsSubHalV2_0*>& subHalList) {
|
||||
for (ISensorsSubHalV2_0* subHal : subHalList) {
|
||||
mSubHalList.push_back(std::make_unique<SubHalWrapperV2_0>(subHal));
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
HalProxy::HalProxy(std::vector<ISensorsSubHalV2_0*>& subHalList,
|
||||
std::vector<ISensorsSubHalV2_1*>& subHalListV2_1) {
|
||||
for (ISensorsSubHalV2_0* subHal : subHalList) {
|
||||
mSubHalList.push_back(std::make_unique<SubHalWrapperV2_0>(subHal));
|
||||
}
|
||||
|
||||
for (ISensorsSubHalV2_1* subHal : subHalListV2_1) {
|
||||
mSubHalList.push_back(std::make_unique<SubHalWrapperV2_1>(subHal));
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
HalProxy::~HalProxy() {
|
||||
stopThreads();
|
||||
}
|
||||
|
||||
Return<void> HalProxy::getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _hidl_cb) {
|
||||
std::vector<V2_1::SensorInfo> sensors;
|
||||
for (const auto& iter : mSensors) {
|
||||
sensors.push_back(iter.second);
|
||||
}
|
||||
_hidl_cb(sensors);
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> HalProxy::getSensorsList(ISensorsV2_0::getSensorsList_cb _hidl_cb) {
|
||||
std::vector<V1_0::SensorInfo> sensors;
|
||||
for (const auto& iter : mSensors) {
|
||||
if (iter.second.type != SensorType::HINGE_ANGLE) {
|
||||
sensors.push_back(convertToOldSensorInfo(iter.second));
|
||||
}
|
||||
}
|
||||
_hidl_cb(sensors);
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::setOperationMode(OperationMode mode) {
|
||||
Result result = Result::OK;
|
||||
size_t subHalIndex;
|
||||
for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
|
||||
result = mSubHalList[subHalIndex]->setOperationMode(mode);
|
||||
if (result != Result::OK) {
|
||||
ALOGE("setOperationMode failed for SubHal: %s",
|
||||
mSubHalList[subHalIndex]->getName().c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != Result::OK) {
|
||||
// Reset the subhal operation modes that have been flipped
|
||||
for (size_t i = 0; i < subHalIndex; i++) {
|
||||
mSubHalList[i]->setOperationMode(mCurrentOperationMode);
|
||||
}
|
||||
} else {
|
||||
mCurrentOperationMode = mode;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
|
||||
if (!isSubHalIndexValid(sensorHandle)) {
|
||||
return Result::BAD_VALUE;
|
||||
}
|
||||
return getSubHalForSensorHandle(sensorHandle)
|
||||
->activate(clearSubHalIndex(sensorHandle), enabled);
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::initialize_2_1(
|
||||
const ::android::hardware::MQDescriptorSync<V2_1::Event>& eventQueueDescriptor,
|
||||
const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
|
||||
const sp<V2_1::ISensorsCallback>& sensorsCallback) {
|
||||
sp<ISensorsCallbackWrapperBase> dynamicCallback =
|
||||
new ISensorsCallbackWrapperV2_1(sensorsCallback);
|
||||
|
||||
// Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
|
||||
auto eventQueue =
|
||||
std::make_unique<EventMessageQueueV2_1>(eventQueueDescriptor, true /* resetPointers */);
|
||||
std::unique_ptr<EventMessageQueueWrapperBase> queue =
|
||||
std::make_unique<EventMessageQueueWrapperV2_1>(eventQueue);
|
||||
|
||||
// Create the Wake Lock FMQ from the wakeLockDescriptor. Reset the read/write positions.
|
||||
auto hidlWakeLockQueue =
|
||||
std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
|
||||
std::unique_ptr<WakeLockMessageQueueWrapperBase> wakeLockQueue =
|
||||
std::make_unique<WakeLockMessageQueueWrapperHidl>(hidlWakeLockQueue);
|
||||
|
||||
return initializeCommon(queue, wakeLockQueue, dynamicCallback);
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::initialize(
|
||||
const ::android::hardware::MQDescriptorSync<V1_0::Event>& eventQueueDescriptor,
|
||||
const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
|
||||
const sp<V2_0::ISensorsCallback>& sensorsCallback) {
|
||||
sp<ISensorsCallbackWrapperBase> dynamicCallback =
|
||||
new ISensorsCallbackWrapperV2_0(sensorsCallback);
|
||||
|
||||
// Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
|
||||
auto eventQueue =
|
||||
std::make_unique<EventMessageQueueV2_0>(eventQueueDescriptor, true /* resetPointers */);
|
||||
std::unique_ptr<EventMessageQueueWrapperBase> queue =
|
||||
std::make_unique<EventMessageQueueWrapperV1_0>(eventQueue);
|
||||
|
||||
// Create the Wake Lock FMQ from the wakeLockDescriptor. Reset the read/write positions.
|
||||
auto hidlWakeLockQueue =
|
||||
std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
|
||||
std::unique_ptr<WakeLockMessageQueueWrapperBase> wakeLockQueue =
|
||||
std::make_unique<WakeLockMessageQueueWrapperHidl>(hidlWakeLockQueue);
|
||||
|
||||
return initializeCommon(queue, wakeLockQueue, dynamicCallback);
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::initializeCommon(
|
||||
std::unique_ptr<EventMessageQueueWrapperBase>& eventQueue,
|
||||
std::unique_ptr<WakeLockMessageQueueWrapperBase>& wakeLockQueue,
|
||||
const sp<ISensorsCallbackWrapperBase>& sensorsCallback) {
|
||||
Result result = Result::OK;
|
||||
|
||||
stopThreads();
|
||||
resetSharedWakelock();
|
||||
|
||||
// So that the pending write events queue can be cleared safely and when we start threads
|
||||
// again we do not get new events until after initialize resets the subhals.
|
||||
disableAllSensors();
|
||||
|
||||
// Clears the queue if any events were pending write before.
|
||||
mPendingWriteEventsQueue = std::queue<std::pair<std::vector<V2_1::Event>, size_t>>();
|
||||
mSizePendingWriteEventsQueue = 0;
|
||||
|
||||
// Clears previously connected dynamic sensors
|
||||
mDynamicSensors.clear();
|
||||
|
||||
mDynamicSensorsCallback = sensorsCallback;
|
||||
|
||||
// Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
|
||||
mEventQueue = std::move(eventQueue);
|
||||
|
||||
// Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
|
||||
// events have been successfully read and handled by the framework.
|
||||
mWakeLockQueue = std::move(wakeLockQueue);
|
||||
|
||||
if (mEventQueueFlag != nullptr) {
|
||||
EventFlag::deleteEventFlag(&mEventQueueFlag);
|
||||
}
|
||||
if (mWakelockQueueFlag != nullptr) {
|
||||
EventFlag::deleteEventFlag(&mWakelockQueueFlag);
|
||||
}
|
||||
if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
|
||||
result = Result::BAD_VALUE;
|
||||
}
|
||||
if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
|
||||
result = Result::BAD_VALUE;
|
||||
}
|
||||
if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
|
||||
result = Result::BAD_VALUE;
|
||||
}
|
||||
|
||||
mThreadsRun.store(true);
|
||||
|
||||
mPendingWritesThread = std::thread(startPendingWritesThread, this);
|
||||
mWakelockThread = std::thread(startWakelockThread, this);
|
||||
|
||||
for (size_t i = 0; i < mSubHalList.size(); i++) {
|
||||
Result currRes = mSubHalList[i]->initialize(this, this, i);
|
||||
if (currRes != Result::OK) {
|
||||
result = currRes;
|
||||
ALOGE("Subhal '%s' failed to initialize with reason %" PRId32 ".",
|
||||
mSubHalList[i]->getName().c_str(), static_cast<int32_t>(currRes));
|
||||
}
|
||||
}
|
||||
|
||||
mCurrentOperationMode = OperationMode::NORMAL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
|
||||
int64_t maxReportLatencyNs) {
|
||||
if (!isSubHalIndexValid(sensorHandle)) {
|
||||
return Result::BAD_VALUE;
|
||||
}
|
||||
return getSubHalForSensorHandle(sensorHandle)
|
||||
->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::flush(int32_t sensorHandle) {
|
||||
if (!isSubHalIndexValid(sensorHandle)) {
|
||||
return Result::BAD_VALUE;
|
||||
}
|
||||
return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::injectSensorData_2_1(const V2_1::Event& event) {
|
||||
return injectSensorData(convertToOldEvent(event));
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::injectSensorData(const V1_0::Event& event) {
|
||||
Result result = Result::OK;
|
||||
if (mCurrentOperationMode == OperationMode::NORMAL &&
|
||||
event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) {
|
||||
ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation"
|
||||
" mode was NORMAL.");
|
||||
result = Result::BAD_VALUE;
|
||||
}
|
||||
if (result == Result::OK) {
|
||||
V1_0::Event subHalEvent = event;
|
||||
if (!isSubHalIndexValid(event.sensorHandle)) {
|
||||
return Result::BAD_VALUE;
|
||||
}
|
||||
subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
|
||||
result = getSubHalForSensorHandle(event.sensorHandle)
|
||||
->injectSensorData(convertToNewEvent(subHalEvent));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& mem,
|
||||
ISensorsV2_0::registerDirectChannel_cb _hidl_cb) {
|
||||
if (mDirectChannelSubHal == nullptr) {
|
||||
_hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
|
||||
} else {
|
||||
mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb);
|
||||
}
|
||||
return Return<void>();
|
||||
}
|
||||
|
||||
Return<Result> HalProxy::unregisterDirectChannel(int32_t channelHandle) {
|
||||
Result result;
|
||||
if (mDirectChannelSubHal == nullptr) {
|
||||
result = Result::INVALID_OPERATION;
|
||||
} else {
|
||||
result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Return<void> HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
|
||||
RateLevel rate,
|
||||
ISensorsV2_0::configDirectReport_cb _hidl_cb) {
|
||||
if (mDirectChannelSubHal == nullptr) {
|
||||
_hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */);
|
||||
} else if (sensorHandle == -1 && rate != RateLevel::STOP) {
|
||||
_hidl_cb(Result::BAD_VALUE, -1 /* reportToken */);
|
||||
} else {
|
||||
// -1 denotes all sensors should be disabled
|
||||
if (sensorHandle != -1) {
|
||||
sensorHandle = clearSubHalIndex(sensorHandle);
|
||||
}
|
||||
mDirectChannelSubHal->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
|
||||
}
|
||||
return Return<void>();
|
||||
}
|
||||
|
||||
Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
|
||||
if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
|
||||
ALOGE("%s: missing fd for writing", __FUNCTION__);
|
||||
return Void();
|
||||
}
|
||||
|
||||
int writeFd = fd->data[0];
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << "===HalProxy===" << std::endl;
|
||||
stream << "Internal values:" << std::endl;
|
||||
stream << " Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl;
|
||||
int64_t now = getTimeNow();
|
||||
stream << " Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime)
|
||||
<< " ms ago" << std::endl;
|
||||
stream << " Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime)
|
||||
<< " ms ago" << std::endl;
|
||||
// TODO(b/142969448): Add logging for history of wakelock acquisition per subhal.
|
||||
stream << " Wakelock ref count: " << mWakelockRefCount << std::endl;
|
||||
stream << " # of events on pending write writes queue: " << mSizePendingWriteEventsQueue
|
||||
<< std::endl;
|
||||
stream << " Most events seen on pending write events queue: "
|
||||
<< mMostEventsObservedPendingWriteEventsQueue << std::endl;
|
||||
if (!mPendingWriteEventsQueue.empty()) {
|
||||
stream << " Size of events list on front of pending writes queue: "
|
||||
<< mPendingWriteEventsQueue.front().first.size() << std::endl;
|
||||
}
|
||||
stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl;
|
||||
stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl;
|
||||
stream << "SubHals (" << mSubHalList.size() << "):" << std::endl;
|
||||
for (auto& subHal : mSubHalList) {
|
||||
stream << " Name: " << subHal->getName() << std::endl;
|
||||
stream << " Debug dump: " << std::endl;
|
||||
android::base::WriteStringToFd(stream.str(), writeFd);
|
||||
subHal->debug(fd, args);
|
||||
stream.str("");
|
||||
stream << std::endl;
|
||||
}
|
||||
android::base::WriteStringToFd(stream.str(), writeFd);
|
||||
return Return<void>();
|
||||
}
|
||||
|
||||
Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
|
||||
int32_t subHalIndex) {
|
||||
std::vector<SensorInfo> sensors;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
|
||||
for (SensorInfo sensor : dynamicSensorsAdded) {
|
||||
if (!subHalIndexIsClear(sensor.sensorHandle)) {
|
||||
ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.",
|
||||
sensor.name.c_str());
|
||||
} else {
|
||||
sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
|
||||
mDynamicSensors[sensor.sensorHandle] = sensor;
|
||||
sensors.push_back(sensor);
|
||||
}
|
||||
}
|
||||
}
|
||||
mDynamicSensorsCallback->onDynamicSensorsConnected(sensors);
|
||||
return Return<void>();
|
||||
}
|
||||
|
||||
Return<void> HalProxy::onDynamicSensorsDisconnected(
|
||||
const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
|
||||
// TODO(b/143302327): Block this call until all pending events are flushed from queue
|
||||
std::vector<int32_t> sensorHandles;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
|
||||
for (int32_t sensorHandle : dynamicSensorHandlesRemoved) {
|
||||
if (!subHalIndexIsClear(sensorHandle)) {
|
||||
ALOGE("Dynamic sensorHandle removed had first byte not 0.");
|
||||
} else {
|
||||
sensorHandle = setSubHalIndex(sensorHandle, subHalIndex);
|
||||
if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) {
|
||||
mDynamicSensors.erase(sensorHandle);
|
||||
sensorHandles.push_back(sensorHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
|
||||
return Return<void>();
|
||||
}
|
||||
|
||||
void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
|
||||
std::ifstream subHalConfigStream(configFileName);
|
||||
if (!subHalConfigStream) {
|
||||
ALOGE("Failed to load subHal config file: %s", configFileName);
|
||||
} else {
|
||||
std::string subHalLibraryFile;
|
||||
while (subHalConfigStream >> subHalLibraryFile) {
|
||||
void* handle = getHandleForSubHalSharedObject(subHalLibraryFile);
|
||||
if (handle == nullptr) {
|
||||
ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
|
||||
} else {
|
||||
SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
|
||||
(SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
|
||||
if (sensorsHalGetSubHalPtr != nullptr) {
|
||||
std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
|
||||
*sensorsHalGetSubHalPtr;
|
||||
uint32_t version;
|
||||
ISensorsSubHalV2_0* subHal = sensorsHalGetSubHal(&version);
|
||||
if (version != SUB_HAL_2_0_VERSION) {
|
||||
ALOGE("SubHal version was not 2.0 for library: %s",
|
||||
subHalLibraryFile.c_str());
|
||||
} else {
|
||||
ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
|
||||
mSubHalList.push_back(std::make_unique<SubHalWrapperV2_0>(subHal));
|
||||
}
|
||||
} else {
|
||||
SensorsHalGetSubHalV2_1Func* getSubHalV2_1Ptr =
|
||||
(SensorsHalGetSubHalV2_1Func*)dlsym(handle, "sensorsHalGetSubHal_2_1");
|
||||
|
||||
if (getSubHalV2_1Ptr == nullptr) {
|
||||
ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
|
||||
subHalLibraryFile.c_str());
|
||||
} else {
|
||||
std::function<SensorsHalGetSubHalV2_1Func> sensorsHalGetSubHal_2_1 =
|
||||
*getSubHalV2_1Ptr;
|
||||
uint32_t version;
|
||||
ISensorsSubHalV2_1* subHal = sensorsHalGetSubHal_2_1(&version);
|
||||
if (version != SUB_HAL_2_1_VERSION) {
|
||||
ALOGE("SubHal version was not 2.1 for library: %s",
|
||||
subHalLibraryFile.c_str());
|
||||
} else {
|
||||
ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
|
||||
mSubHalList.push_back(std::make_unique<SubHalWrapperV2_1>(subHal));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HalProxy::initializeSensorList() {
|
||||
for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
|
||||
auto result = mSubHalList[subHalIndex]->getSensorsList([&](const auto& list) {
|
||||
for (SensorInfo sensor : list) {
|
||||
if (!subHalIndexIsClear(sensor.sensorHandle)) {
|
||||
ALOGE("SubHal sensorHandle's first byte was not 0");
|
||||
} else {
|
||||
ALOGV("Loaded sensor: %s", sensor.name.c_str());
|
||||
sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
|
||||
setDirectChannelFlags(&sensor, mSubHalList[subHalIndex]);
|
||||
bool keep = patchOplusPickupSensor(sensor) && patchOplusGlanceSensor(sensor);
|
||||
if (!keep) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mSensors[sensor.sensorHandle] = sensor;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!result.isOk()) {
|
||||
ALOGE("getSensorsList call failed for SubHal: %s",
|
||||
mSubHalList[subHalIndex]->getName().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* HalProxy::getHandleForSubHalSharedObject(const std::string& filename) {
|
||||
static const std::string kSubHalShareObjectLocations[] = {
|
||||
"", // Default locations will be searched
|
||||
#ifdef __LP64__
|
||||
"/vendor/lib64/hw/", "/odm/lib64/hw/"
|
||||
#else
|
||||
"/vendor/lib/hw/", "/odm/lib/hw/"
|
||||
#endif
|
||||
};
|
||||
|
||||
for (const std::string& dir : kSubHalShareObjectLocations) {
|
||||
void* handle = dlopen((dir + filename).c_str(), RTLD_NOW);
|
||||
if (handle != nullptr) {
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void HalProxy::init() {
|
||||
initializeSensorList();
|
||||
}
|
||||
|
||||
void HalProxy::stopThreads() {
|
||||
mThreadsRun.store(false);
|
||||
if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
|
||||
size_t numToRead = mEventQueue->availableToRead();
|
||||
std::vector<Event> events(numToRead);
|
||||
mEventQueue->read(events.data(), numToRead);
|
||||
mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
|
||||
}
|
||||
if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
|
||||
uint32_t kZero = 0;
|
||||
mWakeLockQueue->write(&kZero);
|
||||
mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
|
||||
}
|
||||
mWakelockCV.notify_one();
|
||||
mEventQueueWriteCV.notify_one();
|
||||
if (mPendingWritesThread.joinable()) {
|
||||
mPendingWritesThread.join();
|
||||
}
|
||||
if (mWakelockThread.joinable()) {
|
||||
mWakelockThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void HalProxy::disableAllSensors() {
|
||||
for (const auto& sensorEntry : mSensors) {
|
||||
int32_t sensorHandle = sensorEntry.first;
|
||||
activate(sensorHandle, false /* enabled */);
|
||||
}
|
||||
std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
|
||||
for (const auto& sensorEntry : mDynamicSensors) {
|
||||
int32_t sensorHandle = sensorEntry.first;
|
||||
activate(sensorHandle, false /* enabled */);
|
||||
}
|
||||
}
|
||||
|
||||
void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
|
||||
halProxy->handlePendingWrites();
|
||||
}
|
||||
|
||||
void HalProxy::handlePendingWrites() {
|
||||
// TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of
|
||||
// one.
|
||||
std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
|
||||
while (mThreadsRun.load()) {
|
||||
mEventQueueWriteCV.wait(
|
||||
lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
|
||||
if (mThreadsRun.load()) {
|
||||
std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
|
||||
size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
|
||||
size_t eventQueueSize = mEventQueue->getQuantumCount();
|
||||
size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
|
||||
lock.unlock();
|
||||
if (!mEventQueue->writeBlocking(
|
||||
pendingWriteEvents.data(), numToWrite,
|
||||
static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
|
||||
static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
|
||||
kPendingWriteTimeoutNs, mEventQueueFlag)) {
|
||||
ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
|
||||
if (numWakeupEvents > 0) {
|
||||
if (pendingWriteEvents.size() > eventQueueSize) {
|
||||
decrementRefCountAndMaybeReleaseWakelock(
|
||||
countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
|
||||
} else {
|
||||
decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
|
||||
}
|
||||
}
|
||||
}
|
||||
lock.lock();
|
||||
mSizePendingWriteEventsQueue -= numToWrite;
|
||||
if (pendingWriteEvents.size() > eventQueueSize) {
|
||||
// TODO(b/143302327): Check if this erase operation is too inefficient. It will copy
|
||||
// all the events ahead of it down to fill gap off array at front after the erase.
|
||||
pendingWriteEvents.erase(pendingWriteEvents.begin(),
|
||||
pendingWriteEvents.begin() + eventQueueSize);
|
||||
} else {
|
||||
mPendingWriteEventsQueue.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HalProxy::startWakelockThread(HalProxy* halProxy) {
|
||||
halProxy->handleWakelocks();
|
||||
}
|
||||
|
||||
void HalProxy::handleWakelocks() {
|
||||
std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
|
||||
while (mThreadsRun.load()) {
|
||||
mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
|
||||
if (mThreadsRun.load()) {
|
||||
int64_t timeLeft;
|
||||
if (sharedWakelockDidTimeout(&timeLeft)) {
|
||||
resetSharedWakelock();
|
||||
} else {
|
||||
uint32_t numWakeLocksProcessed;
|
||||
lock.unlock();
|
||||
bool success = mWakeLockQueue->readBlocking(
|
||||
&numWakeLocksProcessed, 1, 0,
|
||||
static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
|
||||
lock.lock();
|
||||
if (success) {
|
||||
decrementRefCountAndMaybeReleaseWakelock(
|
||||
static_cast<size_t>(numWakeLocksProcessed));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
resetSharedWakelock();
|
||||
}
|
||||
|
||||
bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
|
||||
bool didTimeout;
|
||||
int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
|
||||
if (duration > kWakelockTimeoutNs) {
|
||||
didTimeout = true;
|
||||
} else {
|
||||
didTimeout = false;
|
||||
*timeLeft = kWakelockTimeoutNs - duration;
|
||||
}
|
||||
return didTimeout;
|
||||
}
|
||||
|
||||
void HalProxy::resetSharedWakelock() {
|
||||
std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
|
||||
decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
|
||||
mWakelockTimeoutResetTime = getTimeNow();
|
||||
}
|
||||
|
||||
void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
|
||||
V2_0::implementation::ScopedWakelock wakelock) {
|
||||
size_t numToWrite = 0;
|
||||
std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
|
||||
if (wakelock.isLocked()) {
|
||||
incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
|
||||
}
|
||||
if (mPendingWriteEventsQueue.empty()) {
|
||||
numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
|
||||
if (numToWrite > 0) {
|
||||
if (mEventQueue->write(events.data(), numToWrite)) {
|
||||
// TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit
|
||||
// in more writes immediately
|
||||
mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
|
||||
} else {
|
||||
numToWrite = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
size_t numLeft = events.size() - numToWrite;
|
||||
if (numToWrite < events.size() &&
|
||||
mSizePendingWriteEventsQueue + numLeft <= kMaxSizePendingWriteEventsQueue) {
|
||||
std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
|
||||
mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
|
||||
mSizePendingWriteEventsQueue += numLeft;
|
||||
mMostEventsObservedPendingWriteEventsQueue =
|
||||
std::max(mMostEventsObservedPendingWriteEventsQueue, mSizePendingWriteEventsQueue);
|
||||
mEventQueueWriteCV.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
|
||||
int64_t* timeoutStart /* = nullptr */) {
|
||||
if (!mThreadsRun.load()) return false;
|
||||
std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
|
||||
if (mWakelockRefCount == 0) {
|
||||
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
|
||||
mWakelockCV.notify_one();
|
||||
}
|
||||
mWakelockTimeoutStartTime = getTimeNow();
|
||||
mWakelockRefCount += delta;
|
||||
if (timeoutStart != nullptr) {
|
||||
*timeoutStart = mWakelockTimeoutStartTime;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
|
||||
int64_t timeoutStart /* = -1 */) {
|
||||
if (!mThreadsRun.load()) return;
|
||||
std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
|
||||
if (delta > mWakelockRefCount) {
|
||||
ALOGE("Decrementing wakelock ref count by %zu when count is %zu",
|
||||
delta, mWakelockRefCount);
|
||||
}
|
||||
if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
|
||||
if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
|
||||
mWakelockRefCount -= std::min(mWakelockRefCount, delta);
|
||||
if (mWakelockRefCount == 0) {
|
||||
release_wake_lock(kWakelockName);
|
||||
}
|
||||
}
|
||||
|
||||
void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo,
|
||||
std::shared_ptr<ISubHalWrapperBase> subHal) {
|
||||
bool sensorSupportsDirectChannel =
|
||||
(sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
|
||||
V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
|
||||
if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
|
||||
mDirectChannelSubHal = subHal;
|
||||
} else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
|
||||
// disable direct channel capability for sensors in subHals that are not
|
||||
// the only one we will enable
|
||||
sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
|
||||
V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ISubHalWrapperBase> HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) {
|
||||
return mSubHalList[extractSubHalIndex(sensorHandle)];
|
||||
}
|
||||
|
||||
bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) {
|
||||
return extractSubHalIndex(sensorHandle) < mSubHalList.size();
|
||||
}
|
||||
|
||||
size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
|
||||
size_t numWakeupEvents = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
int32_t sensorHandle = events[i].sensorHandle;
|
||||
if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
|
||||
numWakeupEvents++;
|
||||
}
|
||||
}
|
||||
return numWakeupEvents;
|
||||
}
|
||||
|
||||
int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) {
|
||||
return sensorHandle & (~kSensorHandleSubHalIndexMask);
|
||||
}
|
||||
|
||||
bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) {
|
||||
return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V2_1
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
109
aidl/sensors/HalProxyCallback.cpp
Normal file
109
aidl/sensors/HalProxyCallback.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "HalProxyCallback.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <fstream>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace sensors {
|
||||
namespace V2_0 {
|
||||
namespace implementation {
|
||||
|
||||
static constexpr int32_t kBitsAfterSubHalIndex = 24;
|
||||
|
||||
/**
|
||||
* Set the subhal index as first byte of sensor handle and return this modified version.
|
||||
*
|
||||
* @param sensorHandle The sensor handle to modify.
|
||||
* @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
|
||||
*
|
||||
* @return The modified sensor handle.
|
||||
*/
|
||||
int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
|
||||
return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
|
||||
}
|
||||
|
||||
void HalProxyCallbackBase::postEvents(const std::vector<V2_1::Event>& events,
|
||||
ScopedWakelock wakelock) {
|
||||
if (events.empty() || !mCallback->areThreadsRunning()) return;
|
||||
size_t numWakeupEvents;
|
||||
std::vector<V2_1::Event> processedEvents = processEvents(events, &numWakeupEvents);
|
||||
if (numWakeupEvents > 0) {
|
||||
ALOG_ASSERT(wakelock.isLocked(),
|
||||
"Wakeup events posted while wakelock unlocked for subhal"
|
||||
" w/ index %" PRId32 ".",
|
||||
mSubHalIndex);
|
||||
} else {
|
||||
ALOG_ASSERT(!wakelock.isLocked(),
|
||||
"No Wakeup events posted but wakelock locked for subhal"
|
||||
" w/ index %" PRId32 ".",
|
||||
mSubHalIndex);
|
||||
}
|
||||
mCallback->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
|
||||
}
|
||||
|
||||
ScopedWakelock HalProxyCallbackBase::createScopedWakelock(bool lock) {
|
||||
ScopedWakelock wakelock(mRefCounter, lock);
|
||||
return wakelock;
|
||||
}
|
||||
|
||||
std::vector<V2_1::Event> HalProxyCallbackBase::processEvents(const std::vector<V2_1::Event>& events,
|
||||
size_t* numWakeupEvents) const {
|
||||
*numWakeupEvents = 0;
|
||||
std::vector<V2_1::Event> eventsOut;
|
||||
const char* aodLightModeNode = "/sys/kernel/oplus_display/aod_light_mode_set";
|
||||
for (V2_1::Event event : events) {
|
||||
event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
|
||||
if (event.sensorType == V2_1::SensorType::DYNAMIC_SENSOR_META) {
|
||||
event.u.dynamic.sensorHandle =
|
||||
setSubHalIndex(event.u.dynamic.sensorHandle, mSubHalIndex);
|
||||
}
|
||||
const V2_1::SensorInfo& sensor = mCallback->getSensorInfo(event.sensorHandle);
|
||||
|
||||
if (sensor.type == V2_1::SensorType::GLANCE_GESTURE
|
||||
&& event.u.scalar != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sensor.type == V2_1::SensorType::PICK_UP_GESTURE
|
||||
&& event.u.scalar != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sensor.typeAsString == "qti.sensor.lux_aod") {
|
||||
std::ofstream nodeFile(aodLightModeNode);
|
||||
if (nodeFile.is_open()) {
|
||||
nodeFile << !event.u.scalar;
|
||||
nodeFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
|
||||
(*numWakeupEvents)++;
|
||||
}
|
||||
eventsOut.push_back(event);
|
||||
}
|
||||
return eventsOut;
|
||||
}
|
||||
|
||||
} // namespace implementation
|
||||
} // namespace V2_0
|
||||
} // namespace sensors
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
@@ -0,0 +1,10 @@
|
||||
on boot
|
||||
chmod 666 /sys/kernel/oplus_display/aod_light_mode_set
|
||||
|
||||
service vendor.sensors-hal-multihal /vendor/bin/hw/android.hardware.sensors-service.oplus-multihal
|
||||
class hal
|
||||
user system
|
||||
group system wakelock context_hub input uhid
|
||||
task_profiles ServiceCapacityLow
|
||||
capabilities BLOCK_SUSPEND
|
||||
rlimit rtprio 10 10
|
||||
23
aidl/sensors/android.hardware.sensors.oplus-multihal.xml
Normal file
23
aidl/sensors/android.hardware.sensors.oplus-multihal.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<!--
|
||||
~ Copyright (C) 2021 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest version="1.0" type="device">
|
||||
<hal format="aidl">
|
||||
<name>android.hardware.sensors</name>
|
||||
<version>2</version>
|
||||
<fqname>ISensors/default</fqname>
|
||||
</hal>
|
||||
</manifest>
|
||||
36
aidl/sensors/service.cpp
Normal file
36
aidl/sensors/service.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android/binder_manager.h>
|
||||
#include <android/binder_process.h>
|
||||
#include "HalProxyAidl.h"
|
||||
|
||||
using ::aidl::android::hardware::sensors::implementation::HalProxyAidl;
|
||||
|
||||
int main() {
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(0);
|
||||
|
||||
// Make a default multihal sensors service
|
||||
auto halProxy = ndk::SharedRefBase::make<HalProxyAidl>();
|
||||
const std::string halProxyName = std::string() + HalProxyAidl::descriptor + "/default";
|
||||
binder_status_t status =
|
||||
AServiceManager_addService(halProxy->asBinder().get(), halProxyName.c_str());
|
||||
CHECK_EQ(status, STATUS_OK);
|
||||
|
||||
ABinderProcess_joinThreadPool();
|
||||
return EXIT_FAILURE; // should not reach
|
||||
}
|
||||
@@ -396,6 +396,7 @@ int LedVibratorDevice::on(int32_t timeoutMs) {
|
||||
ret |= write_value(LED_DEVICE "/duration", timeoutMs);
|
||||
ret |= write_value(LED_DEVICE "/state", "1");
|
||||
ret |= write_value(LED_DEVICE "/activate", "1");
|
||||
usleep(100 * 1000);
|
||||
ret |= write_value(LED_DEVICE "/activate", "0");
|
||||
|
||||
return ret;
|
||||
@@ -403,11 +404,9 @@ int LedVibratorDevice::on(int32_t timeoutMs) {
|
||||
|
||||
int LedVibratorDevice::onWaveform(int waveformIndex) {
|
||||
int ret = 0;
|
||||
ret |= write_value(LED_DEVICE "/rtp", "0");
|
||||
ret |= write_value(LED_DEVICE "/vmax", "1600");
|
||||
ret |= write_value(LED_DEVICE "/waveform_index", waveformIndex);
|
||||
ret |= write_value(LED_DEVICE "/brightness", "1");
|
||||
ret |= write_value(LED_DEVICE "/rtp", "0");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -491,50 +490,37 @@ ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength es, const std
|
||||
if (ledVib.mDetected) {
|
||||
switch (effect) {
|
||||
case Effect::CLICK:
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
ledVib.write_value(LED_DEVICE "/vmax", "2500");
|
||||
ledVib.write_value(LED_DEVICE "/waveform_index", "1");
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
break;
|
||||
case Effect::DOUBLE_CLICK:
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
ledVib.write_value(LED_DEVICE "/vmax", "2500");
|
||||
ledVib.write_value(LED_DEVICE "/waveform_index", "1");
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
usleep(100 * 1000);
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
ledVib.write_value(LED_DEVICE "/vmax", "2500");
|
||||
ledVib.write_value(LED_DEVICE "/waveform_index", "1");
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
break;
|
||||
case Effect::TICK:
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
ledVib.write_value(LED_DEVICE "/vmax", "1400");
|
||||
ledVib.write_value(LED_DEVICE "/waveform_index", "1");
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
break;
|
||||
case Effect::HEAVY_CLICK:
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
ledVib.write_value(LED_DEVICE "/vmax", "2500");
|
||||
ledVib.write_value(LED_DEVICE "/waveform_index", "4");
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
break;
|
||||
case Effect::TEXTURE_TICK:
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
ledVib.write_value(LED_DEVICE "/vmax", "60");
|
||||
ledVib.write_value(LED_DEVICE "/waveform_index", "2");
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
ledVib.write_value(LED_DEVICE "/rtp", "0");
|
||||
break;
|
||||
default:
|
||||
return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
|
||||
}
|
||||
|
||||
if (effect == Effect::DOUBLE_CLICK) {
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
usleep(100 * 1000);
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
} else {
|
||||
ledVib.write_value(LED_DEVICE "/brightness", "1");
|
||||
}
|
||||
|
||||
// Return magic value for play length so that we won't end up calling on() / off()
|
||||
playLengthMs = 150;
|
||||
} else {
|
||||
|
||||
@@ -27,28 +27,107 @@
|
||||
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* Wly THUD as DOUBLE_CLICK */
|
||||
static const int8_t effect_1[] = {
|
||||
1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4,
|
||||
4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 20,
|
||||
22, 26, 29, 33, 38, 43, 49, 56, 64, 71, 76, 81,
|
||||
85, 88, 90, 92, 93, 93, 93, 92, 91, 90, 88, 86,
|
||||
84, 81, 78, 75, 72, 68, 65, 61, 57, 53, 49, 44,
|
||||
40, 36, 31, 27, 22, 17, 12, 7, 2, -3, -9, -15,
|
||||
-21, -28, -35, -43, -51, -60, -71, -82, -94, -103, -112, -118,
|
||||
-123, -126, -127, -127, -127, -127, -124, -121, -117, -112, -107, -101,
|
||||
-94, -87, -80, -72, -64, -55, -47, -38, -30, -21, -12, -4,
|
||||
5, 13, 21, 29, 37, 44, 51, 57, 63, 68, 73, 77,
|
||||
81, 84, 86, 88, 89, 89, 88, 86, 84, 81, 78, 75,
|
||||
72, 68, 64, 59, 54, 49, 44, 38, 32, 25, 19, 12,
|
||||
5, -2, -9, -17, -24, -32, -40, -47, -55, -62, -69, -76,
|
||||
-83, -89, -95, -101, -106, -111, -115, -119, -122, -124, -125, -125,
|
||||
-125, -123, -120, -116, -111, -104, -95, -85, -74, -65, -56, -49,
|
||||
-42, -35, -30, -24, -19, -15, -10, -6, -3, 1, 5, 8,
|
||||
11, 15, 18, 21, 24, 26, 29, 32, 34, 37, 39, 41,
|
||||
43, 45, 47, 49, 50, 51, 52, 53, 54, 54, 54, 54,
|
||||
53, 52, 50, 48, 45, 42, 38, 33, 29, 25, 22, 19,
|
||||
17, 14, 12, 11, 9, 8, 7, 6, 5, 4, 4, 3,
|
||||
3, 2, 2, 2, 1, 1, 1, 1, 1, 0
|
||||
0, 5, 10, 15, 20, 25, 29, 34, 38, 43, 47, 51, 55, 58, 62,
|
||||
65, 68, 70, 73, 75, 77, 78, 79, 80, 81, 81, 81, 81, 80, 79,
|
||||
78, 77, 75, 73, 70, 68, 65, 62, 59, 55, 51, 47, 43, 39, 34,
|
||||
30, 25, 20, 15, 10, 5, 0, -5, -10, -15, -19, -24, -29, -34, -38,
|
||||
-42, -47, -51, -54, -58, -61, -65, -68, -70, -73, -75, -77, -78, -79, -80,
|
||||
-81, -81, -81, -81, -80, -79, -78, -77, -75, -73, -71, -68, -65, -62, -59,
|
||||
-55, -51, -47, -43, -39, -35, -30, -25, -20, -16, -11, -6, -1, 4, 9,
|
||||
14, 19, 24, 29, 33, 38, 42, 46, 50, 54, 58, 61, 64, 67, 70,
|
||||
72, 75, 76, 78, 79, 80, 81, 81, 81, 81, 80, 80, 78, 77, 75,
|
||||
73, 71, 68, 65, 62, 59, 55, 52, 48, 44, 39, 35, 30, 26, 21,
|
||||
16, 11, 6, 1, -4, -9, -14, -19, -24, -28, -33, -38, -42, -46, -50,
|
||||
-54, -58, -61, -64, -67, -70, -72, -74, -76, -78, -79, -80, -81, -81, -81,
|
||||
-81, -80, -80, -78, -77, -75, -73, -71, -68, -66, -62, -59, -56, -52, -48,
|
||||
-44, -40, -35, -31, -26, -21, -16, -11, -6, -1, 4, 9, 14, 19, 23,
|
||||
28, 33, 37, 42, 46, 50, 54, 57, 61, 64, 67, 70, 72, 74, 76,
|
||||
78, 79, 80, 81, 81, 81, 81, 81, 80, 79, 77, 75, 73, 71, 69,
|
||||
66, 63, 59, 56, 52, 48, 44, 40, 35, 31, 26, 21, 16, 12, 7,
|
||||
2, -3, -8, -13, -18, -23, -28, -32, -37, -41, -46, -50, -54, -57, -61,
|
||||
-64, -67, -70, -72, -74, -76, -78, -79, -80, -81, -81, -81, -81, -81, -80,
|
||||
-79, -77, -76, -74, -71, -69, -66, -63, -60, -56, -52, -48, -44, -40, -36,
|
||||
-31, -26, -22, -17, -12, -7, 0, 2, 3, 5, 7, 8, 10, 12, 13,
|
||||
15, 16, 17, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 27, 28,
|
||||
28, 28, 28, 28, 28, 27, 27, 26, 26, 25, 24, 23, 22, 21, 20,
|
||||
19, 18, 16, 15, 13, 12, 10, 9, 7, 5, 4, 2, 0, -2, -3,
|
||||
-5, -7, -8, -10, -12, -13, -15, -16, -17, -19, -20, -21, -22, -23, -24,
|
||||
-25, -26, -26, -27, -27, -28, -28, -28, -28, -28, -28, -27, -27, -26, -26,
|
||||
-25, -24, -23, -22, -21, -20, -19, -18, -16, -15, -13, -12, -10, -9, -7,
|
||||
-5, -4, -2, 0, 1, 3, 5, 7, 8, 10, 11, 13, 15, 16, 17,
|
||||
19, 20, 21, 22, 23, 24, 25, 26, 26, 27, 27, 28, 28, 28, 28,
|
||||
28, 28, 27, 27, 26, 26, 25, 24, 23, 22, 21, 20, 19, 18, 16,
|
||||
15, 13, 12, 10, 9, 7, 5, 4, 2, 0, -1, -3, -5, -6, -8,
|
||||
-10, -11, -13, -14, -16, -17, -19, -20, -21, -22, -23, -24, -25, -26, -26,
|
||||
-27, -27, -28, -28, -28, -28, -28, -28, -27, -27, -26, -26, -25, -24, -24,
|
||||
-23, -21, -20, -19, -18, -16, -15, -14, -12, -10, -9, -7, -6, -4, -2,
|
||||
0, 1, 3, 5, 6, 8, 10, 11, 13, 14, 16, 17, 18, 20, 21,
|
||||
22, 23, 24, 25, 26, 26, 27, 27, 28, 28, 28, 28, 28, 28, 27,
|
||||
27, 27, 26, 25, 24, 24, 23, 22, 20, 19, 18, 17, 15, 14, 12,
|
||||
11, 9, 7, 6, 4, 2, 1, -1, -3, -5, -6, -8, -10, -11, -13,
|
||||
-14, -16, -17, -18, -20, -21, -22, -23, -24, -25, -25, -26, -27, -27, -28,
|
||||
-28, -28, -28, -28, -28, -27, -27, -27, -26, -25, -24, -24, -23, -22, -20,
|
||||
-19, -18, -17, -15, -14, -12, -11, -9, -7, -6, -4, -2, -1, 1, 3,
|
||||
4, 6, 8, 9, 11, 13, 14, 16, 17, 18, 20, 21, 22, 23, 24,
|
||||
25, 25, 26, 27, 27, 27, 28, 28, 28, 28, 28, 27, 27, 27, 26,
|
||||
25, 25, 24, 23, 22, 21, 19, 18, 17, 15, 14, 12, 11, 9, 8,
|
||||
6, 4, 2, 1, -1, -3, -4, -6, -8, -9, -11, -13, -14, -15, -17,
|
||||
-18, -19, -21, -22, -23, -24, -25, -25, -26, -27, -27, -27, -28, -28, -28,
|
||||
-28, -28, -27, -27, -27, -26, -25, -25, -24, -23, -22, -21, -19, -18, -17,
|
||||
-15, -14, -12, -11, -9, -8, -6, -4, -3, -1, 1, 3, 4, 6, 8,
|
||||
9, 11, 12, 14, 15, 17, 18, 19, 21, 22, 23, 24, 25, 25, 26,
|
||||
27, 27, 27, 28, 28, 28, 28, 28, 27, 27, 27, 26, 25, 25, 24,
|
||||
23, 22, 21, 20, 18, 17, 16, 14, 13, 11, 9, 8, 6, 4, 3,
|
||||
1, -1, -2, -4, -6, -8, -9, -11, -12, -14, -15, -17, -18, -19, -21,
|
||||
-22, -23, -24, -25, -25, -26, -27, -27, -27, -28, -28, -28, -28, -28, -27,
|
||||
-27, -27, -26, -25, -25, -24, -23, -22, -21, -20, -18, -17, -16, -14, -13,
|
||||
-11, -9, -8, -6, -5, -3, -1, 1, 2, 4, 6, 7, 9, 11, 12,
|
||||
14, 15, 17, 18, 19, 20, 22, 23, 24, 24, 25, 26, 27, 27, 27,
|
||||
28, 28, 28, 28, 28, 28, 27, 27, 26, 26, 25, 24, 23, 22, 21,
|
||||
20, 18, 17, 16, 14, 13, 11, 10, 8, 6, 5, 3, 1, -1, -2,
|
||||
-4, -6, -7, -9, -11, -12, -14, -15, -17, -18, -19, -20, -22, -23, -24,
|
||||
-24, -25, -26, -27, -27, -27, -28, -28, -28, -28, -28, -28, -27, -27, -26,
|
||||
-26, -25, -24, -23, -22, -21, -20, -19, -17, -16, -14, -13, -11, -10, -8,
|
||||
-6, -5, -3, -1, 0, 2, 4, 6, 7, 9, 10, 12, 14, 15, 16,
|
||||
18, 19, 20, 21, 23, 23, 24, 25, 26, 26, 27, 27, 28, 28, 28,
|
||||
28, 28, 28, 27, 27, 26, 26, 25, 24, 23, 22, 21, 20, 19, 17,
|
||||
16, 14, 13, 11, 10, 8, 7, 5, 3, 1, 0, -2, -4, -5, -7,
|
||||
-9, -10, -12, -13, -15, -16, -18, -19, -20, -21, -22, -23, -24, -25, -26,
|
||||
-26, -27, -27, -28, -28, -28, -28, -28, -28, -27, -27, -26, -26, -25, -24,
|
||||
-23, -22, -21, -20, -19, -17, -16, -15, -13, -11, -10, -8, -7, -5, -3,
|
||||
-2, 0, 2, 4, 5, 7, 9, 10, 12, 13, 15, 16, 18, 19, 20,
|
||||
21, 22, 23, 24, 25, 26, 26, 27, 27, 28, 28, 28, 28, 28, 28,
|
||||
27, 27, 26, 26, 25, 24, 23, 22, 21, 20, 19, 17, 16, 15, 13,
|
||||
12, 10, 8, 7, 5, 3, 2, 0, -2, -3, -5, -7, -9, -10, -12,
|
||||
-13, -15, -16, -18, -19, -20, -21, -22, -23, -24, -25, -26, -26, -27, -27,
|
||||
-28, -28, -28, -28, -28, -28, -27, -27, -26, -26, -25, -24, -23, -22, -21,
|
||||
-20, -19, -18, -16, -15, -13, -12, -10, -8, -7, -5, -3, -2, 0, 2,
|
||||
3, 5, 7, 8, 10, 12, 13, 15, 16, 17, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 26, 27, 27, 28, 28, 28, 28, 28, 28, 27, 27, 26,
|
||||
26, 25, 24, 23, 22, 21, 20, 19, 18, 16, 15, 13, 12, 10, 9,
|
||||
7, 5, 4, 2, 0, -2, -3, -5, -7, -8, -10, -12, -13, -15, -16,
|
||||
-17, -19, -20, -21, -22, -23, -24, -25, -26, -26, -27, -27, -28, -28, -28,
|
||||
-28, -28, -28, -27, -27, -26, -26, -25, -24, -23, -22, -21, -20, -19, -18,
|
||||
-16, -15, -13, -12, -10, -9, -7, -5, -4, -2, 0, -6, -12, -18, -24,
|
||||
-30, -35, -41, -46, -51, -56, -61, -66, -70, -74, -78, -81, -85, -87, -90,
|
||||
-92, -94, -95, -97, -97, -98, -98, -97, -97, -96, -94, -92, -90, -88, -85,
|
||||
-82, -78, -74, -70, -66, -62, -57, -52, -47, -41, -36, -30, -24, -18, -12,
|
||||
-6, 0, 6, 12, 18, 23, 29, 35, 40, 46, 51, 56, 61, 66, 70,
|
||||
74, 78, 81, 84, 87, 90, 92, 94, 95, 97, 97, 98, 98, 97, 97,
|
||||
96, 94, 92, 90, 88, 85, 82, 78, 75, 71, 66, 62, 57, 52, 47,
|
||||
42, 36, 30, 25, 19, 13, 7, 1, -5, -11, -17, -23, -29, -35, -40,
|
||||
-46, -51, -56, -61, -65, -70, -74, -77, -81, -84, -87, -90, -92, -94, -95,
|
||||
-96, -97, -98, -98, -97, -97, -96, -94, -93, -90, -88, -85, -82, -79, -75,
|
||||
-71, -67, -62, -57, -52, -47, -42, -36, -31, -25, -19, -13, -7, -1, 5,
|
||||
11, 17, 23, 29, 34, 40, 45, 50, 55, 60, 65, 69, 73, 77, 81,
|
||||
84, 87, 90, 92, 94, 95, 96, 97, 98, 98, 97, 97, 96, 94, 93,
|
||||
91, 88, 85, 82, 79, 75, 71, 67, 62, 58, 53, 48, 42, 37, 31,
|
||||
25, 19, 14, 8, 2, -4, -10, -16, -22, -28, -34, -39, -45, -50, -55,
|
||||
-60, -65, -69, -73, -77, -81, -84, -87, -89, -92, -94, -95, -96, -97, -98,
|
||||
-98, -98, -97, -96, -95, -93, -91, -88, -86, -82, -79, -75, -71, -67, -63,
|
||||
-58, -53, -48, -43, -37, -31, -26, -20, -14, -8, 0
|
||||
};
|
||||
|
||||
static const int8_t effect_2[] = {
|
||||
|
||||
28
dolby/Android.bp
Normal file
28
dolby/Android.bp
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright (C) 2017-2021 The LineageOS Project
|
||||
// (C) 2023-24 Paranoid Android
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
android_app {
|
||||
name: "OplusDolby",
|
||||
|
||||
srcs: ["src/**/*.kt"],
|
||||
resource_dirs: ["res"],
|
||||
certificate: "platform",
|
||||
platform_apis: true,
|
||||
system_ext_specific: true,
|
||||
privileged: true,
|
||||
|
||||
overrides: ["MusicFX"],
|
||||
static_libs: [
|
||||
"SettingsLib",
|
||||
"SpaLib",
|
||||
"androidx.activity_activity-compose",
|
||||
"androidx.compose.material3_material3",
|
||||
"androidx.compose.runtime_runtime",
|
||||
"androidx.preference_preference",
|
||||
"org.lineageos.settings.resources",
|
||||
],
|
||||
}
|
||||
79
dolby/AndroidManifest.xml
Normal file
79
dolby/AndroidManifest.xml
Normal file
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023-24 Paranoid Android
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="co.aospa.dolby.oplus"
|
||||
android:sharedUserId="android.uid.system">
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<application
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:allowBackup="false"
|
||||
android:label="@string/dolby_title"
|
||||
android:persistent="true">
|
||||
|
||||
<receiver
|
||||
android:name=".BootCompletedReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter android:priority="1000">
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".DolbyActivity"
|
||||
android:label="@string/dolby_title"
|
||||
android:theme="@style/Theme.SubSettingsBase"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.android.settings.action.IA_SETTINGS" />
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.CATEGORY_CONTENT_MUSIC" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="com.android.settings.category"
|
||||
android:value="com.android.settings.category.ia.sound" />
|
||||
<meta-data android:name="com.android.settings.summary_uri"
|
||||
android:value="content://co.aospa.dolby.oplus.summary/dolby" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".geq.EqualizerActivity"
|
||||
android:label="@string/dolby_preset"
|
||||
android:theme="@style/Theme.SubSettingsBase"
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".DolbyTileService"
|
||||
android:icon="@drawable/ic_dolby_qs"
|
||||
android:label="@string/dolby_title"
|
||||
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.service.quicksettings.action.QS_TILE"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<provider
|
||||
android:name=".SummaryProvider"
|
||||
android:authorities="co.aospa.dolby.oplus.summary">
|
||||
</provider>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
5
dolby/dolby.mk
Normal file
5
dolby/dolby.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
# DolbyManager
|
||||
PRODUCT_PACKAGES += \
|
||||
OplusDolby
|
||||
|
||||
BOARD_VENDOR_SEPOLICY_DIRS += hardware/oplus/sepolicy/qti/dolby
|
||||
8
dolby/res/drawable/ic_dolby.xml
Normal file
8
dolby/res/drawable/ic_dolby.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24" android:tint="?android:attr/colorControlNormal">
|
||||
<path android:fillColor="#000000" android:pathData="M1,4.0214C2.2767,4.0743 3.5798,3.9866 4.8252,4.2063C8.8352,4.9133 11.4129,8.3489 11.0507,12.3402C10.7124,16.0695 7.3661,18.9511 3.3484,18.9651C2.5657,18.9678 1.7827,18.9441 1,18.9324L1,4.0214Z" android:strokeColor="#00000000" android:strokeWidth="1" android:fillType="evenOdd"/>
|
||||
<group>
|
||||
<clip-path android:pathData="M12.9332,4l10.0668,0l0,15l-10.0668,0z"/>
|
||||
<path android:fillColor="#000000" android:pathData="M23,4.0924L23,18.8825C19.4973,19.298 16.399,18.6968 14.3366,15.6947C12.5148,13.043 12.4594,10.2265 14.2129,7.5241C16.244,4.394 19.3953,3.7204 23,4.0924" android:strokeColor="#00000000" android:strokeWidth="1" android:fillType="evenOdd"/>
|
||||
</group>
|
||||
</vector>
|
||||
8
dolby/res/drawable/ic_dolby_qs.xml
Normal file
8
dolby/res/drawable/ic_dolby_qs.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:width="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:fillColor="#191c1e" android:pathData="M1,4.0214C2.2767,4.0743 3.5798,3.9866 4.8252,4.2063C8.8352,4.9133 11.4129,8.3489 11.0507,12.3402C10.7124,16.0695 7.3661,18.9511 3.3484,18.9651C2.5657,18.9678 1.7827,18.9441 1,18.9324L1,4.0214Z" android:strokeColor="#00000000" android:strokeWidth="1" android:fillType="evenOdd"/>
|
||||
<group>
|
||||
<clip-path android:pathData="M12.9332,4l10.0668,0l0,15l-10.0668,0z"/>
|
||||
<path android:fillColor="#191c1e" android:pathData="M23,4.0924L23,18.8825C19.4973,19.298 16.399,18.6968 14.3366,15.6947C12.5148,13.043 12.4594,10.2265 14.2129,7.5241C16.244,4.394 19.3953,3.7204 23,4.0924" android:strokeColor="#00000000" android:strokeWidth="1" android:fillType="evenOdd"/>
|
||||
</group>
|
||||
</vector>
|
||||
24
dolby/res/drawable/ic_ieq_balanced.xml
Normal file
24
dolby/res/drawable/ic_ieq_balanced.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="192dp"
|
||||
android:height="192dp"
|
||||
android:viewportWidth="192"
|
||||
android:viewportHeight="192"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 69.584 66.547 L 63.792 70.797 L 38.646 71.697 L 13.5 72.597 L 13.5 89.723 C 13.5 99.143 13.865 111.999 14.313 118.292 L 15.124 129.734 L 178.5 129.734 L 178.5 102.234 L 121.248 102.234 L 99.203 82.234 C 87.078 71.234 76.756 62.248 76.266 62.266 C 75.776 62.282 72.769 64.209 69.584 66.547"
|
||||
android:strokeWidth="1.25"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 69.125 67.065 L 62.875 71.921 L 38.188 71.99 L 13.5 72.06 L 13.504 81.122 C 13.506 86.106 13.876 99.044 14.325 109.872 L 15.141 129.56 L 178.5 129.56 L 178.5 103.31 L 122.126 103.31 L 99.675 82.997 C 87.326 71.826 76.808 62.577 76.299 62.446 C 75.791 62.315 72.563 64.394 69.125 67.065"
|
||||
android:strokeWidth="1.25"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 69.854 67.249 L 63.237 72.187 L 13.311 72.187 L 14.119 84.374 C 14.562 91.077 14.929 104.016 14.932 113.124 L 14.939 129.687 L 178.689 129.687 L 178.689 103.437 L 150.251 103.428 L 121.814 103.418 L 99.143 82.865 L 76.471 62.313 L 69.854 67.249"
|
||||
android:strokeWidth="1.25"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 69.141 67.266 L 63.221 71.609 L 45.888 71.609 C 36.354 71.609 25.238 71.956 21.184 72.378 L 13.813 73.147 L 14.115 93.316 C 14.281 104.408 14.748 117.001 15.151 121.297 L 15.886 129.109 L 178.188 129.109 L 178.188 102.859 L 120.703 102.859 L 98.696 82.859 C 86.594 71.859 76.324 62.873 75.876 62.891 C 75.429 62.907 72.399 64.876 69.141 67.266"
|
||||
android:strokeWidth="1.25"/>
|
||||
</vector>
|
||||
24
dolby/res/drawable/ic_ieq_detailed.xml
Normal file
24
dolby/res/drawable/ic_ieq_detailed.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="192dp"
|
||||
android:height="192dp"
|
||||
android:viewportWidth="192"
|
||||
android:viewportHeight="192"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 126.625 63.749 C 120.886 65.812 115.12 69.774 103.5 79.643 C 85.566 94.873 77.207 98.716 62.179 98.637 C 51.344 98.582 42.841 96.091 34.946 90.659 C 29.282 86.763 22.25 77.097 22.25 73.209 C 22.25 71.466 21.259 70.954 17.875 70.954 L 13.5 70.954 L 13.5 129.704 L 178.5 129.704 L 178.5 86.329 L 174.915 81.381 C 169.567 73.999 161.404 67.534 153.865 64.714 C 146.447 61.939 132.988 61.463 126.625 63.749"
|
||||
android:strokeWidth="1.25"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 128.493 63.479 C 122.229 65.384 117.026 68.819 104.59 79.26 C 89.19 92.189 83.945 95.359 73.54 98.024 C 60.438 101.381 44.281 98.268 33.966 90.4 C 28.19 85.994 22.25 77.679 22.25 73.999 C 22.25 71.475 21.634 71.061 17.875 71.061 L 13.5 71.061 L 13.5 129.811 L 178.5 129.811 L 178.494 108.249 L 178.488 86.686 L 173.807 80.541 C 163.119 66.51 143.193 59.008 128.493 63.479"
|
||||
android:strokeWidth="1.25"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 129.75 63.348 C 122.865 65.451 115.829 70.014 103.442 80.413 C 96.136 86.547 86.969 92.947 82.48 95.048 C 60.304 105.426 32.044 97.046 23.267 77.492 C 21.242 72.979 20.328 72.179 17.191 72.179 L 13.5 72.179 L 13.5 129.679 L 178.5 129.679 L 178.456 108.742 C 178.41 86.981 178.329 86.587 172.313 78.669 C 163.463 67.022 142.469 59.466 129.75 63.348"
|
||||
android:strokeWidth="1.25"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 131.184 63.546 C 123.825 64.992 117.559 68.919 103.5 80.894 C 96.969 86.458 87.98 92.824 83.526 95.043 C 75.941 98.821 74.591 99.077 62.25 99.077 C 49.875 99.077 48.564 98.827 40.714 94.962 C 31.655 90.503 24.469 83.298 22.19 76.396 C 21.04 72.909 20.19 72.202 17.152 72.202 L 13.5 72.202 L 13.5 129.702 L 178.5 129.702 L 178.5 87.577 L 174.965 82.702 C 170.49 76.532 163.525 70.403 157.488 67.323 C 153.545 65.312 139.684 61.884 137.333 62.339 C 136.944 62.414 134.176 62.957 131.184 63.546"
|
||||
android:strokeWidth="1.25"/>
|
||||
</vector>
|
||||
13
dolby/res/drawable/ic_ieq_off.xml
Normal file
13
dolby/res/drawable/ic_ieq_off.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="192dp"
|
||||
android:height="192dp"
|
||||
android:viewportWidth="192"
|
||||
android:viewportHeight="192"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 13.5 96 L 13.5 103.5 L 178.5 103.5 L 178.5 88.5 L 13.5 88.5 L 13.5 96"
|
||||
android:strokeWidth="1.25"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
28
dolby/res/drawable/ic_ieq_warm.xml
Normal file
28
dolby/res/drawable/ic_ieq_warm.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="192dp"
|
||||
android:height="192dp"
|
||||
android:viewportWidth="192"
|
||||
android:viewportHeight="192"
|
||||
android:tint="?android:attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 48.789 64.919 C 45.865 66.366 40.885 70.429 37.721 73.948 C 28.465 84.243 13.479 116.446 13.479 126.041 L 13.479 129.786 L 95.979 129.786 C 141.354 129.786 178.479 129.486 178.479 129.12 C 178.479 128.753 177.131 125.8 175.483 122.558 C 170.413 112.579 162.723 104.006 155.705 100.509 C 149.673 97.503 148.053 97.286 131.582 97.286 C 105.944 97.286 102.89 95.881 86.335 76.454 C 74.977 63.124 61.056 58.848 48.789 64.919"
|
||||
android:strokeWidth="1.25"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 49.712 64.871 C 40.942 68.842 33.167 78.157 25.45 93.941 C 18.063 109.047 13.462 121.585 13.462 126.604 L 13.462 129.769 L 178.496 129.769 L 176.673 125.407 C 171.895 113.971 159.81 101.317 151.203 98.739 C 148.476 97.921 138.591 97.264 128.942 97.256 C 107.671 97.241 102.106 95.265 93.347 84.617 C 76.128 63.684 64.227 58.297 49.712 64.871"
|
||||
android:strokeWidth="1.25"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 52.781 63.452 C 47.321 65.482 40.256 70.907 35.792 76.496 C 27.971 86.29 13.406 119.09 13.406 126.91 L 13.406 129.502 L 178.552 129.502 L 174.586 122.06 C 169.31 112.162 163.213 105.23 156.113 101.056 C 150.453 97.729 149.705 97.625 130.807 97.53 C 107.81 97.414 103.646 96.04 94.012 85.387 C 80.912 70.9 77.898 68.045 73.171 65.632 C 67.157 62.565 57.846 61.569 52.781 63.452"
|
||||
android:strokeWidth="1.25"
|
||||
android:fillType="evenOdd"/>
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:pathData="M 56.078 63.069 C 44.607 65.852 35.711 75.314 26.246 94.802 C 19.707 108.263 16.537 116.731 14.817 125.334 L 14.005 129.397 L 95.98 129.397 C 165.857 129.397 177.953 129.136 177.953 127.627 C 177.953 124.146 165.22 106.857 160.048 103.314 C 152.515 98.156 150.572 97.791 129.828 97.641 C 111.478 97.507 110.935 97.424 104.33 93.776 C 99.905 91.331 95.316 87.208 91 81.798 C 80.578 68.737 74.351 64.324 64.203 62.812 C 61.797 62.453 58.141 62.568 56.078 63.069"
|
||||
android:strokeWidth="1.25"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
12
dolby/res/drawable/ic_launcher_background.xml
Normal file
12
dolby/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector android:height="108.0dip" android:width="108.0dip" android:viewportWidth="108.0" android:viewportHeight="108.0"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<group android:scaleX="1.3544992" android:scaleY="1.3544992" android:translateX="-23.22" android:translateY="-23.22">
|
||||
<group>
|
||||
<clip-path android:pathData="M57.01,57.01m-54,0a54,54 0,1 1,108 0a54,54 0,1 1,-108 0" />
|
||||
<path android:fillColor="#ffeaedef" android:pathData="M-1.9,-1.9h117.82v117.82h-117.82z" />
|
||||
<path android:fillColor="@drawable/ic_launcher_background__0" android:pathData="M-1.9,115.92l0,-117.82l117.82,0l-117.82,117.82z" />
|
||||
<path android:fillColor="@drawable/ic_launcher_background__1" android:pathData="M-1.9,-1.9h117.82v117.82h-117.82z" android:strokeAlpha="0.2" android:fillAlpha="0.2" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
6
dolby/res/drawable/ic_launcher_background__0.xml
Normal file
6
dolby/res/drawable/ic_launcher_background__0.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<gradient android:angle="0.0" android:type="linear" android:startX="57.01" android:startY="56.4" android:endX="57.01" android:endY="-1.58"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<item android:color="#ffffffff" android:offset="0.0" />
|
||||
<item android:color="#fff3f5f6" android:offset="1.0" />
|
||||
</gradient>
|
||||
6
dolby/res/drawable/ic_launcher_background__1.xml
Normal file
6
dolby/res/drawable/ic_launcher_background__1.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<gradient android:angle="0.0" android:type="linear" android:startX="-1.9" android:startY="115.92" android:endX="115.92" android:endY="-1.9"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<item android:color="#ff80d0ce" android:offset="0.0" />
|
||||
<item android:color="#ff9fa8da" android:offset="1.0" />
|
||||
</gradient>
|
||||
8
dolby/res/drawable/ic_launcher_foreground.xml
Normal file
8
dolby/res/drawable/ic_launcher_foreground.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector android:height="108.0dip" android:width="108.0dip" android:viewportWidth="108.0" android:viewportHeight="108.0"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<group android:scaleX="0.84" android:scaleY="0.84" android:translateX="23.76" android:translateY="23.76">
|
||||
<path android:fillColor="#ff465461" android:pathData="M12,19.13h5a16.87,16.87 0,0 1,0 33.74H12Z" />
|
||||
<path android:fillColor="#ff465461" android:pathData="M60,52.87H55a16.87,16.87 0,0 1,0 -33.74h5Z" />
|
||||
</group>
|
||||
</vector>
|
||||
4
dolby/res/drawable/ic_launcher_mono.xml
Normal file
4
dolby/res/drawable/ic_launcher_mono.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="108dp" android:width="108dp" android:viewportWidth="108" android:viewportHeight="108">
|
||||
<path android:fillColor="#000000" android:pathData="M36.6305484,38 C45.6078241,38.1592687 52.837468,45.7082857 52.837468,54.9974325 C52.837468,64.2865794 45.6078241,71.8355964 36.6307694,71.9948651 L32,72 L32,38 L36.6305484,38 Z M36.999,43.017 L36.999,66.977 L37.1225728,66.9701894 C42.9872179,66.559014 47.6837958,61.5395304 47.8337726,55.3050128 L47.837468,54.9974325 C47.837468,48.6211219 43.0833381,43.4425908 37.1223719,43.0246757 L36.999,43.017 Z M71.3694516,38 C62.3921759,38.1592687 55.162532,45.7082857 55.162532,54.9974325 C55.162532,64.2865794 62.3921759,71.8355964 71.3692306,71.9948651 L76,72 L76,38 L71.3694516,38 Z M71.000532,43.017 L71.000532,66.977 L70.8774272,66.9701894 C65.0127821,66.559014 60.3162042,61.5395304 60.1662274,55.3050128 L60.162532,54.9974325 C60.162532,48.6211219 64.9166619,43.4425908 70.8776281,43.0246757 L71.000532,43.017 Z" android:strokeWidth="1"/>
|
||||
</vector>
|
||||
9
dolby/res/drawable/reset_settings_24px.xml
Normal file
9
dolby/res/drawable/reset_settings_24px.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="?android:attr/colorControlNormal"
|
||||
android:pathData="M520,630L520,570L680,570L680,630L520,630ZM580,840L580,790L520,790L520,730L580,730L580,680L640,680L640,840L580,840ZM680,790L680,730L840,730L840,790L680,790ZM720,680L720,520L780,520L780,570L840,570L840,630L780,630L780,680L720,680ZM831,400L748,400Q722,312 649,256Q576,200 480,200Q363,200 281.5,281.5Q200,363 200,480Q200,552 232.5,612Q265,672 320,710L320,600L400,600L400,840L160,840L160,760L254,760Q192,710 156,637.5Q120,565 120,480Q120,405 148.5,339.5Q177,274 225.5,225.5Q274,177 339.5,148.5Q405,120 480,120Q609,120 706.5,199.5Q804,279 831,400Z" />
|
||||
</vector>
|
||||
9
dolby/res/drawable/save_as_24px.xml
Normal file
9
dolby/res/drawable/save_as_24px.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="?android:attr/colorControlNormal"
|
||||
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L680,120L840,280L840,492Q821,484 800.5,481.5Q780,479 760,482L760,313L647,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760L440,760L440,764L440,840L200,840ZM200,200L200,313L200,482Q200,485 200,494.5Q200,504 200,519L200,760L200,760L200,760Q200,760 200,760Q200,760 200,760L200,200Q200,200 200,200Q200,200 200,200ZM520,920L520,797L741,577Q750,568 761,564Q772,560 783,560Q795,560 806,564.5Q817,569 826,578L863,615Q871,624 875.5,635Q880,646 880,657Q880,668 876,679.5Q872,691 863,700L643,920L520,920ZM820,657L820,657L783,620L783,620L820,657ZM580,860L618,860L739,738L721,719L702,701L580,822L580,860ZM721,719L702,701L702,701L739,738L739,738L721,719ZM240,400L600,400L600,240L240,240L240,400ZM480,720Q481,720 482,720Q483,720 484,720L600,605Q600,603 600,602.5Q600,602 600,600Q600,550 565,515Q530,480 480,480Q430,480 395,515Q360,550 360,600Q360,650 395,685Q430,720 480,720Z"/>
|
||||
</vector>
|
||||
41
dolby/res/layout/ieq_icon_layout.xml
Normal file
41
dolby/res/layout/ieq_icon_layout.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 The Android Open Source Project
|
||||
(C) 2024 Paranoid Android
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@android:id/widget_frame"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="56dp"
|
||||
android:gravity="end|center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingRight="0dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<androidx.preference.internal.PreferenceImageView
|
||||
android:id="@+id/ieq_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:maxWidth="56dp"
|
||||
app:maxHeight="56dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
7
dolby/res/mipmap-anydpi/ic_launcher.xml
Normal file
7
dolby/res/mipmap-anydpi/ic_launcher.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_mono" />
|
||||
</adaptive-icon>
|
||||
102
dolby/res/values/arrays.xml
Normal file
102
dolby/res/values/arrays.xml
Normal file
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023-24 Paranoid Android
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!-- Dolby Atmos -->
|
||||
<string-array name="dolby_profile_entries">
|
||||
<item>@string/dolby_profile_dynamic</item>
|
||||
<item>@string/dolby_profile_video</item>
|
||||
<item>@string/dolby_profile_music</item>
|
||||
<item>@string/dolby_profile_voice</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_profile_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>8</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_preset_entries" translatable="false">
|
||||
<item>@string/dolby_preset_default</item>
|
||||
<item>@string/dolby_preset_rock</item>
|
||||
<item>@string/dolby_preset_jazz</item>
|
||||
<item>@string/dolby_preset_pop</item>
|
||||
<item>@string/dolby_preset_classical</item>
|
||||
<item>@string/dolby_preset_hiphop</item>
|
||||
<item>@string/dolby_preset_blues</item>
|
||||
<item>@string/dolby_preset_electronic</item>
|
||||
<item>@string/dolby_preset_metal</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_preset_values">
|
||||
<!--
|
||||
<item>0,0,0,0,0,0,0,0,0,0</item>
|
||||
<item>4,1,-2,-0.25,0,-2,0,-2,0.5,4</item>
|
||||
<item>0,0,0,-1,-1,-3,-0.5,0,0,0</item>
|
||||
<item>-2,-0.5,-5,-1,0,0,-0.5,-3,-0.5,0</item>
|
||||
<item>0,0,0,0,0.5,3,1,6,2,6</item>
|
||||
<item>3,0,-3,-0.5,-0.5,-3,-0.5,0,0,2</item>
|
||||
<item>2,2,-6,-2,3,1,0,1,0,2</item>
|
||||
<item>3,1,-1,0,-0.5,-3,-0.5,0,0,0</item>
|
||||
<item>2,0,0,-1.25,-1,-4,0,0,0,0</item>
|
||||
-->
|
||||
<item>0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0</item>
|
||||
<item>60,36,12,-12,-36,-24,-12,-8,-4,-20,-36,-20,-4,-20,-36,-16,4,32,60,60</item>
|
||||
<item>8,8,8,8,8,0,-8,-8,-8,-24,-40,-20,0,4,8,8,8,8,8,8</item>
|
||||
<item>-13,-1,11,-25,-61,-29,3,11,19,19,19,15,11,-9,-29,-9,11,15,19,19</item>
|
||||
<item>-32,-32,-32,-32,-32,-32,-32,-28,-24,-4,16,0,-16,24,64,32,0,32,64,64</item>
|
||||
<item>52,28,4,-20,-44,-24,-4,-4,-4,-24,-44,-24,-4,0,4,4,4,20,36,36</item>
|
||||
<item>28,28,28,-36,-100,-68,-36,4,44,28,12,4,-4,4,12,4,-4,12,28,28</item>
|
||||
<item>50,34,18,2,-14,-6,2,-2,-6,-26,-46,-26,-6,-2,2,2,2,2,2,2</item>
|
||||
<item>40,24,8,8,8,-4,-16,-12,-8,-32,-56,-24,8,8,8,8,8,8,8,8</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_dialogue_entries">
|
||||
<item>@string/dolby_off</item>
|
||||
<item>@string/dolby_low</item>
|
||||
<item>@string/dolby_medium</item>
|
||||
<item>@string/dolby_high</item>
|
||||
<item>@string/dolby_max</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_dialogue_values">
|
||||
<item>0</item>
|
||||
<item>2</item>
|
||||
<item>6</item>
|
||||
<item>9</item>
|
||||
<item>12</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_stereo_entries">
|
||||
<item>@string/dolby_low</item>
|
||||
<item>@string/dolby_medium</item>
|
||||
<item>@string/dolby_high</item>
|
||||
<item>@string/dolby_max</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_stereo_values">
|
||||
<item>4</item>
|
||||
<item>24</item>
|
||||
<item>44</item>
|
||||
<item>64</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_ieq_entries">
|
||||
<item>@string/dolby_off</item>
|
||||
<item>@string/dolby_balanced</item>
|
||||
<item>@string/dolby_warm</item>
|
||||
<item>@string/dolby_detailed</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="dolby_ieq_values">
|
||||
<item>0</item>
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
70
dolby/res/values/strings.xml
Normal file
70
dolby/res/values/strings.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023-24 Paranoid Android
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
|
||||
<!-- Dolby Atmos -->
|
||||
<string name="dolby_title">Dolby Atmos</string>
|
||||
<string name="dolby_enable">Use Dolby Atmos</string>
|
||||
<string name="dolby_profile_title">Choose a profile</string>
|
||||
<string name="dolby_preset">Graphic equalizer</string>
|
||||
<string name="dolby_off">Off</string>
|
||||
<string name="dolby_on">On</string>
|
||||
<string name="dolby_low">Low</string>
|
||||
<string name="dolby_medium">Medium</string>
|
||||
<string name="dolby_high">High</string>
|
||||
<string name="dolby_max">Max</string>
|
||||
<string name="dolby_unknown">Unknown</string>
|
||||
<string name="dolby_on_with_profile">On (%1$s)</string>
|
||||
<string name="dolby_category_settings">Settings</string>
|
||||
<string name="dolby_bass_enhancer">Bass enhancer</string>
|
||||
<string name="dolby_dialogue_enhancer">Dialogue enhancer</string>
|
||||
<string name="dolby_spk_virtualizer">Speaker virtualization</string>
|
||||
<string name="dolby_hp_virtualizer">Headphone virtualization</string>
|
||||
<string name="dolby_stereo_widening">Stereo widening</string>
|
||||
<string name="dolby_volume_leveler">Volume leveler</string>
|
||||
<string name="dolby_connect_headphones">Connect headphones</string>
|
||||
<string name="dolby_reset_profile">Reset to defaults</string>
|
||||
<string name="dolby_reset_profile_toast">Succesfully reset settings for %1$s profile</string>
|
||||
|
||||
<!-- Dolby profiles -->
|
||||
<string name="dolby_profile_dynamic">Dynamic</string>
|
||||
<string name="dolby_profile_video">Movie/Video</string>
|
||||
<string name="dolby_profile_music">Music</string>
|
||||
<string name="dolby_profile_voice">Voice</string>
|
||||
|
||||
<!-- Dolby equalizer presets -->
|
||||
<string name="dolby_preset_default">Flat (off)</string>
|
||||
<string name="dolby_preset_rock">Rock</string>
|
||||
<string name="dolby_preset_jazz">Jazz</string>
|
||||
<string name="dolby_preset_pop">Pop</string>
|
||||
<string name="dolby_preset_classical">Classical</string>
|
||||
<string name="dolby_preset_hiphop">Hip Hop</string>
|
||||
<string name="dolby_preset_blues">Blues</string>
|
||||
<string name="dolby_preset_electronic">Electronic</string>
|
||||
<string name="dolby_preset_country">Country</string>
|
||||
<string name="dolby_preset_dance">Dance</string>
|
||||
<string name="dolby_preset_metal">Metal</string>
|
||||
|
||||
<!-- Dolby equalizer UI -->
|
||||
<string name="dolby_geq_slider_label_gain">Gain</string>
|
||||
<string name="dolby_geq_preset">Preset</string>
|
||||
<string name="dolby_geq_preset_name">Preset name</string>
|
||||
<string name="dolby_geq_new_preset">New preset</string>
|
||||
<string name="dolby_geq_rename_preset">Rename preset</string>
|
||||
<string name="dolby_geq_delete_preset">Delete preset</string>
|
||||
<string name="dolby_geq_delete_preset_prompt">Do you want to delete this preset?</string>
|
||||
<string name="dolby_geq_reset_gains">Reset gains</string>
|
||||
<string name="dolby_geq_reset_gains_prompt">Do you want to reset this preset to defaults?</string>
|
||||
<string name="dolby_geq_preset_name_exists">Preset name already exists!</string>
|
||||
<string name="dolby_geq_preset_name_too_long">Preset name is too long!</string>
|
||||
|
||||
<!-- Dolby intelligent EQ -->
|
||||
<string name="dolby_ieq">Intelligent equalizer</string>
|
||||
<string name="dolby_balanced">Balanced</string>
|
||||
<string name="dolby_warm">Warm</string>
|
||||
<string name="dolby_detailed">Detailed</string>
|
||||
|
||||
</resources>
|
||||
77
dolby/res/xml/dolby_settings.xml
Normal file
77
dolby/res/xml/dolby_settings.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2023-24 Paranoid Android
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:title="@string/dolby_title">
|
||||
|
||||
<com.android.settingslib.widget.MainSwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="dolby_enable"
|
||||
android:title="@string/dolby_enable" />
|
||||
|
||||
<ListPreference
|
||||
android:key="dolby_profile"
|
||||
android:entries="@array/dolby_profile_entries"
|
||||
android:entryValues="@array/dolby_profile_values"
|
||||
android:defaultValue="0"
|
||||
android:title="@string/dolby_profile_title"
|
||||
android:summary="%s"
|
||||
android:icon="@drawable/ic_dolby" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/dolby_category_settings">
|
||||
|
||||
<Preference
|
||||
android:key="dolby_preset"
|
||||
android:title="@string/dolby_preset">
|
||||
<intent
|
||||
android:action="android.intent.action.MAIN"
|
||||
android:targetPackage="co.aospa.dolby.oplus"
|
||||
android:targetClass="co.aospa.dolby.oplus.geq.EqualizerActivity" />
|
||||
</Preference>
|
||||
|
||||
<co.aospa.dolby.oplus.preference.DolbyIeqPreference
|
||||
android:key="dolby_ieq"
|
||||
android:entries="@array/dolby_ieq_entries"
|
||||
android:entryValues="@array/dolby_ieq_values"
|
||||
android:title="@string/dolby_ieq" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="dolby_spk_virtualizer"
|
||||
android:title="@string/dolby_spk_virtualizer" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="dolby_virtualizer"
|
||||
android:title="@string/dolby_hp_virtualizer" />
|
||||
|
||||
<ListPreference
|
||||
android:key="dolby_stereo"
|
||||
android:entries="@array/dolby_stereo_entries"
|
||||
android:entryValues="@array/dolby_stereo_values"
|
||||
android:title="@string/dolby_stereo_widening"
|
||||
android:dependency="dolby_virtualizer" />
|
||||
|
||||
<ListPreference
|
||||
android:key="dolby_dialogue"
|
||||
android:entries="@array/dolby_dialogue_entries"
|
||||
android:entryValues="@array/dolby_dialogue_values"
|
||||
android:title="@string/dolby_dialogue_enhancer" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="dolby_bass"
|
||||
android:title="@string/dolby_bass_enhancer" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="dolby_volume"
|
||||
android:title="@string/dolby_volume_leveler" />
|
||||
|
||||
<Preference
|
||||
android:key="dolby_reset"
|
||||
android:title="@string/dolby_reset_profile" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
27
dolby/src/co/aospa/dolby/oplus/BootCompletedReceiver.kt
Normal file
27
dolby/src/co/aospa/dolby/oplus/BootCompletedReceiver.kt
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
|
||||
private const val TAG = "OplusDolby-Boot"
|
||||
|
||||
class BootCompletedReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Log.d(TAG, "Received intent: ${intent.action}")
|
||||
if (intent.action != Intent.ACTION_BOOT_COMPLETED) {
|
||||
return
|
||||
}
|
||||
|
||||
Log.i(TAG, "Boot completed, starting dolby")
|
||||
DolbyController.getInstance(context).onBootCompleted()
|
||||
}
|
||||
}
|
||||
23
dolby/src/co/aospa/dolby/oplus/DolbyActivity.kt
Normal file
23
dolby/src/co/aospa/dolby/oplus/DolbyActivity.kt
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus
|
||||
|
||||
import android.os.Bundle
|
||||
import co.aospa.dolby.oplus.preference.DolbySettingsFragment
|
||||
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity
|
||||
|
||||
private const val TAG = "DolbyActivity"
|
||||
|
||||
class DolbyActivity : CollapsingToolbarBaseActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
fragmentManager.beginTransaction()
|
||||
.replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame, DolbySettingsFragment(), TAG)
|
||||
.commit()
|
||||
}
|
||||
}
|
||||
136
dolby/src/co/aospa/dolby/oplus/DolbyAudioEffect.kt
Normal file
136
dolby/src/co/aospa/dolby/oplus/DolbyAudioEffect.kt
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus
|
||||
|
||||
import android.media.audiofx.AudioEffect
|
||||
import co.aospa.dolby.oplus.DolbyConstants.Companion.dlog
|
||||
import co.aospa.dolby.oplus.DolbyConstants.DsParam
|
||||
import java.util.UUID
|
||||
|
||||
class DolbyAudioEffect(priority: Int, audioSession: Int) : AudioEffect(
|
||||
EFFECT_TYPE_NULL, EFFECT_TYPE_DAP, priority, audioSession
|
||||
) {
|
||||
|
||||
var dsOn: Boolean
|
||||
get() = getIntParam(EFFECT_PARAM_ENABLE) == 1
|
||||
set(value) {
|
||||
setIntParam(EFFECT_PARAM_ENABLE, if (value) 1 else 0)
|
||||
enabled = value
|
||||
}
|
||||
|
||||
var profile: Int
|
||||
get() = getIntParam(EFFECT_PARAM_PROFILE)
|
||||
set(value) {
|
||||
setIntParam(EFFECT_PARAM_PROFILE, value)
|
||||
}
|
||||
|
||||
private fun setIntParam(param: Int, value: Int) {
|
||||
dlog(TAG, "setIntParam($param, $value)")
|
||||
val buf = ByteArray(12)
|
||||
int32ToByteArray(param, buf, 0)
|
||||
int32ToByteArray(1, buf, 4)
|
||||
int32ToByteArray(value, buf, 8)
|
||||
checkStatus(setParameter(EFFECT_PARAM_CPDP_VALUES, buf))
|
||||
}
|
||||
|
||||
private fun getIntParam(param: Int): Int {
|
||||
val buf = ByteArray(12)
|
||||
int32ToByteArray(param, buf, 0)
|
||||
checkStatus(getParameter(EFFECT_PARAM_CPDP_VALUES + param, buf))
|
||||
return byteArrayToInt32(buf).also {
|
||||
dlog(TAG, "getIntParam($param): $it")
|
||||
}
|
||||
}
|
||||
|
||||
fun resetProfileSpecificSettings(profile: Int = this.profile) {
|
||||
dlog(TAG, "resetProfileSpecificSettings: profile=$profile")
|
||||
setIntParam(EFFECT_PARAM_RESET_PROFILE_SETTINGS, profile)
|
||||
}
|
||||
|
||||
fun setDapParameter(param: DsParam, values: IntArray, profile: Int = this.profile) {
|
||||
dlog(TAG, "setDapParameter: profile=$profile param=$param")
|
||||
val length = values.size
|
||||
val buf = ByteArray((length + 4) * 4)
|
||||
int32ToByteArray(EFFECT_PARAM_SET_PROFILE_PARAMETER, buf, 0)
|
||||
int32ToByteArray(length + 1, buf, 4)
|
||||
int32ToByteArray(profile, buf, 8)
|
||||
int32ToByteArray(param.id, buf, 12)
|
||||
int32ArrayToByteArray(values, buf, 16)
|
||||
checkStatus(setParameter(EFFECT_PARAM_CPDP_VALUES, buf))
|
||||
}
|
||||
|
||||
fun setDapParameter(param: DsParam, enable: Boolean, profile: Int = this.profile) =
|
||||
setDapParameter(param, intArrayOf(if (enable) 1 else 0), profile)
|
||||
|
||||
fun setDapParameter(param: DsParam, value: Int, profile: Int = this.profile) =
|
||||
setDapParameter(param, intArrayOf(value), profile)
|
||||
|
||||
fun getDapParameter(param: DsParam, profile: Int = this.profile): IntArray {
|
||||
dlog(TAG, "getDapParameter: profile=$profile param=$param")
|
||||
val length = param.length
|
||||
val buf = ByteArray((length + 2) * 4)
|
||||
val p = (param.id shl 16) + (profile shl 8) + EFFECT_PARAM_GET_PROFILE_PARAMETER
|
||||
checkStatus(getParameter(p, buf))
|
||||
return byteArrayToInt32Array(buf, length)
|
||||
}
|
||||
|
||||
fun getDapParameterBool(param: DsParam, profile: Int = this.profile): Boolean =
|
||||
getDapParameter(param, profile)[0] == 1
|
||||
|
||||
fun getDapParameterInt(param: DsParam, profile: Int = this.profile): Int =
|
||||
getDapParameter(param, profile)[0]
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DolbyAudioEffect"
|
||||
private val EFFECT_TYPE_DAP =
|
||||
UUID.fromString("9d4921da-8225-4f29-aefa-39537a04bcaa")
|
||||
|
||||
private const val EFFECT_PARAM_ENABLE = 0
|
||||
private const val EFFECT_PARAM_CPDP_VALUES = 5
|
||||
private const val EFFECT_PARAM_PROFILE = 0xA000000
|
||||
private const val EFFECT_PARAM_SET_PROFILE_PARAMETER = 0x1000000
|
||||
private const val EFFECT_PARAM_GET_PROFILE_PARAMETER = 0x1000005
|
||||
private const val EFFECT_PARAM_RESET_PROFILE_SETTINGS = 0xC000000
|
||||
|
||||
private fun int32ToByteArray(value: Int, dst: ByteArray, index: Int) {
|
||||
var idx = index
|
||||
dst[idx++] = (value and 0xff).toByte()
|
||||
dst[idx++] = ((value ushr 8) and 0xff).toByte()
|
||||
dst[idx++] = ((value ushr 16) and 0xff).toByte()
|
||||
dst[idx] = ((value ushr 24) and 0xff).toByte()
|
||||
}
|
||||
|
||||
private fun byteArrayToInt32(ba: ByteArray): Int {
|
||||
return ((ba[3].toInt() and 0xff) shl 24) or
|
||||
((ba[2].toInt() and 0xff) shl 16) or
|
||||
((ba[1].toInt() and 0xff) shl 8) or
|
||||
(ba[0].toInt() and 0xff)
|
||||
}
|
||||
|
||||
private fun int32ArrayToByteArray(src: IntArray, dst: ByteArray, index: Int) {
|
||||
var idx = index
|
||||
for (x in src) {
|
||||
dst[idx++] = (x and 0xff).toByte()
|
||||
dst[idx++] = ((x ushr 8) and 0xff).toByte()
|
||||
dst[idx++] = ((x ushr 16) and 0xff).toByte()
|
||||
dst[idx++] = ((x ushr 24) and 0xff).toByte()
|
||||
}
|
||||
}
|
||||
|
||||
private fun byteArrayToInt32Array(ba: ByteArray, dstLength: Int): IntArray {
|
||||
val srcLength = ba.size shr 2
|
||||
val dst = IntArray(dstLength.coerceAtMost(srcLength))
|
||||
for (i in dst.indices) {
|
||||
dst[i] = ((ba[i * 4 + 3].toInt() and 0xff) shl 24) or
|
||||
((ba[i * 4 + 2].toInt() and 0xff) shl 16) or
|
||||
((ba[i * 4 + 1].toInt() and 0xff) shl 8) or
|
||||
(ba[i * 4].toInt() and 0xff)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
}
|
||||
}
|
||||
60
dolby/src/co/aospa/dolby/oplus/DolbyConstants.kt
Normal file
60
dolby/src/co/aospa/dolby/oplus/DolbyConstants.kt
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus
|
||||
|
||||
import android.util.Log
|
||||
|
||||
class DolbyConstants {
|
||||
|
||||
enum class DsParam(val id: Int, val length: Int = 1) {
|
||||
HEADPHONE_VIRTUALIZER(101),
|
||||
SPEAKER_VIRTUALIZER(102),
|
||||
VOLUME_LEVELER_ENABLE(103),
|
||||
IEQ_PRESET(104),
|
||||
DIALOGUE_ENHANCER_ENABLE(105),
|
||||
DIALOGUE_ENHANCER_AMOUNT(108),
|
||||
GEQ_BAND_GAINS(110, 20),
|
||||
BASS_ENHANCER_ENABLE(111),
|
||||
STEREO_WIDENING_AMOUNT(113);
|
||||
|
||||
override fun toString(): String {
|
||||
return "${name}(${id})"
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "OplusDolby"
|
||||
const val PREF_ENABLE = "dolby_enable"
|
||||
const val PREF_PROFILE = "dolby_profile"
|
||||
const val PREF_PRESET = "dolby_preset"
|
||||
const val PREF_IEQ = "dolby_ieq"
|
||||
const val PREF_HP_VIRTUALIZER = "dolby_virtualizer"
|
||||
const val PREF_SPK_VIRTUALIZER = "dolby_spk_virtualizer"
|
||||
const val PREF_STEREO = "dolby_stereo"
|
||||
const val PREF_DIALOGUE = "dolby_dialogue"
|
||||
const val PREF_BASS = "dolby_bass"
|
||||
const val PREF_VOLUME = "dolby_volume"
|
||||
const val PREF_RESET = "dolby_reset"
|
||||
|
||||
val PROFILE_SPECIFIC_PREFS = setOf(
|
||||
PREF_PRESET,
|
||||
PREF_IEQ,
|
||||
PREF_HP_VIRTUALIZER,
|
||||
PREF_SPK_VIRTUALIZER,
|
||||
PREF_STEREO,
|
||||
PREF_DIALOGUE,
|
||||
PREF_BASS,
|
||||
PREF_VOLUME
|
||||
)
|
||||
|
||||
fun dlog(tag: String, msg: String) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(tag, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
316
dolby/src/co/aospa/dolby/oplus/DolbyController.kt
Normal file
316
dolby/src/co/aospa/dolby/oplus/DolbyController.kt
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioDeviceCallback
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.media.AudioManager
|
||||
import android.media.AudioManager.AudioPlaybackCallback
|
||||
import android.media.AudioPlaybackConfiguration
|
||||
import android.os.Handler
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import co.aospa.dolby.oplus.DolbyConstants.Companion.dlog
|
||||
import co.aospa.dolby.oplus.DolbyConstants.DsParam
|
||||
import co.aospa.dolby.oplus.R
|
||||
|
||||
internal class DolbyController private constructor(
|
||||
private val context: Context
|
||||
) {
|
||||
private var dolbyEffect = DolbyAudioEffect(EFFECT_PRIORITY, audioSession = 0)
|
||||
private val audioManager = context.getSystemService(AudioManager::class.java)
|
||||
private val handler = Handler(context.mainLooper)
|
||||
|
||||
// Restore current profile on every media session
|
||||
private val playbackCallback = object : AudioPlaybackCallback() {
|
||||
override fun onPlaybackConfigChanged(configs: List<AudioPlaybackConfiguration>) {
|
||||
val isPlaying = configs.any {
|
||||
it.playerState == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
|
||||
}
|
||||
dlog(TAG, "onPlaybackConfigChanged: isPlaying=$isPlaying")
|
||||
if (isPlaying)
|
||||
setCurrentProfile()
|
||||
}
|
||||
}
|
||||
|
||||
// Restore current profile on audio device change
|
||||
private val audioDeviceCallback = object : AudioDeviceCallback() {
|
||||
override fun onAudioDevicesAdded(addedDevices: Array<AudioDeviceInfo>) {
|
||||
dlog(TAG, "onAudioDevicesAdded")
|
||||
setCurrentProfile()
|
||||
}
|
||||
|
||||
override fun onAudioDevicesRemoved(removedDevices: Array<AudioDeviceInfo>) {
|
||||
dlog(TAG, "onAudioDevicesRemoved")
|
||||
setCurrentProfile()
|
||||
}
|
||||
}
|
||||
|
||||
private var registerCallbacks = false
|
||||
set(value) {
|
||||
if (field == value) return
|
||||
field = value
|
||||
dlog(TAG, "setRegisterCallbacks($value)")
|
||||
if (value) {
|
||||
audioManager!!.registerAudioPlaybackCallback(playbackCallback, handler)
|
||||
audioManager.registerAudioDeviceCallback(audioDeviceCallback, handler)
|
||||
} else {
|
||||
audioManager!!.unregisterAudioPlaybackCallback(playbackCallback)
|
||||
audioManager.unregisterAudioDeviceCallback(audioDeviceCallback)
|
||||
}
|
||||
}
|
||||
|
||||
var dsOn: Boolean
|
||||
get() =
|
||||
dolbyEffect.dsOn.also {
|
||||
dlog(TAG, "getDsOn: $it")
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setDsOn: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.dsOn = value
|
||||
registerCallbacks = value
|
||||
if (value)
|
||||
setCurrentProfile()
|
||||
}
|
||||
|
||||
var profile: Int
|
||||
get() =
|
||||
dolbyEffect.profile.also {
|
||||
dlog(TAG, "getProfile: $it")
|
||||
}
|
||||
set(value) {
|
||||
dlog(TAG, "setProfile: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.profile = value
|
||||
}
|
||||
|
||||
init {
|
||||
dlog(TAG, "initialized")
|
||||
}
|
||||
|
||||
fun onBootCompleted() {
|
||||
dlog(TAG, "onBootCompleted")
|
||||
|
||||
// Restore our main settings
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
dsOn = prefs.getBoolean(DolbyConstants.PREF_ENABLE, true)
|
||||
|
||||
context.resources.getStringArray(R.array.dolby_profile_values)
|
||||
.map { it.toInt() }
|
||||
.forEach { profile ->
|
||||
// Reset dolby first to prevent it from loading bad settings
|
||||
dolbyEffect.resetProfileSpecificSettings(profile)
|
||||
// Now restore our profile-specific settings
|
||||
restoreSettings(profile)
|
||||
}
|
||||
|
||||
// Finally restore the current profile.
|
||||
setCurrentProfile()
|
||||
}
|
||||
|
||||
private fun restoreSettings(profile: Int) {
|
||||
dlog(TAG, "restoreSettings(profile=$profile)")
|
||||
val prefs = context.getSharedPreferences("profile_$profile", Context.MODE_PRIVATE)
|
||||
setPreset(
|
||||
prefs.getString(DolbyConstants.PREF_PRESET, getPreset(profile))!!,
|
||||
profile
|
||||
)
|
||||
setIeqPreset(
|
||||
prefs.getString(
|
||||
DolbyConstants.PREF_IEQ,
|
||||
getIeqPreset(profile).toString()
|
||||
)!!.toInt(),
|
||||
profile
|
||||
)
|
||||
setHeadphoneVirtEnabled(
|
||||
prefs.getBoolean(DolbyConstants.PREF_HP_VIRTUALIZER, getHeadphoneVirtEnabled(profile)),
|
||||
profile
|
||||
)
|
||||
setSpeakerVirtEnabled(
|
||||
prefs.getBoolean(DolbyConstants.PREF_SPK_VIRTUALIZER, getSpeakerVirtEnabled(profile)),
|
||||
profile
|
||||
)
|
||||
setStereoWideningAmount(
|
||||
prefs.getString(
|
||||
DolbyConstants.PREF_STEREO,
|
||||
getStereoWideningAmount(profile).toString()
|
||||
)!!.toInt(),
|
||||
profile
|
||||
)
|
||||
setDialogueEnhancerAmount(
|
||||
prefs.getString(
|
||||
DolbyConstants.PREF_DIALOGUE,
|
||||
getDialogueEnhancerAmount(profile).toString()
|
||||
)!!.toInt(),
|
||||
profile
|
||||
)
|
||||
setBassEnhancerEnabled(
|
||||
prefs.getBoolean(DolbyConstants.PREF_BASS, getBassEnhancerEnabled(profile)),
|
||||
profile
|
||||
)
|
||||
setVolumeLevelerEnabled(
|
||||
prefs.getBoolean(DolbyConstants.PREF_VOLUME, getVolumeLevelerEnabled(profile)),
|
||||
profile
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkEffect() {
|
||||
if (!dolbyEffect.hasControl()) {
|
||||
Log.w(TAG, "lost control, recreating effect")
|
||||
dolbyEffect.release()
|
||||
dolbyEffect = DolbyAudioEffect(EFFECT_PRIORITY, audioSession = 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCurrentProfile() {
|
||||
dlog(TAG, "setCurrentProfile")
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
profile = prefs.getString(DolbyConstants.PREF_PROFILE, "0" /*dynamic*/)!!.toInt()
|
||||
}
|
||||
|
||||
fun getProfileName(): String? {
|
||||
val profile = dolbyEffect.profile.toString()
|
||||
val profiles = context.resources.getStringArray(R.array.dolby_profile_values)
|
||||
val profileIndex = profiles.indexOf(profile)
|
||||
dlog(TAG, "getProfileName: profile=$profile index=$profileIndex")
|
||||
return if (profileIndex == -1) null else context.resources.getStringArray(
|
||||
R.array.dolby_profile_entries
|
||||
)[profileIndex]
|
||||
}
|
||||
|
||||
fun resetProfileSpecificSettings() {
|
||||
dlog(TAG, "resetProfileSpecificSettings")
|
||||
checkEffect()
|
||||
dolbyEffect.resetProfileSpecificSettings()
|
||||
context.deleteSharedPreferences("profile_$profile")
|
||||
}
|
||||
|
||||
fun getPreset(profile: Int = this.profile): String {
|
||||
val gains = dolbyEffect.getDapParameter(DsParam.GEQ_BAND_GAINS, profile)
|
||||
return gains.joinToString(separator = ",").also {
|
||||
dlog(TAG, "getPreset: $it")
|
||||
}
|
||||
}
|
||||
|
||||
fun setPreset(value: String, profile: Int = this.profile) {
|
||||
dlog(TAG, "setPreset: $value")
|
||||
checkEffect()
|
||||
val gains = value.split(",")
|
||||
.map { it.toInt() }
|
||||
.toIntArray()
|
||||
dolbyEffect.setDapParameter(DsParam.GEQ_BAND_GAINS, gains, profile)
|
||||
}
|
||||
|
||||
fun getPresetName(): String {
|
||||
val presets = context.resources.getStringArray(R.array.dolby_preset_values)
|
||||
val presetIndex = presets.indexOf(getPreset())
|
||||
return if (presetIndex == -1) {
|
||||
"Custom"
|
||||
} else {
|
||||
context.resources.getStringArray(
|
||||
R.array.dolby_preset_entries
|
||||
)[presetIndex]
|
||||
}
|
||||
}
|
||||
|
||||
fun getHeadphoneVirtEnabled(profile: Int = this.profile) =
|
||||
dolbyEffect.getDapParameterBool(DsParam.HEADPHONE_VIRTUALIZER, profile).also {
|
||||
dlog(TAG, "getHeadphoneVirtEnabled: $it")
|
||||
}
|
||||
|
||||
fun setHeadphoneVirtEnabled(value: Boolean, profile: Int = this.profile) {
|
||||
dlog(TAG, "setHeadphoneVirtEnabled: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.HEADPHONE_VIRTUALIZER, value, profile)
|
||||
}
|
||||
|
||||
fun getSpeakerVirtEnabled(profile: Int = this.profile) =
|
||||
dolbyEffect.getDapParameterBool(DsParam.SPEAKER_VIRTUALIZER, profile).also {
|
||||
dlog(TAG, "getSpeakerVirtEnabled: $it")
|
||||
}
|
||||
|
||||
fun setSpeakerVirtEnabled(value: Boolean, profile: Int = this.profile) {
|
||||
dlog(TAG, "setSpeakerVirtEnabled: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.SPEAKER_VIRTUALIZER, value, profile)
|
||||
}
|
||||
|
||||
fun getBassEnhancerEnabled(profile: Int = this.profile) =
|
||||
dolbyEffect.getDapParameterBool(DsParam.BASS_ENHANCER_ENABLE, profile).also {
|
||||
dlog(TAG, "getBassEnhancerEnabled: $it")
|
||||
}
|
||||
|
||||
fun setBassEnhancerEnabled(value: Boolean, profile: Int = this.profile) {
|
||||
dlog(TAG, "setBassEnhancerEnabled: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.BASS_ENHANCER_ENABLE, value, profile)
|
||||
}
|
||||
|
||||
fun getVolumeLevelerEnabled(profile: Int = this.profile) =
|
||||
dolbyEffect.getDapParameterBool(DsParam.VOLUME_LEVELER_ENABLE, profile).also {
|
||||
dlog(TAG, "getVolumeLevelerEnabled: $it")
|
||||
}
|
||||
|
||||
fun setVolumeLevelerEnabled(value: Boolean, profile: Int = this.profile) {
|
||||
dlog(TAG, "setVolumeLevelerEnabled: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.VOLUME_LEVELER_ENABLE, value, profile)
|
||||
}
|
||||
|
||||
fun getStereoWideningAmount(profile: Int = this.profile) =
|
||||
dolbyEffect.getDapParameterInt(DsParam.STEREO_WIDENING_AMOUNT, profile).also {
|
||||
dlog(TAG, "getStereoWideningAmount: $it")
|
||||
}
|
||||
|
||||
fun setStereoWideningAmount(value: Int, profile: Int = this.profile) {
|
||||
dlog(TAG, "setStereoWideningAmount: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.STEREO_WIDENING_AMOUNT, value, profile)
|
||||
}
|
||||
|
||||
fun getDialogueEnhancerAmount(profile: Int = this.profile): Int {
|
||||
val enabled = dolbyEffect.getDapParameterBool(DsParam.DIALOGUE_ENHANCER_ENABLE, profile)
|
||||
val amount = if (enabled) {
|
||||
dolbyEffect.getDapParameterInt(DsParam.DIALOGUE_ENHANCER_AMOUNT, profile)
|
||||
} else 0
|
||||
dlog(TAG, "getDialogueEnhancerAmount: enabled=$enabled amount=$amount")
|
||||
return amount
|
||||
}
|
||||
|
||||
fun setDialogueEnhancerAmount(value: Int, profile: Int = this.profile) {
|
||||
dlog(TAG, "setDialogueEnhancerAmount: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.DIALOGUE_ENHANCER_ENABLE, (value > 0), profile)
|
||||
dolbyEffect.setDapParameter(DsParam.DIALOGUE_ENHANCER_AMOUNT, value, profile)
|
||||
}
|
||||
|
||||
fun getIeqPreset(profile: Int = this.profile) =
|
||||
dolbyEffect.getDapParameterInt(DsParam.IEQ_PRESET, profile).also {
|
||||
dlog(TAG, "getIeqPreset: $it")
|
||||
}
|
||||
|
||||
fun setIeqPreset(value: Int, profile: Int = this.profile) {
|
||||
dlog(TAG, "setIeqPreset: $value")
|
||||
checkEffect()
|
||||
dolbyEffect.setDapParameter(DsParam.IEQ_PRESET, value, profile)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "DolbyController"
|
||||
private const val EFFECT_PRIORITY = 100
|
||||
|
||||
@Volatile
|
||||
private var instance: DolbyController? = null
|
||||
|
||||
fun getInstance(context: Context) =
|
||||
instance ?: synchronized(this) {
|
||||
instance ?: DolbyController(context).also { instance = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
36
dolby/src/co/aospa/dolby/oplus/DolbyTileService.kt
Normal file
36
dolby/src/co/aospa/dolby/oplus/DolbyTileService.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus
|
||||
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
|
||||
private const val TAG = "DolbyTileService"
|
||||
|
||||
class DolbyTileService : TileService() {
|
||||
|
||||
private val dolbyController by lazy { DolbyController.getInstance(applicationContext) }
|
||||
|
||||
override fun onStartListening() {
|
||||
qsTile.apply {
|
||||
state = if (dolbyController.dsOn) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE
|
||||
subtitle = dolbyController.getProfileName() ?: getString(R.string.dolby_unknown)
|
||||
updateTile()
|
||||
}
|
||||
super.onStartListening()
|
||||
}
|
||||
|
||||
override fun onClick() {
|
||||
val isDsOn = dolbyController.dsOn
|
||||
dolbyController.dsOn = !isDsOn
|
||||
qsTile.apply {
|
||||
state = if (isDsOn) Tile.STATE_INACTIVE else Tile.STATE_ACTIVE
|
||||
updateTile()
|
||||
}
|
||||
super.onClick()
|
||||
}
|
||||
}
|
||||
70
dolby/src/co/aospa/dolby/oplus/SummaryProvider.kt
Normal file
70
dolby/src/co/aospa/dolby/oplus/SummaryProvider.kt
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
* (C) 2023-24 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus
|
||||
|
||||
import android.content.ContentProvider
|
||||
import android.content.ContentValues
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import co.aospa.dolby.oplus.R
|
||||
import com.android.settingslib.drawer.TileUtils.META_DATA_PREFERENCE_SUMMARY
|
||||
|
||||
private const val KEY_DOLBY = "dolby"
|
||||
|
||||
/** Provide preference summary for injected items. */
|
||||
class SummaryProvider : ContentProvider() {
|
||||
|
||||
override fun call(
|
||||
method: String,
|
||||
arg: String?,
|
||||
extras: Bundle?
|
||||
): Bundle? {
|
||||
val summary = when (method) {
|
||||
KEY_DOLBY -> getDolbySummary()
|
||||
else -> return null
|
||||
}
|
||||
return Bundle().apply {
|
||||
putString(META_DATA_PREFERENCE_SUMMARY, summary)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(): Boolean = true
|
||||
|
||||
override fun query(
|
||||
uri: Uri,
|
||||
projection: Array<String>?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<String>?,
|
||||
sortOrder: String?
|
||||
): Cursor? = null
|
||||
|
||||
override fun getType(uri: Uri): String? = null
|
||||
|
||||
override fun insert(uri: Uri, values: ContentValues?): Uri? = null
|
||||
|
||||
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int = 0
|
||||
|
||||
override fun update(
|
||||
uri: Uri,
|
||||
values: ContentValues?,
|
||||
selection: String?,
|
||||
selectionArgs: Array<String>?
|
||||
): Int = 0
|
||||
|
||||
private fun getDolbySummary(): String {
|
||||
val dolbyController = DolbyController.getInstance(context!!)
|
||||
if (!dolbyController.dsOn) {
|
||||
return context!!.getString(R.string.dolby_off)
|
||||
}
|
||||
return dolbyController.getProfileName()?.let {
|
||||
context!!.getString(R.string.dolby_on_with_profile, it)
|
||||
} ?: context!!.getString(R.string.dolby_on)
|
||||
}
|
||||
|
||||
}
|
||||
53
dolby/src/co/aospa/dolby/oplus/geq/EqualizerActivity.kt
Normal file
53
dolby/src/co/aospa/dolby/oplus/geq/EqualizerActivity.kt
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus.geq
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import co.aospa.dolby.oplus.R
|
||||
import co.aospa.dolby.oplus.geq.ui.EqualizerScreen
|
||||
import co.aospa.dolby.oplus.geq.ui.EqualizerViewModel
|
||||
import com.android.settingslib.spa.framework.compose.localNavController
|
||||
import com.android.settingslib.spa.framework.theme.SettingsTheme
|
||||
import com.android.settingslib.spa.widget.scaffold.SettingsScaffold
|
||||
|
||||
class EqualizerActivity : ComponentActivity() {
|
||||
|
||||
private val viewModel: EqualizerViewModel by viewModels { EqualizerViewModel.Factory }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
SettingsTheme {
|
||||
MainContent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MainContent() {
|
||||
val navController = rememberNavController()
|
||||
CompositionLocalProvider(navController.localNavController()) {
|
||||
SettingsScaffold(
|
||||
title = stringResource(id = R.string.dolby_preset)
|
||||
) { paddingValues ->
|
||||
EqualizerScreen(
|
||||
viewModel = viewModel,
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
dolby/src/co/aospa/dolby/oplus/geq/data/BandGain.kt
Normal file
12
dolby/src/co/aospa/dolby/oplus/geq/data/BandGain.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (C) 2024 Paranoid Android
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package co.aospa.dolby.oplus.geq.data
|
||||
|
||||
data class BandGain(
|
||||
val band: Int,
|
||||
var gain: Int = 0
|
||||
)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user