83 Commits
bka ... vic

Author SHA1 Message Date
7854cf6443 sepolicy: qti: Allow system server to detect oem charging
Signed-off-by: AnierinB <anierin@evolution-x.org>
2025-09-12 13:53:12 -04:00
DragonEmperor9480
87797f25be sepolicy: adress fingerprint denials
*1565  1775 E [ANC_TAC][File]: AncMkDir: fail to mkdir /data/vendor/fingerprint/info, errno = 13, errnostr = Permission denied
*667   667 W qseecomd: type=1400 audit(0.0:82): avc:  denied  { write } for  name="debase_context" dev="sda2" ino=565 scontext=u:r:tee:s0 tcontext=u:object_r:vendor_persist_fingerprint_file:s0 tclass=file permissive=0
*1565  1565 W fingerprint@2.1: type=1400 audit(0.0:106): avc:  denied  { write } for  name="tee_bind_core" dev="proc" ino=4026532098 scontext=u:r:hal_fingerprint_default:s0 tcontext=u:object_r:proc:s0 tclass=file permissive=0
*667   667 W qseecomd: type=1400 audit(0.0:107): avc:  denied  { write } for  name="debase_context" dev="sda2" ino=565 scontext=u:r:tee:s0 tcontext=u:object_r:vendor_persist_fingerprint_file:s0 tclass=file permissive=0
*1565  1565 W fingerprint@2.1: type=1400 audit(0.0:78): avc:  denied  { write } for  name="tee_bind_core" dev="proc" ino=4026532098 scontext=u:r:hal_fingerprint_default:s0 tcontext=u:object_r:proc:s0 tclass=file permissive=0
*1565  1565 W fingerprint@2.1: type=1400 audit(0.0:79): avc:  denied  { read } for  name="u:object_r:serialno_prop:s0" dev="tmpfs" ino=3880 scontext=u:r:hal_fingerprint_default:s0 tcontext=u:object_r:serialno_prop:s0 tclass=file permissive=0
*1565  1565 W fingerprint@2.1: type=1400 audit(0.0:80): avc:  denied  { create } for  name="image_raw" scontext=u:r:hal_fingerprint_default:s0 tcontext=u:object_r:fingerprint_vendor_data_file:s0 tclass=dir permissive=0
2025-09-12 13:53:12 -04:00
bc83d6ab33 sepolicy: qti: Allow system_server to r/w oplus_chg nodes 2025-09-12 13:53:12 -04:00
Broly1
55220ee27f keyhandler: Move Alert Slider to Sound settings and remove icon 2025-09-12 13:53:12 -04:00
Adhitya Mohan
6d23f9acaa Add icon and summary for alert slider settings 2025-09-12 13:53:12 -04:00
Adhitya Mohan
30dc0eecac Keyhandler: Export Keyhandler setting and service 2025-09-12 13:53:12 -04:00
inferno0230
da51d42fd5 sensors: Bump android.hardware.sensors to V3-ndk
Signed-off-by: inferno0230 <mail@inferno0230.in>
2025-09-12 13:53:12 -04:00
Alcatraz323
1a522811ae Implement DSPVolumeSynchronizer
Some Xiaomi devices have a speaker that needs a framework to cooperate
with DSP to synchronize volume so that the DSP can limit bass when the
volume is high to prevent distortion.

Change-Id: I750803d94161e1e7482552d2a39566f42e82fc0a
2025-09-12 13:53:12 -04:00
Ghosuto
99ff16bb54 dolby: Update to use new tooltip position provider API 2025-09-12 13:53:12 -04:00
Sugakesshaa
636b4d6428 vintf: Add oplus Dolby Atmos entries to FCM
Change-Id: Ifc4dff53e516f33b9e5581d56ce6f9c00f0da8cf
2025-09-12 13:53:12 -04:00
Sugakesshaa
fa4fe970ce dolby: Create a split makefile for Dolby
Change-Id: Ie191d7af0ee55c44cc939fc5dd1b6e45c965dbf4
2025-09-12 13:53:12 -04:00
Adithya R
9a9ac9f666 sepolicy: qti: Add sepolicy for Dolby Atmos
Change-Id: I8c41ff32e579cec9c871d6a0177ca027034281c8
2025-09-12 13:53:12 -04:00
Sugakesshaa
f725f3be91 dolby: Rebrand to oplus
Change-Id: Ic54a93647c0dcbe3b1ef8b576d80cc4c6bf74992
2025-09-12 13:53:12 -04:00
Fabian Leutenegger
cd00f3d796 dolby: Switch to MaterialTheme settingsBackground for EqualizerScreen background color
Change-Id: I546e3528814276eb857a650cb6c173d914550fb5
2025-09-12 13:53:12 -04:00
Bruno Martins
a726af6db4 dolby: Use all shared resources from devicesettings
Change-Id: Icd7f381c574ea36eb4d797cefd60ba9f1a0941bd
2025-09-12 13:53:12 -04:00
Pranav Vashi
9e91203f38 dolby: Remove deprecated PlainTooltipBox
Change-Id: I70ffff5ba30c5eeaff431e46c82eaf05d46e4cb0
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
2025-09-12 13:53:12 -04:00
basamaryan
fe45968ff3 dolby: Fix build with kotlinc 1.9.0
Reformat the code while at it

Change-Id: I4f9fdc9d25eb57240612cff1b3bef3663014f9a8
2025-09-12 13:53:12 -04:00
Michael Bestas
556ea40ab7 dolby: Convert to SwitchPreferenceCompat
Change-Id: Ic1cbaba37d499da1855af9c3930f2df426e2d3af
2025-09-12 13:53:12 -04:00
Chaohui Wang
fcb33262c5 dolby: Migrate to CompoundButton.OnCheckedChangeListener
Switch and SwitchCompat are both CompoundButton.

Using CompoundButton in Java will helps migration in the future.

Bug: 306658427 | AOSP | AOSP
Test: manual - check Settings pages
Test: m RunSettingsLibRoboTests
Change-Id: I85a70d4c504d8584030ea4a058f30d74206ab835
2025-09-12 13:53:12 -04:00
Peter Kalauskas
8f6493a247 dolby: Enable use_resource_processor for all sysui deps
This will make the build faster

Test: m checkbuild
Bug: 295208392
Change-Id: I0c1bd901429bbe3bf81c1530e156735f8637a96e
2025-09-12 13:53:12 -04:00
Adithya R
2d7496345c dolby: Add intelligent equalizer setting
Move preference-related classes to a new package while we're at it,
to reduce code clutter.

Change-Id: I2430e8ab9b6758503ce1777ec985a3e400b55b8e
2025-09-12 13:53:12 -04:00
Adithya R
460a99212e dolby: Introduce graphical equalizer
Squashed:

dolby: Refresh preset name on main screen

Change-Id: I96783e2a03c384f031787f4cc9140f7d64dadb2f
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>

Change-Id: I38ee6ce594e5671af42afc3d4bf0f004329482b9
2025-09-12 13:53:12 -04:00
Pranav Vashi
a9875242af dolby: Add launcher icon
Change-Id: I4d36842ca96048f9b55604d66cc7741759d657f3
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
[adithya2306: Add monochrome icon as well]
Signed-off-by: Adithya R <gh0strider.2k18.reborn@gmail.com>
2025-09-12 13:53:12 -04:00
Adithya R
cb104e3d65 dolby: Restore current profile _after_ resetting profiles
Ensure to end the onBootCompleted routine with the correct profile set.

Change-Id: I2d5f74a7c0145af2f9d064cd98fa2dc70e5a7acd
2025-09-12 13:53:12 -04:00
Adithya R
e5a3466a01 dolby: Do not set volume leveler amount
This value is set to zero in almost every known dax-default.xml,
including ours.
DaxService also doesn't mess with this value, instead only sets
VolumeLevelerEnabled.

Change-Id: Ib944728d478cff58aebc4f47128bcd5fe32ff9f6
2025-09-12 13:53:12 -04:00
Adithya R
791acfda43 dolby: Restore all settings upon bootup
Dolby often messes up restoring profile-specific settings after a reboot.
"Fine. I'll do it myself."

Change-Id: Ic255c6922eabae0b522c05110f87e2c10a97fb6c
2025-09-12 13:53:12 -04:00
Adithya R
e7acd1fa7f dolby: Rewrite in Kotlin
Some cleanup and restructuring while we're at it.

Change-Id: I2f1fc53c202d91421c7b6af68c814c25398a62e4
2025-09-12 13:53:12 -04:00
Adithya R
55a0e6b7fc dolby: Revert "Re-enable speaker virtualization after bootup"
No longer necessary

Change-Id: Iac820eafa71ea3e4ccaad2bfa0fb76c37279a22a
2025-09-12 13:53:12 -04:00
Adithya R
b46821b47c xiaomi: Introduce Dolby Atmos
Moved from marble/sm8450-common

History:

commit 82fe03168c0402e4cb10d25859c3b398c0ef654a
Author: Adithya R <gh0strider.2k18.reborn@gmail.com>
Date:   Thu Mar 21 21:35:36 2024 +0530

    marble: parts: Restore dolby profile on audio changes

    Something keeps resetting back at random times, from what I observed,
    after resuming media or on a device change, lets workaround that.

    Change-Id: Id065f2482636194655c2399f0c35ad56b8e7a29d

commit c4400bd1326f65aeac1d0f26bb830ce7fd079773
Author: Adithya R <gh0strider.2k18.reborn@gmail.com>
Date:   Fri Feb 2 09:29:08 2024 +0530

    marble: parts/keyhandler: Guard debug logging

    Change-Id: I246941f26cd1f71b696eb3c996794c9baa5dbc00

commit f11b70a98a11d0b89673d73002996aed9f11fbd7
Author: Adithya R <gh0strider.2k18.reborn@gmail.com>
Date:   Sun Dec 31 20:36:52 2023 +0530

    marble: parts: Re-enable speaker virtualization after bootup

    For whatever reason, speaker virtualization isn't automatically
    restored at bootup unlike the other parameters. It was reported to be
    fixed by connecting and disconnecting headphones or disabling and
    enabling the toggle, so let's just automate that at bootup.

commit abcff4fb947c89b69c1d25bd290fd91b7873af6a
Author: Adithya R <gh0strider.2k18.reborn@gmail.com>
Date:   Fri Oct 20 06:49:19 2023 +0530

    marble: parts: Implement profile-specific Dolby settings

    Some refactoring and cleanup while we're at it.

commit dc54f9ddeff212d017b0cba16e56516e99335bb3
Author: Adithya R <gh0strider.2k18.reborn@gmail.com>
Date:   Mon Oct 9 21:58:58 2023 +0530

    marble: parts: Remove play/pause hack while toggling Dolby

    Not required with/fixed by:
    35217: audioflinger: Do not allow DAP effect to be suspended | https://gerrit.aospa.co/c/AOSPA/android_frameworks_av/+/35217

commit dd2acc8e0c10d05f86ff229412cc9f72ea242b44
Author: Adithya R <gh0strider.2k18.reborn@gmail.com>
Date:   Wed Sep 13 21:41:20 2023 +0530

    marble: parts: Set proper summary for dolby settings

    Show the current status in Settings > Sound as well as the QS tile.

commit 92d341ba3d22f323eded525487db4289d6edc0fe
Author: Fabian Leutenegger <fabian.leutenegger@bluewin.ch>
Date:   Fri Aug 25 10:26:53 2023 +0200

    marble: parts: Always refresh playback if status changed

     * otherwise dolby would stay active even if you disable its setting

    Change-Id: If59d8081fa12da2aa67e5149db97965c0805d76e

commit b1944744649b6fddcb7bc3864b92f298b6e78821
Author: Adithya R <gh0strider.2k18.reborn@gmail.com>
Date:   Mon Aug 21 13:21:18 2023 +0530

    marble: parts: Introduce Dolby Atmos

    Based on existing dirac implementation and observing stock
    sound effects app and daxservice.

    Thanks to jhenrique09 for the hack from old dirac parts
    "Pause/play music stream to get effects applied".

    TODO: bring back misound (same as stock)

    Co-authored-by: Henrique Silva <jhenrique09.mcz@hotmail.com>

Change-Id: I79841c045fe7b92c438177916f756faab72ff0e9
2025-09-12 13:53:12 -04:00
Sugakesshaa
3fec8a2160 sepolicy: qti: Allow powerhal write to /proc
Change-Id: Id894d56fdf0df323e75004c90c0b904eb450837c
2025-09-12 13:53:12 -04:00
Sugakesshaa
55c9700299 sepolicy: qti: Allow binder calls for sensor hal to system_server
Change-Id: Ic624ff754f0bf7f60f443a449987e30ca2691dfd
2025-09-12 13:53:12 -04:00
pjgowtham
1e93163668 aidl: sensors: Add clang-format
Change-Id: Ifece344ef765d5437eefd59ecbe4cd50ce1295f5
2025-09-12 13:53:12 -04:00
pjgowtham
e5e0f18f31 overlay/sensors: Configure Doze brightness sensor
Oplus doze brightness sensors either reports 0 or 1

0.0 - Dark environment
1.0 - Bright environment

aod_light_mode value of 1 enables qcom,mdss-dsi-aod-low-mode-command
and any other value would enable qcom,mdss-dsi-aod-high-mode-command

Change-Id: I98e3ea6abe0375ca75dad1b82e0bc6a1551cbb0e
2025-09-12 13:53:12 -04:00
pjgowtham
373f8335ec overlay: qssi: Define quick_pickup sensor string
Tests: Ensure quick pickup works when the "Lift to check phone"
is enabled under settings (with fingerprint enrolled)

Change-Id: I00626512dcca51d666e37dda4b281575bf1a2ea7
2025-09-12 13:53:12 -04:00
Sebastiano Barezzi
4b6662f6cf overlay: qssi: Enable config_dozePulsePickup
Change-Id: Ice5cd780eb77e2ae78a3a84a0140c321ad84f143
2025-09-12 13:53:12 -04:00
pjgowtham
35c76b7f85 sepolicy: qti: Label sensors AIDL multihal
Change-Id: I51d1f5542f3bb6922d0f3d9b39777bc8b1ff58ff
Signed-off-by: Vaisakh Murali <mvaisakh@statixos.com>
2025-09-12 13:53:12 -04:00
pjgowtham
62f85bdab9 aidl: sensors: Standardize qti.sensor.amd to glance sensor
Change-Id: I65150cffde2bd8a48c33b26a0f139a24687f8591
2025-09-12 13:53:12 -04:00
Sugakesshaa
37f2b80fcc aidl: sensors: Invert value for pickup gesture event
- oplus pickup sensor inverts the value for it to work properly;
- Hence, invert the event check for it to work accordingly.

thanks to @ cyberknight777 for the idea

Test: Build, test lift to check phone.

Change-Id: If09de1758823e2246106d6e278ecc80ca5327ee5
2025-09-12 13:53:12 -04:00
Cosmin Tanislav
a71cd8bba5 aidl: sensors: Change standard tilt_detector to pickup_gesture
* ignore non-wakeup sensor variant
* ignore events that do not properly match a pickup

pjgowtham: The tilt_detector sensor already has inverted sensor events
for it to be any useful as standard sensor. Thus repurpose them as
pickup sensor.

Change-Id: Ibe2f9fee1551da613713d40c1b8d0a26d38a93ae
Signed-off-by: ralph950412 <ralph950412@gmail.com>
Signed-off-by: Sugakesshaa <sugakesshaa@pixelos.net>
2025-09-12 13:53:12 -04:00
Cosmin Tanislav
07a7277cc7 aidl: sensors: Avoid target name conflicts
Change-Id: Ib6426caf68fe1a7a7f637bdc5c4f0036866f8b78
Signed-off-by: ralph950412 <ralph950412@gmail.com>
Signed-off-by: Cyber Knight <cyberknight755@gmail.com>
2025-09-12 13:53:12 -04:00
Arian
357e7bdd36 aidl: sensors: Change default applicable license to Android-Apache-2.0
hardware_interfaces_license is not available here.

Change-Id: I8c8d00cdeda2739c3e4419f979f1fbf0ef66fc0a
2025-09-12 13:53:12 -04:00
ralph950412
f1565a99e2 aidl: sensors: Import 2.X sensors hal proxy
* From android-14.0.0_r15

Change-Id: Id6f37920db2869574ca1b8e04c10e6ec3268ad4b
Signed-off-by: ralph950412 <ralph950412@gmail.com>
Signed-off-by: Cyber Knight <cyberknight755@gmail.com>
2025-09-12 13:53:12 -04:00
ralph950412
5dc2395c1a aidl: sensors: Import aidl sensors MultiHal
* From android-14.0.0_r15

Change-Id: Id7d8dfae1290bdba84d5a9f4c6583d54a2769ba8
Signed-off-by: ralph950412 <ralph950412@gmail.com>
2025-09-12 13:53:12 -04:00
pjgowtham
b93792e127 aidl: vibrator: Use THUD effect from wly for DOUBLE_CLICK
Change-Id: I4f1a718254ca1df5167956371e11b4102b10094c
2025-09-12 13:53:12 -04:00
pjgowtham
befcb928b3 aidl: vibrator: Minimize code for ledVibratorDevice
This fixes vibration on ziti where it works only when strace is used.

* Minimize code wherever applicable.
* Remove writes to /rtp since we are not using them.

Change-Id: I385fe64b33e541bc398e58dbbf67a728edff8b24
2025-09-12 13:53:12 -04:00
pjgowtham
7f3969b7c7 sepolicy: qti: Allow init to write to usb nodes for enabling OTG
Change-Id: I14d209d1d04ba6aae077f828a71f5683b4a6405c
2025-09-12 13:53:12 -04:00
inferno0230
34a24318a8 sepolicy: qti: Label SM7550 charging sysfs path
Change-Id: Ia79079f3df34714e5a8f9294d3db6048552609e6
Signed-off-by: inferno0230 <mail@inferno0230.in>
2025-09-09 22:06:47 +02:00
LuK1337
495cfb6640 sepolicy: qti: Allow vendor_init to set vendor_fingerprint_prop
Change-Id: Icc898bba9d8a06b79e1cfcf34412871471a9bdf7
Signed-off-by: inferno0230 <mail@inferno0230.in>
2025-09-09 19:54:53 +05:30
dianlujitao
7a643a4105 sepolicy: qti: Move proc_horae to vendor
This fixes booting AOSP GSIs.

Fixes: 8acb73ff6a ("sepolicy: qti: Add support for horae service")
Change-Id: Ica812bb31d6c60b4ec5f6837de7712bd0c275543
2025-09-07 15:29:03 +08:00
dianlujitao
8ae5447fc5 Euicc: Add China version support
Despite lack of native eSIM hardware, this enables managing removable
eUICCs through EuiccGoogle

Change-Id: I9d5a360dde85ede18761ff795641e199507ff688
2025-09-06 14:39:20 +00:00
LuK1337
20b9ca79d6 livedisplay: Use PWM turbo for IAntiFlicker if available
Change-Id: I4162f79c5309038dfff1bd00f2ca8a726c7eb206
2025-09-06 13:56:59 +00:00
LuK1337
b7e4686284 kernel-headers: Add PANEL_IOCTL_{GET,SET}_PWM_TURBO
Change-Id: I0c63693be15a09baa582d14113b642e086e94d6e
2025-09-06 13:56:59 +00:00
grep
641f44934c vintf: Bump vendor.oplus.hardware.charger to V8
lexus shipped with V8.

Change-Id: I0b4733fcb7f5e3ac0834b8526e1ec5a99fd0e8c3
2025-09-06 12:25:27 +02:00
Bruno Martins
d2e134e7c0 interfaces: Mark all aidl interfaces as system_ext_specific
Change-Id: I62d8099cae1d3c2cbe98d5bc514a0713eb84cbe9
2025-09-05 17:11:22 +01:00
Bruno Martins
860533d2bb interfaces: Update ICharger all the way to V8
V7 adds GET_RX_DISABLE_STATUS and SET_RX_DISABLE enum entries on top of
V6 and V8 finally adds only GET_BATTERY_SEC_IC_TEST_STATUS.

Change-Id: I134bac4ffc536280dbb778a4a349943b67c175dc
2025-09-05 15:49:48 +01:00
Bruno Martins
70168c51f2 interfaces: Bump ICharger directly to V5
Looks like V4 never existed.

Change-Id: I1999da190461411913e98d98c258a2825fb039d5
2025-09-05 15:48:10 +01:00
Bruno Martins
c0d70dc0f9 interfaces: Update ICharger to V3
Change-Id: Ife15bb3b9f51dbc83bb975a7603f47985e1178bd
2025-09-05 15:47:13 +01:00
Bruno Martins
e8d95112d7 interfaces: Update ICharger to V2
Change-Id: I2ffe384dad647c3e115d6bb1d2e7d85e94d720e5
2025-09-05 15:46:18 +01:00
Bruno Martins
8c1e19bdb8 interfaces: Add vendor.oplus.hardware.charger V1
Change-Id: Ia3916a80e106c3b92428b1239c0fae90b8a5eaf3
2025-09-05 15:45:00 +01:00
Bruno Martins
a9438581bb sepolicy: qti: Add inital eSIM support
Change-Id: Iae2d3c17a6eb5a9b1c71198c8ac861ad4e5f85d5
2025-09-05 13:42:42 +00:00
Bruno Martins
63795ed4d4 sepolicy: qti: Update compatibility mapping files
Change-Id: I6d10fa03042e4f360a494a7eb2c9ffd0502c86a4
2025-09-04 16:05:55 +01:00
chandu078
8acb73ff6a sepolicy: qti: Add support for horae service
Service required for thermal management, as it reports and updates shell
temperature to /proc/shell-temp.

Change-Id: I02e2ddeda461cbb2ead1348edc6ebf57b8f7fdde
2025-09-04 13:30:17 +01:00
LuK1337
3633fe6cbe oplus: Get rid of in_ prefix
Change-Id: Ibdafd315098ccc54ec19f298bdb28cb894017489
2025-09-04 11:17:09 +00:00
pjgowtham
b122025d2d Introduce vendor.oplus.hardware.performance-service
Dummy service named differently from the stock one to avoid conflicts.

This can be used on devices that do not include CPU ricing, but still
require the service to register for camera and prebuilt audio stack to
actually work.

Change-Id: I41087aefe9af57e7a1161a3a71ab3b9e849925f2
2025-09-04 10:14:22 +00:00
pjgowtham
8ecfa3412a interfaces: Add vendor.oplus.hardware.performance V1
Change-Id: I5a56cdc826495e1770905e3286bcbc2bef0cf2a3
2025-09-04 10:16:09 +01:00
LineageOS Infra
826524b2cb Automatic translation import
Change-Id: I433a0975161c90f6e9cec98e824f56c3c80e39a1
2025-09-01 14:54:29 +00:00
Bruno Martins
8393454ee6 usb_compositions: Restore QCOM VID/PID combos for diag
This re-allows installing Qualcomm drivers for accessing diag,
serial_cdev, rmnet (and others) devices. Needed for QPST Flash Tool.

Change-Id: Iafe2236bb63adb005bfecae46887c58c69db8ca2
2025-09-01 14:03:27 +00:00
dianlujitao
0b09eeb4b7 KeyHandler: Populate tri-state-key state on boot
Change-Id: I11e785b5824d581f748e038f292c8846b2a13a0f
2025-09-01 14:50:41 +01:00
LuK1337
23a4f0c429 sepolicy: qti: Add system_oplus_radio_prop to *.ignore.cil
Change-Id: If943028a54f7a7f32f289bf080f6565052bdaf40
2025-08-31 20:00:33 +02:00
pjgowtham
0ad31fba1e sepolicy: qti: Let qti secure_element rw /dev/nq-nci
vendor.qti.secu: type=1400 audit(0.0:2346): avc:  denied  { getattr }
for  path=/dev/nq-nci dev=tmpfs ino=1371
scontext=u:r:hal_secure_element_default:s0
tcontext=u:object_r:nfc_device:s0 tclass=chr_file permissive=1

Spotted on ferrari.

Change-Id: I8869fffae3cc6028b6b8ff009bd84108e2a53ada
2025-08-25 13:59:35 +02:00
pjgowtham
9b27b2665b fingerprint: Shim property_get() as well
On OnePlus Nord CE3 (ziti), shimming `__system_property_get()` is not
enough. Without this change, `vendor.fingerprint.cali` is set to 0 when
`ro.boot.vbmeta.device_state` is unset.

Test: Ensure adb logcat | grep "lcd LockState" does not show up as NULL
      Ensure adb shell getprop vendor.fingerprint.cali is 1
Change-Id: I913f00db1542a28aaaa11dba93fcce67b39717bf
2025-08-25 09:49:43 +00:00
pjgowtham
1477e8b42e sepolicy: qti: Label awinic vibrator sysfs for ziti
Change-Id: I6543983b6de8f7852015ea6a304be9aa809dc65f
2025-08-24 21:23:41 +05:30
LuK1337
4af7f26d3f sepolicy: qti: oplusSensor -> oplus_sensor
Matches new AIDL naming style.

Change-Id: I93a22091f54df5c48d105bc82d51b90bcf1e59e3
2025-08-22 10:06:40 +02:00
pjgowtham
04441ff343 sepolicy: qti: Label and add rules for oplusSensor AIDL
Change-Id: I451d7bf6bb110ed900ff5258cdcf6566945ab490
2025-08-22 10:06:39 +02:00
pjgowtham
93e8cfc069 sepolicy: qti: Let vendor_hal_oplusSensor_default search /dev/block
Change-Id: I248bd96c9753a4c9f51643368a0a5f67d52729df
2025-08-22 09:58:37 +02:00
pjgowtham
17d525da8f sepolicy: qti: Let hal_oplus_charger_aidl rw /dev/oplus_chg
Change-Id: I222aed7542f5750a3fe2f062998237bc00d22a3a
2025-08-22 09:49:45 +02:00
pjgowtham
af977627d4 sepolicy: qti: Let hal_oplus_charger_aidl rw vendor_sysfs_battery_supply
Change-Id: I058aad89acba10eaae84734341d30d1efa8e4a2f
2025-08-22 09:49:45 +02:00
pjgowtham
00c112c97a sepolicy: qti: Update qseecom rules for fingerprint
Change-Id: I34cbd4642f1c03446d1e57da079e5e495c2326cc
2025-08-22 07:43:54 +00:00
pjgowtham
9914060348 sepolicy: qti: Label goodix fingerprint property
W /system/bin/init: type=1107 audit(0.0:13): uid=0 auid=4294967295
ses=4294967295 subj=u:r:init:s0 msg='avc:  denied  { set } for
property=gf.debug.dump_data pid=1873 uid=1000 gid=1000
scontext=u:r:hal_fingerprint_default:s0 tcontext=u:object_r:default_prop:s0
tclass=property_service permissive=0'

Change-Id: I07acc42f6a5cba7e7b94f8473feb0540eee9096c
2025-08-22 07:43:54 +00:00
pjgowtham
abe43816a2 sepolicy: qti: Let camera hal rw /proc/qcom_flash
On Ziti (OnePlus Nord CE 3), this seems necessary for the torchlight
function to work.

Change-Id: I37ac5d7a1578d939d61728e8292c47b2fa9d870d
2025-08-22 09:35:36 +02:00
pjgowtham
655f8c1814 sepolicy: qti: Label wly wakeup nodes
wly / # cat /sys/devices/platform/soc/984000.i2c/i2c-5/5-003b/name
p9415-rx
wly / # cat /sys/devices/platform/soc/990000.i2c/i2c-6/6-004b/name
synaptics-s3908
wly / # cat /sys/devices/platform/soc/a84000.i2c/i2c-8/8-0028/name
sn-nci

Change-Id: I8aef0c21df2af86b06515ef609729c352770a260
2025-08-22 09:28:01 +02:00
pjgowtham
8da66b3786 sepolicy: qti: Label ferrari wakeup nodes
ferrari / # cat /sys/devices/platform/soc/990000.i2c/i2c-5/5-004b/name
synaptics-s3908
ferrari / # cat /sys/devices/platform/soc/a84000.i2c/i2c-7/7-0028/name
sn-nci

Change-Id: Ia2af6499a912697694ee24f209726a974887545f
2025-08-22 09:26:25 +02:00
pjgowtham
19cd98ab96 sepolicy: qti: Label lunaa/ziti wakeup nodes
lunaa / # cat /sys/devices/platform/soc/a84000.i2c/i2c-1/1-0008/name
st21nfc
lunaa / # cat /sys/devices/platform/soc/a94000.i2c/i2c-2/2-0038/name
fts
ziti / # ls /sys/devices/platform/soc/a94000.spi/spi_master/spi1/spi1.0/
driver           fts_rw_reg  supplier:18200000.rsc:rpmh-regulator-ldoc12
driver_override  input       supplier:18200000.rsc:rpmh-regulator-ldoc3
fts_dump_reg     modalias    supplier:f000000.pinctrl
fts_esd_check    of_node     supplier:regulator.36
fts_fw_version   power       supplier:regulator.47
fts_hw_reset     statistics  uevent
fts_irq          subsystem   wakeup

Change-Id: I2933a1fb695f72cd859d6654947ac37bd7f3f77f
2025-08-21 17:22:41 +05:30
191 changed files with 9317 additions and 303 deletions

View 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,
}

View 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>

View 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>

View 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>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- App Name -->
<string name="app_name">DSP Volume Synchronizer</string>
</resources>

View File

@@ -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));
}
}

View File

@@ -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");
}
}
}

View File

@@ -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);
}
}

View File

@@ -4,6 +4,6 @@
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">{\"sim_illustration_lottie_mappings\":[{\"devices\":[\"OP591BL1\",\"OP5929L1\",\"OP594DL1\",\"OP595DL1\",\"OP5D0DL1\",\"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]},{\"devices\":[\"OP591BL1\",\"OP5929L1\",\"OP5D0DL1\"],\"esim-slot-ids\":[],\"psim-slot-ids\":[0,1]}]}</string>
</resources>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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)
}
}
}

View File

@@ -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());

View File

@@ -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;
};

View File

@@ -19,7 +19,8 @@ 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_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 +34,7 @@ ndk::ScopedAStatus AntiFlicker::setEnabled(bool enabled) {
return status;
}
unsigned int value = enabled;
if (isEnabled != enabled &&
if (isEnabled != enabled && 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);

View 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",
],
}

File diff suppressed because it is too large Load Diff

View 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

View 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
}

View File

@@ -0,0 +1,4 @@
service oplus.performance.hal.service /vendor/bin/hw/vendor.oplus.hardware.performance-service
class hal
user system
group system

View File

@@ -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
View File

@@ -0,0 +1 @@
../../../../build/soong/scripts/system-clang-format

57
aidl/sensors/Android.bp Normal file
View 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
View 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

View 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

View File

@@ -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

View 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
View 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
}

View File

@@ -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 {

View File

@@ -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
View 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
View 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
View File

@@ -0,0 +1,5 @@
# DolbyManager
PRODUCT_PACKAGES += \
OplusDolby
BOARD_VENDOR_SEPOLICY_DIRS += hardware/oplus/sepolicy/qti/dolby

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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>

View 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
View 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>

View 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>

View 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>

View 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()
}
}

View 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()
}
}

View 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
}
}
}

View 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)
}
}
}
}

View 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 }
}
}
}

View 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()
}
}

View 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)
}
}

View 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)
)
}
}
}
}

View 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
)

View File

@@ -0,0 +1,183 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.data
import android.content.Context
import android.content.SharedPreferences
import android.util.Log
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_PRESET
import co.aospa.dolby.oplus.DolbyConstants.Companion.dlog
import co.aospa.dolby.oplus.DolbyController
import co.aospa.dolby.oplus.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.withContext
class EqualizerRepository(
private val context: Context
) {
private val dolbyController by lazy { DolbyController.getInstance(context) }
// Preset is saved as a string of comma separated gains in SharedPreferences
// and is unique to each profile ID
private val profile = dolbyController.profile
private val profileSharedPrefs by lazy {
context.getSharedPreferences(
"profile_$profile",
Context.MODE_PRIVATE
)
}
private val presetsSharedPrefs by lazy {
context.getSharedPreferences(
"presets",
Context.MODE_PRIVATE
)
}
val builtInPresets: List<Preset> by lazy {
val names = context.resources.getStringArray(
R.array.dolby_preset_entries
)
val presets = context.resources.getStringArray(
R.array.dolby_preset_values
)
List(names.size) { index ->
Preset(
name = names[index],
bandGains = deserializeGains(presets[index]),
)
}
}
val defaultPreset by lazy { builtInPresets[0] } // Flat
// User defined presets are stored in a SharedPreferences as
// key - preset name
// value - comma separated string of gains
val userPresets: Flow<List<Preset>> = callbackFlow {
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, _ ->
dlog(TAG, "presetsSharedPrefs changed")
trySend(
presetsSharedPrefs.all.map { (key, value) ->
Preset(
name = key,
bandGains = deserializeGains(value.toString()),
isUserDefined = true
)
}
)
}
presetsSharedPrefs.registerOnSharedPreferenceChangeListener(listener)
dlog(TAG, "presetsSharedPrefs registered listener")
// trigger an initial emission
listener.onSharedPreferenceChanged(presetsSharedPrefs, null)
awaitClose {
presetsSharedPrefs.unregisterOnSharedPreferenceChangeListener(listener)
dlog(TAG, "presetsSharedPrefs unregistered listener")
}
}
suspend fun getBandGains(): List<BandGain> = withContext(Dispatchers.IO) {
val gains = profileSharedPrefs.getString(PREF_PRESET, dolbyController.getPreset())
return@withContext if (gains.isNullOrEmpty()) {
defaultPreset.bandGains
} else {
deserializeGains(gains)
}.also {
dlog(TAG, "getBandGains: $it")
}
}
suspend fun setBandGains(bandGains: List<BandGain>) = withContext(Dispatchers.IO) {
dlog(TAG, "setBandGains($bandGains)")
val gains = serializeGains(bandGains)
dolbyController.setPreset(gains)
profileSharedPrefs.edit()
.putString(PREF_PRESET, gains)
.apply()
}
suspend fun addPreset(preset: Preset) = withContext(Dispatchers.IO) {
dlog(TAG, "addPreset($preset)")
presetsSharedPrefs.edit()
.putString(preset.name, serializeGains(preset.bandGains))
.apply()
}
suspend fun removePreset(preset: Preset) = withContext(Dispatchers.IO) {
dlog(TAG, "removePreset($preset)")
presetsSharedPrefs.edit()
.remove(preset.name)
.apply()
}
private companion object {
const val TAG = "EqRepository"
val tenBandFreqs = intArrayOf(
32,
64,
125,
250,
500,
1000,
2000,
4000,
8000,
16000
)
fun deserializeGains(bandGains: String): List<BandGain> {
val gains: List<Int> =
bandGains.split(",").runCatching {
require(size == 20) {
"Preset must have 20 elements, has only $size!"
}
map { it.toInt() }
.twentyToTenBandGains()
}.onFailure { exception ->
Log.e(TAG, "Failed to parse preset", exception)
}.getOrDefault(
// fallback to flat
List<Int>(10) { 0 }
)
return List(10) { index ->
BandGain(
band = tenBandFreqs[index],
gain = gains[index]
)
}
}
fun serializeGains(bandGains: List<BandGain>): String {
return bandGains.map { it.gain }
.tenToTwentyBandGains()
.joinToString(",")
}
// we show only 10 bands in UI however backend requires 20 bands
fun List<Int>.tenToTwentyBandGains() =
List<Int>(20) { index ->
if (index % 2 == 1 && index < 19) {
// every odd element is the average of its surrounding elements
(this[(index - 1) / 2] + this[(index + 1) / 2]) / 2
} else {
this[index / 2]
}
}
fun List<Int>.twentyToTenBandGains() =
// skip every odd element
filterIndexed { index, _ -> index % 2 == 0 }
}
}

View File

@@ -0,0 +1,14 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.data
data class Preset(
var name: String,
val bandGains: List<BandGain>,
var isUserDefined: Boolean = false,
var isMutated: Boolean = false
)

View File

@@ -0,0 +1,101 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Slider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import co.aospa.dolby.oplus.geq.data.BandGain
@Composable
fun BandGainSlider(
bandGain: BandGain,
onValueChangeFinished: (Int) -> Unit
) {
// Gain range is of -1->1 in UI, -100->100 in backend, but actually is -10->10 dB.
// Ensure we update the slider when gain is changed,
// for eg. when changing the preset
var sliderPosition by remember(bandGain.gain) {
mutableFloatStateOf(bandGain.gain / 100f)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
SliderText(
"%.1f".format(sliderPosition * 10f)
)
Slider(
value = sliderPosition,
onValueChange = { sliderPosition = it },
onValueChangeFinished = {
onValueChangeFinished((sliderPosition * 100f).toInt())
},
valueRange = -1f..1f,
modifier = Modifier
.graphicsLayer {
rotationZ = 270f
transformOrigin = TransformOrigin(0f, 0f)
}
.layout { measurable, constraints ->
val placeable = measurable.measure(
Constraints(
minWidth = constraints.minHeight,
maxWidth = constraints.maxHeight,
minHeight = constraints.minWidth,
maxHeight = constraints.maxHeight,
)
)
layout(placeable.height, placeable.width) {
placeable.place(-placeable.width, 0)
}
}
// horizontal and vertical dimensions are inverted due to rotation
.width(200.dp)
.height(40.dp)
.padding(8.dp)
)
SliderText(
with(bandGain.band) {
if (this >= 1000) {
"${this / 1000}k"
} else {
"$this"
}
}
)
}
}
@Composable
fun SliderText(
text: String,
modifier: Modifier = Modifier
) {
Text(
text = text,
modifier = modifier,
fontSize = 12.sp
)
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import co.aospa.dolby.oplus.R
@Composable
fun BandGainSliderLabels() {
Column(
horizontalAlignment = Alignment.End,
modifier = Modifier.padding(end = 8.dp)
) {
LabelText(
stringResource(id = R.string.dolby_geq_slider_label_gain)
)
Column(
modifier = Modifier.height(200.dp),
horizontalAlignment = Alignment.End
) {
LabelText(
"+10 dB",
modifier = Modifier.padding(
top = 10.dp
)
)
Spacer(
modifier = Modifier.weight(1f)
)
LabelText("0 dB")
Spacer(
modifier = Modifier.weight(1f)
)
LabelText(
"-10 dB",
modifier = Modifier.padding(
bottom = 10.dp
)
)
}
LabelText("Hz")
}
}
@Composable
fun LabelText(
text: String,
modifier: Modifier = Modifier
) {
Text(
text = text,
modifier = modifier,
color = MaterialTheme.colorScheme.secondary,
fontSize = 12.sp
)
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.res.stringResource
@Composable
fun ConfirmationDialog(
text: String,
onConfirm: () -> Unit,
onDismiss: () -> Unit
) {
var showDialog by remember { mutableStateOf(true) }
if (!showDialog) {
onDismiss()
return
}
AlertDialog(
onDismissRequest = { showDialog = false },
confirmButton = {
TextButton(
onClick = {
showDialog = false
onConfirm()
}
) {
Text(
stringResource(id = android.R.string.ok)
)
}
},
dismissButton = {
TextButton(
onClick = { showDialog = false }
) {
Text(
stringResource(id = android.R.string.cancel)
)
}
},
text = {
Text(text)
}
)
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@Composable
fun EqualizerBands(viewModel: EqualizerViewModel) {
val preset by viewModel.preset.collectAsState()
val bandGains = preset.bandGains
LazyRow(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
item {
BandGainSliderLabels()
}
items(bandGains.size) { index ->
BandGainSlider(
bandGains[index],
onValueChangeFinished = {
viewModel.setGain(index, it)
}
)
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.theme.settingsBackground
import com.android.settingslib.spa.framework.theme.SettingsDimension
@Composable
fun EqualizerScreen(
viewModel: EqualizerViewModel,
modifier: Modifier = Modifier
) {
Surface(
modifier = Modifier
.fillMaxSize()
.padding(SettingsDimension.itemPadding)
.then(modifier),
color = MaterialTheme.colorScheme.settingsBackground
) {
Column(
verticalArrangement = Arrangement.Top,
modifier = Modifier.fillMaxHeight()
) {
PresetSelector(viewModel = viewModel)
EqualizerBands(viewModel = viewModel)
}
}
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import co.aospa.dolby.oplus.geq.data.EqualizerRepository
import co.aospa.dolby.oplus.geq.data.Preset
import co.aospa.dolby.oplus.DolbyConstants.Companion.dlog
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
const val TAG = "EqViewModel"
class EqualizerViewModel(
private val repository: EqualizerRepository
) : ViewModel() {
private val _presets = MutableStateFlow(repository.builtInPresets)
val presets = _presets.asStateFlow()
private val _preset = MutableStateFlow(repository.defaultPreset)
val preset = _preset.asStateFlow()
private var presetRestored = false
init {
// Update the list of presets: combined list of user defined presets if any,
// and then the built in presets.
repository.userPresets
.onEach { presets ->
dlog(TAG, "updated userPresets: $presets")
_presets.value = mutableListOf<Preset>().apply {
addAll(presets)
addAll(repository.builtInPresets)
}.toList()
// We can restore the active preset only after the presets list is populated,
// since we do not save the preset name but only its gains.
if (!presetRestored) {
val bandGains = repository.getBandGains()
_preset.value = _presets.value.find {
bandGains == it.bandGains
} ?: Preset(
name = "Custom",
bandGains = bandGains
)
dlog(TAG, "restored preset: ${_preset.value}")
presetRestored = true
}
}
.launchIn(viewModelScope)
// Update the preset in repository everytime we set it here
_preset
.drop(1) // skip the initial value
.onEach {
// wait till the active preset is restored
if (!presetRestored) {
return@onEach
}
dlog(TAG, "updated preset: $it")
repository.setBandGains(it.bandGains)
if (it.isUserDefined) {
repository.addPreset(it)
}
}
.launchIn(viewModelScope)
}
fun reset() {
dlog(TAG, "reset()")
if (_preset.value.isUserDefined) {
// Reset gains to 0
_preset.value = _preset.value.copy(
bandGains = repository.defaultPreset.bandGains
)
} else {
// Switch to flat preset
_preset.value = repository.defaultPreset
}
}
fun setPreset(preset: Preset) {
dlog(TAG, "setPreset($preset)")
_preset.value = preset
}
fun setGain(index: Int, gain: Int) {
dlog(TAG, "setGain($index, $gain)")
_preset.value = _preset.value.run {
copy(
name = if (!isUserDefined) "Custom" else name,
bandGains = bandGains
.toMutableList()
// create a new object to ensure the flow emits an update.
.apply { this[index] = this[index].copy(gain = gain) }
.toList(),
isMutated = true
)
}
}
// Returns string containing the error message if it failed, otherwise null
private fun validatePresetName(name: String): PresetNameValidationError? {
// Ensure we don't have another preset with the same name
return if (
_presets.value
.any { it.name.equals(name.trim(), ignoreCase = true) }
) {
PresetNameValidationError.NAME_EXISTS
} else if (name.length > 50) {
PresetNameValidationError.NAME_TOO_LONG
} else null
}
fun createNewPreset(name: String): PresetNameValidationError? {
dlog(TAG, "createNewPreset($name)")
validatePresetName(name)?.let {
dlog(TAG, "createNewPreset failed: $it")
return it
}
_preset.value = _preset.value.copy(
name = name.trim(),
isUserDefined = true,
isMutated = false
)
return null
}
fun renamePreset(preset: Preset, name: String): PresetNameValidationError? {
dlog(TAG, "renamePreset($preset, $name)")
// create a preset with the new name and same gains
createNewPreset(name = name)?.let {
dlog(TAG, "renamePreset failed")
return it
}
// and delete the old one.
deletePreset(preset, shouldReset = false)
return null
}
fun deletePreset(preset: Preset, shouldReset: Boolean = true) {
dlog(TAG, "deletePreset($preset)")
viewModelScope.launch {
repository.removePreset(preset)
}
if (shouldReset) {
_preset.value = repository.defaultPreset
}
}
companion object {
val Factory = viewModelFactory {
initializer {
EqualizerViewModel(
repository = EqualizerRepository(
this[ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY]!!
)
)
}
}
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import co.aospa.dolby.oplus.R
@Composable
fun PresetNameDialog(
title: String,
presetName: String = "",
onPresetNameSet: (String) -> PresetNameValidationError?,
onDismissDialog: () -> Unit
) {
var showDialog by remember { mutableStateOf(true) }
if (!showDialog) {
onDismissDialog()
return
}
var text by remember { mutableStateOf(presetName) }
var error by remember { mutableStateOf<PresetNameValidationError?>(null) }
AlertDialog(
onDismissRequest = { showDialog = false },
confirmButton = {
TextButton(
onClick = {
onPresetNameSet(text)?.let {
// validation failed
error = it
return@TextButton
}
// succeeded
showDialog = false
error = null
}
) {
Text(
stringResource(id = android.R.string.ok)
)
}
},
dismissButton = {
TextButton(
onClick = { showDialog = false }
) {
Text(
stringResource(id = android.R.string.cancel)
)
}
},
title = { Text(title) },
text = {
Column {
OutlinedTextField(
value = text,
onValueChange = { text = it },
label = {
Text(
stringResource(id = R.string.dolby_geq_preset_name)
)
},
isError = error != null,
singleLine = true
)
error?.let {
Text(
text = it.toErrorMessage(),
color = MaterialTheme.colorScheme.error,
modifier = Modifier.padding(top = 8.dp)
)
}
}
}
)
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import co.aospa.dolby.oplus.R
enum class PresetNameValidationError {
NAME_EXISTS,
NAME_TOO_LONG;
@Composable
fun toErrorMessage() =
stringResource(
id = when (this) {
NAME_EXISTS -> R.string.dolby_geq_preset_name_exists
NAME_TOO_LONG -> R.string.dolby_geq_preset_name_too_long
}
)
}

View File

@@ -0,0 +1,176 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import co.aospa.dolby.oplus.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PresetSelector(viewModel: EqualizerViewModel) {
val presets by viewModel.presets.collectAsState()
val currentPreset by viewModel.preset.collectAsState()
var expanded by remember { mutableStateOf(false) }
var showNewPresetDialog by remember { mutableStateOf(false) }
var showRenamePresetDialog by remember { mutableStateOf(false) }
var showDeleteConfirmDialog by remember { mutableStateOf(false) }
var showResetConfirmDialog by remember { mutableStateOf(false) }
Row(
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 24.dp),
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
) {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded },
modifier = Modifier
.padding(end = 8.dp)
.weight(1f)
) {
TextField(
value = currentPreset.name,
onValueChange = { },
readOnly = true,
label = {
Text(
stringResource(id = R.string.dolby_geq_preset)
)
},
singleLine = true,
trailingIcon = {
ExposedDropdownMenuDefaults.TrailingIcon(
expanded = expanded
)
},
colors = ExposedDropdownMenuDefaults.textFieldColors(),
modifier = Modifier.menuAnchor()
// prevent keyboard from popping up
.focusProperties { canFocus = false }
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
presets.forEach { preset ->
DropdownMenuItem(
text = { Text(text = preset.name) },
onClick = {
viewModel.setPreset(preset)
expanded = false
}
)
}
}
}
TooltipIconButton(
icon = ImageVector.vectorResource(
id = R.drawable.save_as_24px
),
text = stringResource(id = R.string.dolby_geq_new_preset),
onClick = { showNewPresetDialog = true }
)
if (currentPreset.isUserDefined) {
TooltipIconButton(
icon = Icons.Default.Edit,
text = stringResource(id = R.string.dolby_geq_rename_preset),
onClick = { showRenamePresetDialog = true }
)
TooltipIconButton(
icon = Icons.Default.Delete,
text = stringResource(id = R.string.dolby_geq_delete_preset),
onClick = { showDeleteConfirmDialog = true }
)
}
TooltipIconButton(
icon = ImageVector.vectorResource(
id = R.drawable.reset_settings_24px
),
text = stringResource(id = R.string.dolby_geq_reset_gains),
onClick = {
if (currentPreset.isUserDefined) {
showResetConfirmDialog = true
} else {
viewModel.reset()
}
}
)
}
// Dialogs
if (showNewPresetDialog) {
PresetNameDialog(
title = stringResource(id = R.string.dolby_geq_new_preset),
onPresetNameSet = {
return@PresetNameDialog viewModel.createNewPreset(name = it)
},
onDismissDialog = { showNewPresetDialog = false }
)
}
if (showRenamePresetDialog) {
PresetNameDialog(
title = stringResource(id = R.string.dolby_geq_rename_preset),
presetName = currentPreset.name,
onPresetNameSet = {
return@PresetNameDialog viewModel.renamePreset(
preset = currentPreset,
name = it
)
},
onDismissDialog = { showRenamePresetDialog = false }
)
}
if (showDeleteConfirmDialog) {
ConfirmationDialog(
text = stringResource(id = R.string.dolby_geq_delete_preset_prompt),
onConfirm = { viewModel.deletePreset(currentPreset) },
onDismiss = { showDeleteConfirmDialog = false }
)
}
if (showResetConfirmDialog) {
ConfirmationDialog(
text = stringResource(id = R.string.dolby_geq_reset_gains_prompt),
onConfirm = { viewModel.reset() },
onDismiss = { showResetConfirmDialog = false }
)
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.geq.ui
import androidx.compose.foundation.layout.size
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.material3.TooltipBox
import androidx.compose.material3.TooltipDefaults
import androidx.compose.material3.rememberTooltipState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.unit.dp
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TooltipIconButton(
icon: ImageVector,
text: String,
onClick: () -> Unit
) {
TooltipBox(
positionProvider = TooltipDefaults.rememberTooltipPositionProvider(),
tooltip = {
Text(text)
},
state = rememberTooltipState()
) {
IconButton(
onClick = onClick
) {
Icon(
imageVector = icon,
contentDescription = text,
modifier = Modifier.size(24.dp)
)
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.preference
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.widget.ImageView
import androidx.appcompat.content.res.AppCompatResources
import androidx.preference.ListPreference
import androidx.preference.PreferenceViewHolder
import co.aospa.dolby.oplus.R
// Preference with icon on the right side
class DolbyIeqPreference(
context: Context,
attrs: AttributeSet?,
) : ListPreference(context, attrs) {
init {
widgetLayoutResource = R.layout.ieq_icon_layout
}
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
val iconView = holder.findViewById(R.id.ieq_icon)!! as ImageView
val icon = AppCompatResources.getDrawable(context, getIeqIconResId())
iconView.setImageDrawable(icon)
}
private fun getIeqIconResId(): Int {
val ieqValue = value?.toIntOrNull() ?: 0
return when (ieqValue) {
0 -> R.drawable.ic_ieq_off
1 -> R.drawable.ic_ieq_balanced
2 -> R.drawable.ic_ieq_warm
3 -> R.drawable.ic_ieq_detailed
else -> 0 // should never hit this!
}
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.preference
import android.content.Context
import android.content.SharedPreferences
import androidx.preference.PreferenceDataStore
import androidx.preference.PreferenceManager
import co.aospa.dolby.oplus.DolbyConstants
class DolbyPreferenceStore(
private val context: Context
) : PreferenceDataStore() {
private val defaultSharedPrefs by lazy {
PreferenceManager.getDefaultSharedPreferences(context)
}
private lateinit var profileSharedPrefs: SharedPreferences
var profile = 0
set(value) {
field = value
profileSharedPrefs = context.getSharedPreferences(
"profile_$value",
Context.MODE_PRIVATE
)
}
private fun getSharedPreferences(key: String) =
if (DolbyConstants.PROFILE_SPECIFIC_PREFS.contains(key)) {
profileSharedPrefs
} else {
defaultSharedPrefs
}
override fun putBoolean(key: String, value: Boolean) =
getSharedPreferences(key).edit()
.putBoolean(key, value)
.apply()
override fun getBoolean(key: String, defValue: Boolean) =
getSharedPreferences(key).getBoolean(key, defValue)
override fun putInt(key: String, value: Int) =
getSharedPreferences(key).edit()
.putInt(key, value)
.apply()
override fun getInt(key: String, defValue: Int) =
getSharedPreferences(key).getInt(key, defValue)
override fun putString(key: String, value: String?) =
getSharedPreferences(key).edit()
.putString(key, value)
.apply()
override fun getString(key: String, defValue: String?) =
getSharedPreferences(key).getString(key, defValue)
}

View File

@@ -0,0 +1,299 @@
/*
* Copyright (C) 2023-24 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
package co.aospa.dolby.oplus.preference
import android.media.AudioAttributes
import android.media.AudioDeviceCallback
import android.media.AudioDeviceInfo
import android.media.AudioManager
import android.os.Bundle
import android.os.Handler
import android.widget.CompoundButton
import android.widget.CompoundButton.OnCheckedChangeListener
import android.widget.Toast
import androidx.preference.ListPreference
import androidx.preference.Preference
import androidx.preference.Preference.OnPreferenceChangeListener
import androidx.preference.PreferenceFragment
import androidx.preference.SwitchPreferenceCompat
import co.aospa.dolby.oplus.DolbyConstants
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_BASS
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_DIALOGUE
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_ENABLE
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_HP_VIRTUALIZER
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_IEQ
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_PRESET
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_PROFILE
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_RESET
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_SPK_VIRTUALIZER
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_STEREO
import co.aospa.dolby.oplus.DolbyConstants.Companion.PREF_VOLUME
import co.aospa.dolby.oplus.DolbyConstants.Companion.dlog
import co.aospa.dolby.oplus.DolbyController
import co.aospa.dolby.oplus.R
import com.android.settingslib.widget.MainSwitchPreference
class DolbySettingsFragment : PreferenceFragment(),
OnPreferenceChangeListener, CompoundButton.OnCheckedChangeListener {
private val switchBar by lazy {
findPreference<MainSwitchPreference>(PREF_ENABLE)!!
}
private val profilePref by lazy {
findPreference<ListPreference>(PREF_PROFILE)!!
}
private val presetPref by lazy {
findPreference<Preference>(PREF_PRESET)!!
}
private val ieqPref by lazy {
findPreference<DolbyIeqPreference>(PREF_IEQ)!!
}
private val stereoPref by lazy {
findPreference<ListPreference>(PREF_STEREO)!!
}
private val dialoguePref by lazy {
findPreference<ListPreference>(PREF_DIALOGUE)!!
}
private val bassPref by lazy {
findPreference<SwitchPreferenceCompat>(PREF_BASS)!!
}
private val hpVirtPref by lazy {
findPreference<SwitchPreferenceCompat>(PREF_HP_VIRTUALIZER)!!
}
private val spkVirtPref by lazy {
findPreference<SwitchPreferenceCompat>(PREF_SPK_VIRTUALIZER)!!
}
private val volumePref by lazy {
findPreference<SwitchPreferenceCompat>(PREF_VOLUME)!!
}
private val resetPref by lazy {
findPreference<Preference>(PREF_RESET)!!
}
private val dolbyController by lazy { DolbyController.getInstance(context) }
private val audioManager by lazy { context.getSystemService(AudioManager::class.java) }
private val handler = Handler()
private var isOnSpeaker = true
set(value) {
if (field == value) return
field = value
dlog(TAG, "setIsOnSpeaker($value)")
updateProfileSpecificPrefs()
}
private val audioDeviceCallback = object : AudioDeviceCallback() {
override fun onAudioDevicesAdded(addedDevices: Array<AudioDeviceInfo>) {
dlog(TAG, "onAudioDevicesAdded")
updateSpeakerState()
}
override fun onAudioDevicesRemoved(removedDevices: Array<AudioDeviceInfo>) {
dlog(TAG, "onAudioDevicesRemoved")
updateSpeakerState()
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
dlog(TAG, "onCreatePreferences")
addPreferencesFromResource(R.xml.dolby_settings)
val profile = dolbyController.profile
preferenceManager.preferenceDataStore = DolbyPreferenceStore(context).also {
it.profile = profile
}
val dsOn = dolbyController.dsOn
switchBar.addOnSwitchChangeListener(this)
switchBar.setChecked(dsOn)
profilePref.onPreferenceChangeListener = this
profilePref.setEnabled(dsOn)
profilePref.apply {
if (entryValues.contains(profile.toString())) {
summary = "%s"
value = profile.toString()
} else {
summary = context.getString(R.string.dolby_unknown)
}
}
hpVirtPref.onPreferenceChangeListener = this
spkVirtPref.onPreferenceChangeListener = this
stereoPref.onPreferenceChangeListener = this
dialoguePref.onPreferenceChangeListener = this
bassPref.onPreferenceChangeListener = this
volumePref.onPreferenceChangeListener = this
ieqPref.onPreferenceChangeListener = this
resetPref.setOnPreferenceClickListener {
dolbyController.resetProfileSpecificSettings()
updateProfileSpecificPrefs()
Toast.makeText(
context,
context.getString(R.string.dolby_reset_profile_toast, profilePref.summary),
Toast.LENGTH_SHORT
).show()
true
}
audioManager!!.registerAudioDeviceCallback(audioDeviceCallback, handler)
updateSpeakerState()
updateProfileSpecificPrefs()
}
override fun onDestroyView() {
dlog(TAG, "onDestroyView")
audioManager!!.unregisterAudioDeviceCallback(audioDeviceCallback)
super.onDestroyView()
}
override fun onResume() {
super.onResume()
updateProfileSpecificPrefs()
}
override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
dlog(TAG, "onPreferenceChange: key=${preference.key} value=$newValue")
when (preference.key) {
PREF_PROFILE -> {
val profile = newValue.toString().toInt()
dolbyController.profile = profile
(preferenceManager.preferenceDataStore as DolbyPreferenceStore).profile = profile
updateProfileSpecificPrefs()
}
PREF_SPK_VIRTUALIZER -> {
dolbyController.setSpeakerVirtEnabled(newValue as Boolean)
}
PREF_HP_VIRTUALIZER -> {
dolbyController.setHeadphoneVirtEnabled(newValue as Boolean)
}
PREF_STEREO -> {
dolbyController.setStereoWideningAmount(newValue.toString().toInt())
}
PREF_DIALOGUE -> {
dolbyController.setDialogueEnhancerAmount(newValue.toString().toInt())
}
PREF_BASS -> {
dolbyController.setBassEnhancerEnabled(newValue as Boolean)
}
PREF_VOLUME -> {
dolbyController.setVolumeLevelerEnabled(newValue as Boolean)
}
PREF_IEQ -> {
dolbyController.setIeqPreset(newValue.toString().toInt())
}
else -> return false
}
return true
}
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
dlog(TAG, "onCheckedChanged($isChecked)")
dolbyController.dsOn = isChecked
profilePref.setEnabled(isChecked)
updateProfileSpecificPrefs()
}
private fun updateSpeakerState() {
val device = audioManager!!.getDevicesForAttributes(ATTRIBUTES_MEDIA)[0]
isOnSpeaker = (device.type == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER)
}
private fun updateProfileSpecificPrefs() {
val unknownRes = context.getString(R.string.dolby_unknown)
val headphoneRes = context.getString(R.string.dolby_connect_headphones)
val dsOn = dolbyController.dsOn
val currentProfile = dolbyController.profile
dlog(
TAG, "updateProfileSpecificPrefs: dsOn=$dsOn currentProfile=$currentProfile"
+ " isOnSpeaker=$isOnSpeaker"
)
val enable = dsOn && (currentProfile != -1)
presetPref.setEnabled(enable)
spkVirtPref.setEnabled(enable)
ieqPref.setEnabled(enable)
dialoguePref.setEnabled(enable)
volumePref.setEnabled(enable)
resetPref.setEnabled(enable)
hpVirtPref.setEnabled(enable && !isOnSpeaker)
stereoPref.setEnabled(enable && !isOnSpeaker)
bassPref.setEnabled(enable && !isOnSpeaker)
if (!enable) return
presetPref.summary = dolbyController.getPresetName()
val ieqValue = dolbyController.getIeqPreset(currentProfile)
ieqPref.apply {
if (entryValues.contains(ieqValue.toString())) {
summary = "%s"
value = ieqValue.toString()
} else {
summary = unknownRes
}
}
val deValue = dolbyController.getDialogueEnhancerAmount(currentProfile).toString()
dialoguePref.apply {
if (entryValues.contains(deValue)) {
summary = "%s"
value = deValue
} else {
summary = unknownRes
}
}
spkVirtPref.setChecked(dolbyController.getSpeakerVirtEnabled(currentProfile))
volumePref.setChecked(dolbyController.getVolumeLevelerEnabled(currentProfile))
// below prefs are not enabled on loudspeaker
if (isOnSpeaker) {
stereoPref.summary = headphoneRes
bassPref.summary = headphoneRes
hpVirtPref.summary = headphoneRes
return
}
val swValue = dolbyController.getStereoWideningAmount(currentProfile).toString()
stereoPref.apply {
if (entryValues.contains(swValue)) {
summary = "%s"
value = swValue
} else {
summary = unknownRes
}
}
bassPref.apply {
setChecked(dolbyController.getBassEnhancerEnabled(currentProfile))
summary = null
}
hpVirtPref.apply {
setChecked(dolbyController.getHeadphoneVirtEnabled(currentProfile))
summary = null
}
}
companion object {
private const val TAG = "DolbySettingsFragment"
private val ATTRIBUTES_MEDIA = AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_MEDIA)
.build()
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 The LineageOS Project
* Copyright (C) 2022-2024 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.
@@ -37,3 +37,20 @@ extern "C" int __system_property_get(const char* __name, char* __value) {
return __system_property_get_orig(__name, __value);
}
extern "C" int property_get(const char* key, char* value, const char* default_value) {
static auto property_get_orig =
reinterpret_cast<typeof(property_get)*>(dlsym(RTLD_NEXT, "property_get"));
if (strcmp(key, "ro.boot.vbmeta.device_state") == 0) {
ALOGV("Returning unlocked for ro.boot.vbmeta.device_state");
return strlen(strcpy(value, "unlocked"));
}
if (strcmp(key, "ro.boot.verifiedbootstate") == 0) {
ALOGV("Returning orange for ro.boot.verifiedbootstate");
return strlen(strcpy(value, "orange"));
}
return property_get_orig(key, value, default_value);
}

View File

@@ -5,6 +5,7 @@ hidl_package_root {
aidl_interface {
name: "vendor.oplus.hardware.biometrics.fingerprintpay",
system_ext_specific: true,
odm_available: true,
local_include_dir: "aidl",
srcs: ["aidl/vendor/oplus/hardware/biometrics/fingerprintpay/*.aidl"],
@@ -27,8 +28,58 @@ aidl_interface {
],
}
aidl_interface {
name: "vendor.oplus.hardware.charger",
system_ext_specific: true,
odm_available: true,
local_include_dir: "aidl",
srcs: ["aidl/vendor/oplus/hardware/charger/*.aidl"],
stability: "vintf",
owner: "oplus",
backend: {
cpp: {
enabled: true,
},
java: {
sdk_version: "module_current",
},
},
versions_with_info: [
{
version: "1",
imports: [],
},
{
version: "2",
imports: [],
},
{
version: "3",
imports: [],
},
{
version: "5",
imports: [],
},
{
version: "6",
imports: [],
},
{
version: "7",
imports: [],
},
{
version: "8",
imports: [],
},
],
}
aidl_interface {
name: "vendor.oplus.hardware.commondcs",
system_ext_specific: true,
vendor_available: true,
local_include_dir: "aidl",
srcs: ["aidl/vendor/oplus/hardware/commondcs/*.aidl"],
@@ -53,6 +104,7 @@ aidl_interface {
aidl_interface {
name: "vendor.oplus.hardware.esim",
system_ext_specific: true,
odm_available: true,
local_include_dir: "aidl",
srcs: ["aidl/vendor/oplus/hardware/esim/*.aidl"],
@@ -77,6 +129,7 @@ aidl_interface {
aidl_interface {
name: "vendor.oplus.hardware.osense.client",
system_ext_specific: true,
vendor_available: true,
local_include_dir: "aidl",
srcs: ["aidl/vendor/oplus/hardware/osense/client/*.aidl"],
@@ -99,8 +152,34 @@ aidl_interface {
],
}
aidl_interface {
name: "vendor.oplus.hardware.performance",
system_ext_specific: true,
vendor_available: true,
local_include_dir: "aidl",
srcs: ["aidl/vendor/oplus/hardware/performance/*.aidl"],
stability: "vintf",
owner: "oplus",
backend: {
cpp: {
enabled: true,
},
java: {
sdk_version: "module_current",
},
},
versions_with_info: [
{
version: "1",
imports: [],
},
],
}
aidl_interface {
name: "vendor.oplus.hardware.radio",
system_ext_specific: true,
vendor_available: true,
local_include_dir: "aidl",
srcs: ["aidl/vendor/oplus/hardware/radio/*.aidl"],
@@ -129,6 +208,7 @@ aidl_interface {
aidl_interface {
name: "vendor.oplus.hardware.touch",
system_ext_specific: true,
vendor_available: true,
local_include_dir: "aidl",
srcs: ["aidl/vendor/oplus/hardware/touch/*.aidl"],

View File

@@ -0,0 +1,40 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.charger;
@VintfStability
@Backing(type="int")
enum ChgFuncFlag {
GET_UI_CHG_ICON_TYPE = 0,
GET_UI_POWER_VALUE = 1,
GET_DEVICE_POWER_VALUE = 2,
GET_ADAPTER_POWER_VALUE = 3,
GET_CPA_POWER_VALUE = 4,
SET_CHG_UP_LIMIT_VALUE = 5,
IS_SUPPORT_SINGLE_HYPER_SPEED = 6,
GET_BATT_EXPANSION_STATE = 7,
IS_SUPPORT_ECO_DESIGN = 8,
GET_BATT_MANU_DATE = 9,
GET_BATT_FIRST_USAGE_DATE = 10,
SET_BATT_FIRST_USAGE_DATE = 11,
CLEAR_BATT_ECO_DATA = 12,
SET_RECHG_SOC_EN = 13,
SET_CHG_UP_LIMIT_STATE = 14,
GET_BATTERY_STATUS_PM_VPH = 15,
GET_BATTERY_STATUS_PM_VBAT = 16,
GET_DEEP_DISCHG_COUNTS_VALUE = 17,
GET_ANTI_EXPANSION_INFO = 18,
SET_ANTI_EXPANSION_INFO = 19,
GET_BATT_UI_CYCLE_COUNT = 20,
GET_BATTERY_TYPE = 21,
WIRELESS_PENCIL_QCALI = 22,
GET_BATTERY_GAUGE_TYPE = 23,
GET_CHG_BYPASS_STATUS = 24,
SET_CHG_BYPASS = 25,
GET_RX_DISABLE_STATUS = 26,
SET_RX_DISABLE = 27,
GET_BATTERY_SEC_IC_TEST_STATUS = 28,
}

View File

@@ -0,0 +1,143 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.charger;
import vendor.oplus.hardware.charger.ChgFuncFlag;
import vendor.oplus.hardware.charger.testKitFeatureTestResult;
@VintfStability
interface ICharger {
int VolDividerIcWorkModeSet(String data);
int chgExchangeMesgInit();
int chgExchangeSohMesgInit();
int getAcType();
int getBattAuthenticate();
int getBattPPSChgIng();
int getBattPPSChgPower();
String getBattParamNoplug();
int getBattShortIcOtpStatus();
int getBattSubCurrent();
int getBattVoocChgIng();
int getBatteryVoltageNow();
String getBccCsvData();
int getBccExpStatus();
String getBmsHeatingRunningStatus();
int getBmsHeatingStatus();
String getChargerControl();
int getChargerCoolDown();
int getChargerCriticalLog();
int getChargerIdVolt();
int getChargerLog();
int getCustomSelectChgMode();
String getDevinfoFastchg();
int getFastCharge();
int getParallelChgMosTestResult();
int getPsyAcOnline();
int getPsyBatteryCC();
int getPsyBatteryCurrentNow();
int getPsyBatteryFcc();
int getPsyBatteryHmac();
int getPsyBatteryLevel();
int getPsyBatteryNotify();
int getPsyBatteryPchg();
int getPsyBatteryPchgResetCount();
int getPsyBatteryRm();
int getPsyBatteryShortFeature();
int getPsyBatteryShortStatus();
String getPsyBatteryStatus();
int getPsyBatteryTemp();
int getPsyChargeTech();
int getPsyFastChgType();
int getPsyInputCurrent();
int getPsyOtgOnline();
int getPsyOtgSwitch();
int getPsyPcPortOnline();
int getPsyQGVbatDeviation();
int getPsyTypeOrientation();
int getPsyUsbOnline();
int getPsyUsbStatus();
String getPsyWirelessRX();
String getPsyWirelessRxVersion();
String getPsyWirelessTX();
String getPsyWirelessTxVersion();
int getQgVbatDeviation();
String getQuickModeGain();
String getReserveSocDebug();
int getSmartChgMode();
int getUIsohValue();
String getUisohDebugParameterInfo();
int getUsbInputCurrentNow();
int getUsbPrimalType();
int getWiredOtgOnline();
int getWirelessAdapterPower();
int getWirelessCapacity();
int getWirelessChargePumpEn();
int getWirelessCurrentNow();
String getWirelessDeviated();
int getWirelessOnline();
int getWirelessPenPresent();
int getWirelessPtmcId();
int getWirelessRXEnable();
int getWirelessRealType();
String getWirelessTXEnable();
int getWirelessUserSleepMode();
int getWirelessVoltageNow();
String healthd_update_ui_soc_decimal();
int nightstandby(int status);
int notifyScreenStatus(int status);
String queryChargeInfo();
int setChargeEMMode(String data);
int setChargerControl(String data);
int setChargerCoolDown(String data);
int setChargerCriticalLog(String data);
int setChargerCycle(String data);
int setChargerFactoryModeTest(String data);
int setChargerLog(String data);
int setChgStatusToBcc(int status);
int setCustomSelectChgMode(int mode, boolean enable);
int setFastchgFwUpdate(String data);
int setPsyMmiChgEn(String data);
int setPsyOtgSwitch(String data);
int setReserveSocDebug(String data);
int setShipMode(String data);
int setSmartChgMode(String data);
int setSmartCoolDown(int coolDown, int normalCoolDown, String pkgName);
int setTbattPwrOff(String data);
int setUisohDebugInfo(String data);
int setUsbPrimalType(String data);
int setWirelessChargePumpEn(String data);
int setWirelessFtmMode(String data);
int setWirelessIconDelay(String data);
int setWirelessIdtAdcTest(String data);
int setWirelessPenSoc(String data);
int setWirelessRXEnable(String data);
int setWirelessTXEnable(String data);
int setWirelessUserSleepMode(String data);
int setWlsThirdPartitionInfo(String data);
testKitFeatureTestResult testKitFeatureTest(int index);
String testKitGetFeatureList();
String testKitGetFeatureName(int index);
int testKitGetFeatureNum();
int updateUiSohToPartion();
String queryWlsPencilInfo();
String getChgOlcConfig();
int setChgOlcConfig(String data);
int setSuperEnduranceStatus(String data);
int setSuperEnduranceCount(String data);
int setBobStatus(String data);
int setPsySlowChgEn(String data);
int getCpVbatDeviation();
int setBatteryLogPush(String data);
int getChargingModeInGsmCall();
int setChargingModeInGsmCall(String data);
int setChgRusConfig(String data);
String getPsyBatterySN();
String getBattGaugeInfo();
int setChgConfig(ChgFuncFlag flag, String extra, int callname);
String getChgConfig(ChgFuncFlag flag, String extra, int callname);
int setUsbEyeDiagram(int model, String eyeDiagram, boolean isDefaultEyeDiagram);
String getUsbCurrentEyeDiagram(int model);
}

View File

@@ -0,0 +1,12 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.charger;
@VintfStability
parcelable testKitFeatureTestResult {
int ret;
String str;
}

View File

@@ -0,0 +1,187 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
import vendor.oplus.hardware.performance.OsvelteVersionRet;
import vendor.oplus.hardware.performance.ProcMemStatRet;
import vendor.oplus.hardware.performance.ProcReqHal;
import vendor.oplus.hardware.performance.TaskWakeInfo;
@VintfStability
interface IPerformance {
int addAcmDirName(in String dirname, long flag);
int addAcmNomediaDirName(in String dirname);
int addAcmPkgName(in String pkgname, long flag);
int addTaskTrackPid(int group, int pid, boolean clear);
void clearTaskTrackGroup(int group);
int delAcmDirName(in String dirname);
int delAcmNomediaDirName(in String dirname);
int delAcmPkgName(in String pkgname);
int disableDamonReclaim();
int disableKmallocDebug();
int disableMultiThreadOptimize();
int disableProcessReclaim();
int disableTaskCpustats();
int disableTaskPlacementDecision();
int disableVmallocDebug();
int enableAudioPerf(in String value);
int enableDamonReclaim();
int enableKmallocDebug();
int enableMultiThreadOptimize();
int enableProcessReclaim();
int enableTaskCpustats();
int enableTaskPlacementDecision();
int enableVmallocDebug();
int existMemMonitor();
long getAcmDirFlag(in String dirname);
int getAcmOpstat();
long getAcmPkgFlag(in String pkgname);
String getClmMuxSwitch();
String getClmThreshold(int threshold_id);
String getDdrResidency();
String getDevinfoDDRInfo();
String getDevinfoUfsInfo();
String getDevinfoUfsVersionInfo();
String getExt4FragScore(in String devpath);
String getExt4FreefragInfo(in String devpath);
String getF2fsMovedBlks();
ProcReqHal getHIAllocWait();
String getHICpuInfo();
String getHICpuLoading();
ProcReqHal getHIDState();
ProcReqHal getHIEmcdrvIowait();
ProcReqHal getHIFsyncWait();
ProcReqHal getHIIonWait();
ProcReqHal getHIIowait();
ProcReqHal getHIIowaitHung();
ProcReqHal getHIKswapdLoading();
ProcReqHal getHISchedLatency();
ProcReqHal getHIScmCall();
ProcReqHal getHIUfsFeature();
int getKernelVersion();
String getKmallocDebug();
String getKmallocOrigin();
String getKmallocUsed();
String getMemMonitor();
int getOswapVersion();
String getUfsSignalRecordUpload();
int getUfsplusHpbStatus();
int getUfsplusTwStatus();
String getVmallocDebug();
String getVmallocHashCal();
String getVmallocUsed();
TaskWakeInfo getWakeThreadsAffinityOrdered(in String handle, int size);
String getallocwait();
String getdstate();
String getfsyncwait();
String getionwait();
String getiowait();
String getschedlatency();
String hybridswap_memcg_para_read(int action, in String cgroup);
int hybridswap_memcg_para_write(int action, in String cgroup, in String str);
String hybridswap_zram_para_read(int action);
int hybridswap_zram_para_write(int action, in String str);
boolean isJankTaskTrackEnable();
int perProcessMemReadahead(int uid, int pid, int type);
int perProcessMemReclaim(int uid, int pid, int type);
String readCallStack();
String readClmEnable();
String readClmHighLoadAll();
String readClmHighLoadGrp();
String readClmLowLoadGrp();
String readCpuTaskstats();
String readDBacktrace();
String readDConvert();
String readFgFreqsThreshold();
String readIOBacktrace();
String readIomonitorInfo(in String procname);
String readJankCpuIndicator();
String readJankCpuInfo();
String readJankCpuInfoSig();
String readJankCpuLoad();
String readJankCpuLoad32();
String readJankCpuLoad32Scale();
String readJankTaskTrack();
String readJankTaskTrackByPid(int pid);
String readJankVersion();
String readKmallocDebugCreate();
String readLimitTable();
String readMemleakDetectThread();
ProcMemStatRet readMemoryByPids(in int[] pids, int flags);
ProcMemStatRet readMemoryByUids(in int[] uids, int flags);
String readNandswapProc(in String inProc);
String readNormalizeRealTime();
String readNormalizeRunningTime();
String readOplusReserve3(int offset, int len);
OsvelteVersionRet readOsvelteVersion();
String readPidsSet();
String readRealTime();
String readRunningTime();
String readSchedInfoThreshold();
String readSgeFreqInfo();
String readSgeInfo();
String readStorageFeature(in String name, in String addr, in String isMulti);
String readTargetProcess(in String buffer);
String readTaskCpustatsEnable();
String readTaskSchedInfo();
String readTidsSet();
String readTmemoryDirtypages();
String readTmemoryErrorStat();
String readTmemoryIoLatency();
String readTmemorySysdirtypages();
String readUxTaskTrack(int uPid, int rPid);
String readVaFeature();
String readVersion();
void removeTaskTrackPid(int group, int pid);
int searchAcmNomediaDirName(in String dirname);
int setAcmOpstat(int flag);
void setClmMuxSwitch(in String buffer);
void setClmThreshold(in String buffer, int threshold_id);
int setDamonReclaimColdTime(int cold_time);
int setDamonReclaimMonitoring(int sample, int aggr);
int setDamonReclaimQuota(int quota_ms, int quota_sz, int reset_interval);
int setDamonReclaimWmarks(int metric, int high, int mid, int low);
void setExtSchedProp(in String pid, in String prop);
void setFgUids(in String fg_uid);
void setFrameRate(in String frame_rate);
int setFreqGoverner(in String gov_name, in int[] clusters);
void setImFlag(in String pid, in String im_flag);
int setProcessReclaim(in String info);
void setSchedAssistImptTask(in String impt_info);
void setSchedAssistScene(in String scene_id);
void setSlideboost(in String boost);
int setTpdID(in String param);
int setTpdSerialParams(in String params);
int setWakeSeedThread(in String tid, boolean identify_type, boolean inUid);
void writeClmEnable(in String buffer);
void writeClmHighLoadAll(in String buffer);
void writeClmHighLoadGrp(in String buffer);
void writeClmLowLoadGrp(in String buffer);
void writeDBacktrace(in String buffer);
void writeFgFreqsThreshold(in String buffer);
void writeIOBacktrace(in String buffer);
void writeJankTaskTrackEnable(boolean enable);
int writeKmallocDebugCreate(int kcreate);
int writeKmallocDebugCreateWithType(in String type);
int writeMemMonitor(in String buffer);
int writeMemleakDetectThread(int memdect);
int writeMonitorStatus(in String buffer);
int writeNandswapProc(in String inProc, in String cmd);
int writeOplusReserve3(int offset, int len, in String info);
void writePidsSet(in String buffer);
void writeSchedInfoThreshold(in String buffer);
int writeStorageFeature(in String name, in String addr, in String isMulti, in String cmd);
void writeTaskSchedInfo(in String buffer);
void writeTidsSet(in String buffer);
int writeTmemoryCapacity(int param);
int writeTmemoryFlushBusy(int param);
int writeTmemoryFlushIdle(int param);
int writeTmemoryHighWaterRatio(int param);
int writeTmemoryMemory(in String str);
int writeTmemorySwitch(int param);
int writeUxState(in String ux_state, in String pid, in String tid);
int writeVaFeature(int vafeature);
}

View File

@@ -0,0 +1,12 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
@VintfStability
enum OsvelteStatus {
SUCCESS = 0,
FAILED = 1,
}

View File

@@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
@VintfStability
parcelable OsvelteVersionRet {
int status;
int major = 0;
int minor = 0;
}

View File

@@ -0,0 +1,29 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
@VintfStability
parcelable ProcMemStat {
String comm;
boolean is_32bit = false;
int oom_score_adj = 0;
int nr_fds = 0;
int uid = 0;
int pid = 0;
int ppid = 0;
int anon = 0;
int file = 0;
int shmem = 0;
int swap = 0;
int vss = 0;
int pss = 0;
int swap_rss = 0;
int javaheap = 0;
int nativeheap = 0;
int ashmem = 0;
int dmabuf = 0;
int gpu = 0;
}

View File

@@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
import vendor.oplus.hardware.performance.ProcMemStat;
@VintfStability
parcelable ProcMemStatRet {
int status;
ProcMemStat[] arr_ms;
}

View File

@@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
import vendor.oplus.hardware.performance.ProcReqItemHal;
@VintfStability
parcelable ProcReqHal {
String proc;
ProcReqItemHal[] items;
}

View File

@@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
@VintfStability
parcelable ProcReqItemHal {
String key;
String label;
int uploadType;
}

View File

@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
@VintfStability
enum TaskGroup {
DEFAULT = 0,
UI = 1,
RENDER = 2,
DISPLAY = 3,
INPUT = 4,
GAME = 5,
}

View File

@@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
import vendor.oplus.hardware.performance.ThreadInfo;
@VintfStability
parcelable TaskWakeInfo {
int ret = 0;
ThreadInfo[] list;
}

View File

@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
@VintfStability
parcelable ThreadInfo {
int pid = 0;
int tid = 0;
int SourcePid = 0;
int utils = 0;
int nice = 0;
int WakeCnt = 0;
int totalWakeCnt = 0;
}

View File

@@ -0,0 +1,13 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package vendor.oplus.hardware.performance;
@VintfStability
enum UploadType {
PRIMITIVE = 0,
DELTA = 1,
SKIP = 2,
}

View File

@@ -0,0 +1 @@
f5b7e586df4d7e58cf547d6f81731b69e128bbe1

View File

@@ -0,0 +1,149 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package vendor.oplus.hardware.charger;
@VintfStability
interface ICharger {
int VolDividerIcWorkModeSet(String data);
int chgExchangeMesgInit();
int chgExchangeSohMesgInit();
int getAcType();
int getBattAuthenticate();
int getBattPPSChgIng();
int getBattPPSChgPower();
String getBattParamNoplug();
int getBattShortIcOtpStatus();
int getBattSubCurrent();
int getBattVoocChgIng();
int getBatteryVoltageNow();
String getBccCsvData();
int getBccExpStatus();
String getBmsHeatingRunningStatus();
int getBmsHeatingStatus();
String getChargerControl();
int getChargerCoolDown();
int getChargerCriticalLog();
int getChargerIdVolt();
int getChargerLog();
int getCustomSelectChgMode();
String getDevinfoFastchg();
int getFastCharge();
int getParallelChgMosTestResult();
int getPsyAcOnline();
int getPsyBatteryCC();
int getPsyBatteryCurrentNow();
int getPsyBatteryFcc();
int getPsyBatteryHmac();
int getPsyBatteryLevel();
int getPsyBatteryNotify();
int getPsyBatteryPchg();
int getPsyBatteryPchgResetCount();
int getPsyBatteryRm();
int getPsyBatteryShortFeature();
int getPsyBatteryShortStatus();
String getPsyBatteryStatus();
int getPsyBatteryTemp();
int getPsyChargeTech();
int getPsyFastChgType();
int getPsyInputCurrent();
int getPsyOtgOnline();
int getPsyOtgSwitch();
int getPsyPcPortOnline();
int getPsyQGVbatDeviation();
int getPsyTypeOrientation();
int getPsyUsbOnline();
int getPsyUsbStatus();
String getPsyWirelessRX();
String getPsyWirelessRxVersion();
String getPsyWirelessTX();
String getPsyWirelessTxVersion();
int getQgVbatDeviation();
String getQuickModeGain();
String getReserveSocDebug();
int getSmartChgMode();
int getUIsohValue();
String getUisohDebugParameterInfo();
int getUsbInputCurrentNow();
int getUsbPrimalType();
int getWiredOtgOnline();
int getWirelessAdapterPower();
int getWirelessCapacity();
int getWirelessChargePumpEn();
int getWirelessCurrentNow();
String getWirelessDeviated();
int getWirelessOnline();
int getWirelessPenPresent();
int getWirelessPtmcId();
int getWirelessRXEnable();
int getWirelessRealType();
String getWirelessTXEnable();
int getWirelessUserSleepMode();
int getWirelessVoltageNow();
String healthd_update_ui_soc_decimal();
int nightstandby(int status);
int notifyScreenStatus(int status);
String queryChargeInfo();
int setChargeEMMode(String data);
int setChargerControl(String data);
int setChargerCoolDown(String data);
int setChargerCriticalLog(String data);
int setChargerCycle(String data);
int setChargerFactoryModeTest(String data);
int setChargerLog(String data);
int setChgStatusToBcc(int status);
int setCustomSelectChgMode(int mode, boolean enable);
int setFastchgFwUpdate(String data);
int setPsyMmiChgEn(String data);
int setPsyOtgSwitch(String data);
int setReserveSocDebug(String data);
int setShipMode(String data);
int setSmartChgMode(String data);
int setSmartCoolDown(int coolDown, int normalCoolDown, String pkgName);
int setTbattPwrOff(String data);
int setUisohDebugInfo(String data);
int setUsbPrimalType(String data);
int setWirelessChargePumpEn(String data);
int setWirelessFtmMode(String data);
int setWirelessIconDelay(String data);
int setWirelessIdtAdcTest(String data);
int setWirelessPenSoc(String data);
int setWirelessRXEnable(String data);
int setWirelessTXEnable(String data);
int setWirelessUserSleepMode(String data);
int setWlsThirdPartitionInfo(String data);
vendor.oplus.hardware.charger.testKitFeatureTestResult testKitFeatureTest(int index);
String testKitGetFeatureList();
String testKitGetFeatureName(int index);
int testKitGetFeatureNum();
int updateUiSohToPartion();
String queryWlsPencilInfo();
String getChgOlcConfig();
int setChgOlcConfig(String data);
int setSuperEnduranceStatus(String data);
int setSuperEnduranceCount(String data);
int setBobStatus(String data);
int setPsySlowChgEn(String data);
int getCpVbatDeviation();
int setBatteryLogPush(String data);
int getChargingModeInGsmCall();
int setChargingModeInGsmCall(String data);
}

View File

@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package vendor.oplus.hardware.charger;
@VintfStability
parcelable testKitFeatureTestResult {
int ret;
String str;
}

View File

@@ -0,0 +1 @@
a41b38d964ed21d7edcb4a1c29454c7c969b733b

View File

@@ -0,0 +1,150 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package vendor.oplus.hardware.charger;
@VintfStability
interface ICharger {
int VolDividerIcWorkModeSet(String data);
int chgExchangeMesgInit();
int chgExchangeSohMesgInit();
int getAcType();
int getBattAuthenticate();
int getBattPPSChgIng();
int getBattPPSChgPower();
String getBattParamNoplug();
int getBattShortIcOtpStatus();
int getBattSubCurrent();
int getBattVoocChgIng();
int getBatteryVoltageNow();
String getBccCsvData();
int getBccExpStatus();
String getBmsHeatingRunningStatus();
int getBmsHeatingStatus();
String getChargerControl();
int getChargerCoolDown();
int getChargerCriticalLog();
int getChargerIdVolt();
int getChargerLog();
int getCustomSelectChgMode();
String getDevinfoFastchg();
int getFastCharge();
int getParallelChgMosTestResult();
int getPsyAcOnline();
int getPsyBatteryCC();
int getPsyBatteryCurrentNow();
int getPsyBatteryFcc();
int getPsyBatteryHmac();
int getPsyBatteryLevel();
int getPsyBatteryNotify();
int getPsyBatteryPchg();
int getPsyBatteryPchgResetCount();
int getPsyBatteryRm();
int getPsyBatteryShortFeature();
int getPsyBatteryShortStatus();
String getPsyBatteryStatus();
int getPsyBatteryTemp();
int getPsyChargeTech();
int getPsyFastChgType();
int getPsyInputCurrent();
int getPsyOtgOnline();
int getPsyOtgSwitch();
int getPsyPcPortOnline();
int getPsyQGVbatDeviation();
int getPsyTypeOrientation();
int getPsyUsbOnline();
int getPsyUsbStatus();
String getPsyWirelessRX();
String getPsyWirelessRxVersion();
String getPsyWirelessTX();
String getPsyWirelessTxVersion();
int getQgVbatDeviation();
String getQuickModeGain();
String getReserveSocDebug();
int getSmartChgMode();
int getUIsohValue();
String getUisohDebugParameterInfo();
int getUsbInputCurrentNow();
int getUsbPrimalType();
int getWiredOtgOnline();
int getWirelessAdapterPower();
int getWirelessCapacity();
int getWirelessChargePumpEn();
int getWirelessCurrentNow();
String getWirelessDeviated();
int getWirelessOnline();
int getWirelessPenPresent();
int getWirelessPtmcId();
int getWirelessRXEnable();
int getWirelessRealType();
String getWirelessTXEnable();
int getWirelessUserSleepMode();
int getWirelessVoltageNow();
String healthd_update_ui_soc_decimal();
int nightstandby(int status);
int notifyScreenStatus(int status);
String queryChargeInfo();
int setChargeEMMode(String data);
int setChargerControl(String data);
int setChargerCoolDown(String data);
int setChargerCriticalLog(String data);
int setChargerCycle(String data);
int setChargerFactoryModeTest(String data);
int setChargerLog(String data);
int setChgStatusToBcc(int status);
int setCustomSelectChgMode(int mode, boolean enable);
int setFastchgFwUpdate(String data);
int setPsyMmiChgEn(String data);
int setPsyOtgSwitch(String data);
int setReserveSocDebug(String data);
int setShipMode(String data);
int setSmartChgMode(String data);
int setSmartCoolDown(int coolDown, int normalCoolDown, String pkgName);
int setTbattPwrOff(String data);
int setUisohDebugInfo(String data);
int setUsbPrimalType(String data);
int setWirelessChargePumpEn(String data);
int setWirelessFtmMode(String data);
int setWirelessIconDelay(String data);
int setWirelessIdtAdcTest(String data);
int setWirelessPenSoc(String data);
int setWirelessRXEnable(String data);
int setWirelessTXEnable(String data);
int setWirelessUserSleepMode(String data);
int setWlsThirdPartitionInfo(String data);
vendor.oplus.hardware.charger.testKitFeatureTestResult testKitFeatureTest(int index);
String testKitGetFeatureList();
String testKitGetFeatureName(int index);
int testKitGetFeatureNum();
int updateUiSohToPartion();
String queryWlsPencilInfo();
String getChgOlcConfig();
int setChgOlcConfig(String data);
int setSuperEnduranceStatus(String data);
int setSuperEnduranceCount(String data);
int setBobStatus(String data);
int setPsySlowChgEn(String data);
int getCpVbatDeviation();
int setBatteryLogPush(String data);
int getChargingModeInGsmCall();
int setChargingModeInGsmCall(String data);
int setChgRusConfig(String data);
}

View File

@@ -0,0 +1,28 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package vendor.oplus.hardware.charger;
@VintfStability
parcelable testKitFeatureTestResult {
int ret;
String str;
}

View File

@@ -0,0 +1 @@
94b22213920f83dfdbc7a6b53c0de919dc12eafc

View File

@@ -0,0 +1,152 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
///////////////////////////////////////////////////////////////////////////////
// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
///////////////////////////////////////////////////////////////////////////////
// This file is a snapshot of an AIDL file. Do not edit it manually. There are
// two cases:
// 1). this is a frozen version file - do not edit this in any case.
// 2). this is a 'current' file. If you make a backwards compatible change to
// the interface (from the latest frozen version), the build system will
// prompt you to update this file with `m <name>-update-api`.
//
// You must not make a backward incompatible change to any AIDL file built
// with the aidl_interface module type with versions property set. The module
// type is used to build AIDL files in a way that they can be used across
// independently updatable components of the system. If a device is shipped
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
package vendor.oplus.hardware.charger;
@VintfStability
interface ICharger {
int VolDividerIcWorkModeSet(String data);
int chgExchangeMesgInit();
int chgExchangeSohMesgInit();
int getAcType();
int getBattAuthenticate();
int getBattPPSChgIng();
int getBattPPSChgPower();
String getBattParamNoplug();
int getBattShortIcOtpStatus();
int getBattSubCurrent();
int getBattVoocChgIng();
int getBatteryVoltageNow();
String getBccCsvData();
int getBccExpStatus();
String getBmsHeatingRunningStatus();
int getBmsHeatingStatus();
String getChargerControl();
int getChargerCoolDown();
int getChargerCriticalLog();
int getChargerIdVolt();
int getChargerLog();
int getCustomSelectChgMode();
String getDevinfoFastchg();
int getFastCharge();
int getParallelChgMosTestResult();
int getPsyAcOnline();
int getPsyBatteryCC();
int getPsyBatteryCurrentNow();
int getPsyBatteryFcc();
int getPsyBatteryHmac();
int getPsyBatteryLevel();
int getPsyBatteryNotify();
int getPsyBatteryPchg();
int getPsyBatteryPchgResetCount();
int getPsyBatteryRm();
int getPsyBatteryShortFeature();
int getPsyBatteryShortStatus();
String getPsyBatteryStatus();
int getPsyBatteryTemp();
int getPsyChargeTech();
int getPsyFastChgType();
int getPsyInputCurrent();
int getPsyOtgOnline();
int getPsyOtgSwitch();
int getPsyPcPortOnline();
int getPsyQGVbatDeviation();
int getPsyTypeOrientation();
int getPsyUsbOnline();
int getPsyUsbStatus();
String getPsyWirelessRX();
String getPsyWirelessRxVersion();
String getPsyWirelessTX();
String getPsyWirelessTxVersion();
int getQgVbatDeviation();
String getQuickModeGain();
String getReserveSocDebug();
int getSmartChgMode();
int getUIsohValue();
String getUisohDebugParameterInfo();
int getUsbInputCurrentNow();
int getUsbPrimalType();
int getWiredOtgOnline();
int getWirelessAdapterPower();
int getWirelessCapacity();
int getWirelessChargePumpEn();
int getWirelessCurrentNow();
String getWirelessDeviated();
int getWirelessOnline();
int getWirelessPenPresent();
int getWirelessPtmcId();
int getWirelessRXEnable();
int getWirelessRealType();
String getWirelessTXEnable();
int getWirelessUserSleepMode();
int getWirelessVoltageNow();
String healthd_update_ui_soc_decimal();
int nightstandby(int status);
int notifyScreenStatus(int status);
String queryChargeInfo();
int setChargeEMMode(String data);
int setChargerControl(String data);
int setChargerCoolDown(String data);
int setChargerCriticalLog(String data);
int setChargerCycle(String data);
int setChargerFactoryModeTest(String data);
int setChargerLog(String data);
int setChgStatusToBcc(int status);
int setCustomSelectChgMode(int mode, boolean enable);
int setFastchgFwUpdate(String data);
int setPsyMmiChgEn(String data);
int setPsyOtgSwitch(String data);
int setReserveSocDebug(String data);
int setShipMode(String data);
int setSmartChgMode(String data);
int setSmartCoolDown(int coolDown, int normalCoolDown, String pkgName);
int setTbattPwrOff(String data);
int setUisohDebugInfo(String data);
int setUsbPrimalType(String data);
int setWirelessChargePumpEn(String data);
int setWirelessFtmMode(String data);
int setWirelessIconDelay(String data);
int setWirelessIdtAdcTest(String data);
int setWirelessPenSoc(String data);
int setWirelessRXEnable(String data);
int setWirelessTXEnable(String data);
int setWirelessUserSleepMode(String data);
int setWlsThirdPartitionInfo(String data);
vendor.oplus.hardware.charger.testKitFeatureTestResult testKitFeatureTest(int index);
String testKitGetFeatureList();
String testKitGetFeatureName(int index);
int testKitGetFeatureNum();
int updateUiSohToPartion();
String queryWlsPencilInfo();
String getChgOlcConfig();
int setChgOlcConfig(String data);
int setSuperEnduranceStatus(String data);
int setSuperEnduranceCount(String data);
int setBobStatus(String data);
int setPsySlowChgEn(String data);
int getCpVbatDeviation();
int setBatteryLogPush(String data);
int getChargingModeInGsmCall();
int setChargingModeInGsmCall(String data);
int setChgRusConfig(String data);
String getPsyBatterySN();
String getBattGaugeInfo();
}

Some files were not shown because too many files have changed in this diff Show More