59 Commits

Author SHA1 Message Date
kondors1995
24d924a690 aidl/fingerprint: utilize MaxPerformance task_profile
Some checks failed
action.yml / aidl/fingerprint: utilize MaxPerformance task_profile (push) Failing after 0s
2026-01-23 08:17:07 +09:00
Pranav Vashi
3f98ab0409 DSPVolumeSynchronizer: Do not install for clone apps or private space
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
2026-01-23 08:17:07 +09:00
Alcatraz323
fdb7f5a07c 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
2026-01-23 08:17:07 +09:00
Adithya R
9918fab7e8 interfaces: displayfeature: Fix method ordering
Based on analysis of stock interface.

Change-Id: Ib49d18ee15e3f7be1b3b314277357e54f953d73a
2026-01-23 08:17:07 +09:00
Aaron Kling
73460c17a7 healthd-ext: update AIDL HAL version to 3
Resolves vts failure:
For android.hardware.health.IHealth/default, manifest (targeting FCM:6)
declares version 2, but the actual version is 3

Change-Id: I8ff7278d373d6bdf906d3e1367fe7d4613552a8b
2026-01-23 08:17:07 +09:00
Fenglin Wu
b70a8d1901 healthd-ext: update VINTF manifest version to 2
Update VINTF manifest version to 2 to match with the latest definition
in android.hardware.health.IHealth AIDL interface.

Change-Id: Iabf4165c52cca95ff8aa75a67bbc61f4c102bb9e
(cherry picked from commit ad957d158ad1d53193536a2e0cee016836d90cd0)
2026-01-23 08:17:07 +09:00
Fabian Leutenegger
f29df9dd3b healthd-ext: Fix charge_counter and ETA values
Based on 137843ec4f

Co-authored-by: Adithya R <gh0strider.2k18.reborn@gmail.com>
Change-Id: I3d000d283302a84ee9fcbd5a85ef26817b68c0a7
2026-01-23 08:17:07 +09:00
chrisl7
bd29fa8f94 healthd-ext: Define override to QTI AIDL healthd-ext hal
Change-Id: I26009b1f20c02219dd371ad184cad4eafb9e8eec
2026-01-23 08:17:07 +09:00
chrisl7
307bed2f81 healthd-ext: Rename hal to xiaomi to avoid compilation conflicts
Change-Id: I8f33b6870eccfd19272cfbdb816b5b53371012c5
2026-01-23 08:17:07 +09:00
Fenglin Wu
c556e4a329 healthd-ext: Update AIDL HAL service installation paths
Update the installation path for vendor and recovery partition
respectively.

Change-Id: I1908d10d782127f555e2fb316f3640bc93efcdbd
2026-01-23 08:17:07 +09:00
Fenglin Wu
16e431ce2f healthd-ext: Add suspend support for charger mode
Override ChargerEnableSuspend() function to true to support kernel
suspend and resume in charger mode.

Change-Id: I01ceaecf7e918504624b2bf1bfb34207fcde74e7
2026-01-23 08:17:07 +09:00
Fenglin Wu
8c2abcf067 healthd-ext: Add health HAL AIDL implementation
Add health HAL AIDL implementation which is a service running for
both health HAL and charger mode.

Change-Id: I1f3205d1e34d93ed1739d5fa29c95a8f2b2d2894
2026-01-23 08:17:07 +09:00
AdarshGrewal
6bb35480ed hardware/xiaomi: Mark setTouchMode as void
* these methods dont return any values this needs to be doe for remaining methods too probabbly
2026-01-23 08:17:07 +09:00
AdarshGrewal
5a02b6a1c4 interfaces: Import reversed aidl interface for IDisplayFeature
This Interface Needed for parts fragment to make working custom saturation Slider instead of using linej livedisplay hal.
Signed-off-by: GuidixX <guidixm@gmail.com>
2026-01-23 08:17:07 +09:00
AdarshGrewal
cf8dc72b88 hardware/xiaomi: fixup aidl interfaces 2026-01-23 08:17:07 +09:00
raghavt20
e0435f1a92 hardware/xiaomi: Import reversed aidl interface for ITouchFeature
Change-Id: Icc959b71ae4d90f81c5769de4ad16ba1a0984871
2026-01-23 08:17:07 +09:00
raghavt20
d44baa90c8 hardware/xiaomi: Import reversed aidl interface for IXiaomiFingerprint
Change-Id: I0d60666324d986333dc10824250d90fe42ab878a
2026-01-23 08:17:07 +09:00
Piotr Kozimor
3846de048d vintf: Add IMiSys HAL in compatibility matrix
Change-Id: I65bb9bf6d0aff733ca533f3c8bd5a7922058c9ff
Signed-off-by: Pranav Vashi <neobuddy89@gmail.com>
Signed-off-by: firebird11 <hbgassel@gmail.com>
2026-01-23 08:17:07 +09:00
basamaryan
8b9f87316a vinf: Add {vendor.dolby_sp.hardware.dmssp, vendor.dolby_v3_6.hardware.dms360} to FCM
Change-Id: I19a0ca830469aa3978e0e89a75536d14cec735b8
2026-01-23 08:17:07 +09:00
Adithya R
181b9c2f75 vintf: Add more hals to fcm
Change-Id: I6645216d2665ab1d51f789b9f4f80acf411e875c
2026-01-23 08:17:07 +09:00
Rocky Fang
ea30c0736a aidl: sensors: Set dynamic_sensor_timeout to 1600 during boot
Test: on device test
Bug: 398856625
Flag: EXEMPT N/A for *.rc file

Change-Id: I6c97e6b34305934efdc833e96f0aa4374cb3d878
2026-01-23 08:17:04 +09:00
Bruno Martins
91d15fa7af xiaomi: Move all apps under packages directory
Becomes much better organized.

Change-Id: Ifb7c4d984e7ac1776edc567e682f8d4b0b713543
2026-01-22 13:23:28 +02:00
Jihoon Kang
dbf0dc9428 aidl: sensors: Define vintf_fragments as modules
Define vintf_fragments as modules so that the generated vintf
manifest.xml file is identical between soong and make.

Test: m --no-soong-only && diff xml files
Bug: 322089980
Bug: 409368614
Change-Id: I75c698dfdac9f84a2b37afef62b4086b7b0a5210
2026-01-17 18:21:15 +00:00
Rocky Fang
2c14234077 aidl: sensors: Update a misleading error log.
Bug: 389000592
Bug: 400469383
Test: Presubmit
Flag: EXEMPT bugfix
Change-Id: I0ce33c9e9f7bf4136a1d8aa9219dfce45de157e9
2026-01-17 18:20:34 +00:00
AdarshGrewal
f18dcb8e17 Euicc: Add Redmi Note 13 Pro/POCO X6 support
Change-Id: I921854c9c33122b15cfea0e6dea7b07cb79384d3
2026-01-17 22:50:21 +05:30
Lunark :3
aae52ffce4 Euicc: Add Xiaomi 13 Pro Support
Change-Id: Ia0c3852750f49cbabcc31ff774b7e66dea0cf30b
Signed-off-by: Lunark :3 <jvillaltamatos3007@gmail.com>
2026-01-11 19:32:00 +00:00
Nick Reuter
f677ebecd8 xiaomi: Add EuiccPolicy overlay
Extracted using:
 /path/to/lineage/scripts/dev/generate_euicc.py -v xiaomi -o overlay /path/to/EuiccPartnerApp.apk

Change-Id: I192ddbf961fc2be98dbdf804ab792bb530a0acda
2026-01-11 19:31:55 +00:00
LuK1337
40ef19ab76 pre-commit: Enable clang-format
Change-Id: I7a22a5fe9ee7176604fed0825f96417c53adb1ff
2026-01-11 19:24:41 +00:00
Bruno Martins
e400c781e8 megvii: Run clang-format
Change-Id: I7b3b20c51d06f5425bd2c84ae2785f3e1f593178
2026-01-11 19:24:41 +00:00
Bruno Martins
b0a11aa8b4 sensors: Run clang-format
Change-Id: Ibacd45e08fbace2dd4ff3082712d61215b539121
2026-01-11 19:24:41 +00:00
Bruno Martins
5bb09cf6fa IFAAService: Run through ktfmt
Change-Id: I4a4e6d390ec09d66cd5acda806a200771de67164
2026-01-01 19:10:11 +00:00
LuK1337
2eaa37731a Introduce pre-commit & GitHub Actions for it
Change-Id: I4604d13e5ccf74ec4c7088a40a9f7f915f9b1293
2026-01-01 14:56:38 +00:00
SkyMinus
04c945f5b3 sensors: Lazily open the enable stream
Sysfs node initialization lags behind HAL startup on SM8550 and newer platforms. Opening the node in the constructor causes a race condition, leading to enable path writing failure.

Lazily open the enable stream to resolve this race condition.

Change-Id: I8e2c5996a52a5870143adf9b6a5c6689c9e6d5a5
2025-12-08 23:02:22 +08:00
LuK1337
15e7009f6f IFAAService: Simplify startBIOManager function
Change-Id: I86ae17e0fa3cfcf438c90502a3be5035d9373f54
2025-08-09 13:52:07 +00:00
Elliott Hughes
94a8ea7957 vibrator: libc++fs is part of libc++ now.
Change-Id: I690cf4de20989c7042a2fac831ab2cebf1ea3b9d
2025-07-28 20:19:10 +00:00
Bin
636ce206a0 aidl: fingerprint: Set properties for IFAA
MlipayService needs these props to work.
This exists in hidl fingerprint, but is missing in aidl.

Reference: I0b1786721c951cd833d3c20f58cd0c8a70c08fae
Change-Id: I70a43ccde9ec2db51b265e1896a89ca640164a36
2025-06-23 09:00:45 +00:00
Bruno Martins
33a419e8c1 touch: Include KeyDisabler and KeySwapper generic support
This adds conditional support for KeyDisabler and KeySwapper
along with HighTouchPollingRate feature.

Change-Id: Ie6c0e7c1032e9d44bf03e6f6738581a4418fb645
2025-06-18 07:37:21 +00:00
Bruno Martins
064c24617e touch: Migrate to AIDL
Change-Id: If44efbab6ad53701a662788daecfd7678935e8b4
2025-06-18 07:37:21 +00:00
Bruno Martins
4d7a952308 touch: Use select()
Change-Id: I28e54d5ddaf5e376292d2b4ec7b69d5a49fe4f54
2025-06-18 07:37:21 +00:00
Arian
06bfc823ef aidl: fingerprint: Grant SYS_NICE capability to set SCHED_FIFO
Xiaomi is using sched_setscheduler in libgf_hal to increase the
fingerprint processes scheduling policy to SCHED_FIFO while the
finger is down. This requires the SYS_NICE capability.

Change-Id: Id22c5e255e61080dc83561948ea14f5ad6ebf38f
2025-06-12 23:40:04 +00:00
Bruno Martins
641b58600b xiaomi: Document Soong options
Change-Id: If0bb874560b1a612fb747c79d8a15e4c17277025
2025-06-07 18:22:17 +01:00
Bruno Martins
6454f6c267 aidl: fingerprint: Follow pre-existing namespace convention
Change-Id: I368cfc3756c124f7025ad0ea85c138b5f7e18aa0
2025-06-07 18:15:49 +01:00
basamaryan
6785f93e35 Remove aidl/ir
More common one available in hardware/lineage/interfaces.

Change-Id: I5546cba7ef770f028f8d2222a7960d53c51f02c8
2025-05-27 10:37:37 -04:00
Arian
3bb55820e8 udfpshandler: Add authentication succeeded/failed notifications
We currently miss a call when the fingerprint gets rejected
the fifth time, and the onFingerUp method isn't called anymore.
Without handling this in the touchscreen driver, we can not
disable lhbm (ghbm should turn off fine since the udfps layer
vanishes). The onAuthentication* methods are called when the
authentication ends, allowing for a better control of the lhbm
state.

Change-Id: I5ff6b9b4692657fade4579faff33eb48c1311987
2025-05-22 15:52:00 +02:00
Arian
0b8722e673 udfpshandler: Provide default noop implementations of functions
Some devices might not require to do something in all cases.
In order to simplify adding new functions, add default
implementations such that we can add new functions without
having to add new dummy implementations to all devices
udfpshandlers.

Change-Id: I37ad23c551fd51e3ff778ac43f10dc6552d32651
2025-05-22 15:51:31 +02:00
Arian
3a4813d67b interfaces: Add prebuilt hidl interfaces declarations
All interfaces that are defined in vintf/xiaomi_framework_compatibility_matrix
for which no source is available in interfaces/ are added to the list
of prebuilt hidl interfaces to allow host_init_verifier to work
properly.

Change-Id: If6bdd313bb9ff5dc8c766f0f883f5a86c22c83ec
2025-04-06 22:33:25 +00:00
Giovanni Ricca
1300e116bc vintf: Add IMiCameraPerfService interface to FCM
Change-Id: Ib5d105ead609c9d8bff06733ca0ff5afac38a658
2025-03-30 12:30:53 +02:00
bengris32
88247d9e05 vintf: Add dtool interface
Change-Id: Ida7da820801272266f0081c16ff795b04d7d3202
Signed-off-by: bengris32 <bengris32@protonmail.ch>
2025-03-30 12:30:53 +02:00
bengris32
bb6f814a3d vintf: Add alternative citsensorservice interface
Change-Id: I056da81869f438e197e0c46a4b520124537181bc
Signed-off-by: bengris32 <bengris32@protonmail.ch>
2025-03-30 12:30:50 +02:00
Daniel Zheng
b56de4957c Revert^2 "SensorHAL: add moisture detection"
919258a5867165de9abe377f30a0b7a8fc9a2c99

Change-Id: I351625927ce9259967218565abaf56035e97674a
2025-03-09 23:11:45 +02:00
basamaryan
dc3069c44b Remove aidl/light
More common one available in hardware/lineage/interfaces.

Change-Id: I2f68badca3679f820966e25979c93278b61c6257
2025-02-08 12:46:28 +00:00
Luofan Chen
c8cd550f87 aidl: fingerprint: Improve documentation on sensor_location
Change-Id: Ic0038cadab50208193312e47a616314a77210b1e
2025-02-08 12:45:13 +00:00
Giovanni Ricca
35d550916c aidl: fingerprint: Add support to different Fingerprint module ID
Some devices may use a different module ID than
FINGERPRINT_HARDWARE_MODULE_ID (for example gf_fingerprint).
Let's handle the case for them as well.

Change-Id: I739ae664dec42792d98254352177a74afac98e4f
2024-12-25 19:32:38 -05:00
Giovanni Ricca
1b81776dd7 aidl: fingerprint: Use soong to decide which arch to build
Some devices got 64bit kernelspace ported, but they need to use the
original 32bit HALs.

device.mk:
$(call soong_config_set,xiaomi_hardware_biometrics,run_32bit,true)

Change-Id: I5176147a4da3a8069bcfb35d64fdaa48e23190e2
2024-12-25 19:32:38 -05:00
Jens Reidel
864199e705 aidl: fingerprint: Allow setting more than one sensor location
There are several devices that have only a single display, but different
panels that have different IDs. Since V, display ID is required for the
fingerprint location. The current implementation therefore isn't
suitable anymore. This adds support for specifying multiple locations in
a comma-separated list while retaining backwards compatibility.

Change-Id: Icaa065c9c926503ff07e35ccf64a86ffa1cfd721
Signed-off-by: Jens Reidel <adrian@travitia.xyz>
2024-12-25 19:32:38 -05:00
Arian
94ac6370ad aidl: fingerprint: Eat vendor acquired messages
UdfpsController is calling tryAodSendFingerUp when it receives
a vendor acquired message which in turn calls onPointerUp.
Since our sensors are sending a vendor acquired message during
scanning, the hal is informed about a finger up event and thus
disables hbm etc. during scanning in aod/screen off states.

[1]: 6cc7c9df3a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java (332)
[2]: 6cc7c9df3a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java (352)

Change-Id: I0e3a7113a1ca2cc2c07f141a5e325b0ed61913ca
2024-12-25 19:32:38 -05:00
Fabian Leutenegger
ba11fe6f76 aidl: fingerprint: Initial Xiaomi implementation
Co-authored-by: IPSBHANGU <inderpreetbhangu2@gmail.com>
Change-Id: Ib410ef5d92747deb9af34b3eb88f620c75797618
2024-12-25 19:32:38 -05:00
Tim Zimmermann
4ed4bb5c77 aidl: fingerprint: Initial stub service
Change-Id: I1e0594b88d5230f8c99a6efb0a7dafcbf6ea137a
2024-12-25 19:32:38 -05:00
basamaryan
1c49eb9f6c fingerprint: Move UDFPS handler and extension out of HIDL
Change-Id: Ib78169536cfb3c96b8437dc9b3341837c31c7362
2024-12-25 19:32:26 -05:00
124 changed files with 2933 additions and 1988 deletions

View File

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

13
.clang-format Normal file
View File

@@ -0,0 +1,13 @@
BasedOnStyle: Google
Standard: Cpp11
AccessModifierOffset: -2
AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IncludeBlocks: Preserve
IndentWidth: 4
ContinuationIndentWidth: 8
PointerAlignment: Left
TabWidth: 4
UseTab: Never

13
.github/workflows/build/action.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
name: build
runs:
using: composite
steps:
- name: Install dependencies
shell: bash
run: pip install pre-commit
- name: Lint
shell: bash
run: pre-commit run --all

38
.github/workflows/gerrit.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
name: gerrit checks
on:
workflow_dispatch:
inputs:
ref:
type: string
gerrit-ref:
type: string
change:
type: string
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: lineageos-infra/fetch-gerrit-change@main
with:
gerrit-ref: ${{ inputs.gerrit-ref }}
ref: ${{ inputs.ref }}
- name: Check if build/action.yml exists
id: check
run: |
if [ -f ./.github/workflows/build/action.yml ]; then
echo "run=1" >> "$GITHUB_OUTPUT"
fi
- name: Build
if: ${{ steps.check.outputs.run }}
uses: ./.github/workflows/build
- uses: lineageos-infra/gerrit-vote@main
if: ${{ steps.check.outputs.run && always() }}
with:
auth: ${{ secrets.GERRIT_VOTE_CREDS }}
change: ${{ inputs.change }}
ref: ${{ inputs.ref }}

20
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,20 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v21.1.8
hooks:
- id: clang-format
types_or: [c, c++]
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
rev: v2.15.0
hooks:
- id: pretty-format-kotlin
args: [--autofix, --ktfmt, --ktfmt-style=kotlinlang]

View File

@@ -0,0 +1,48 @@
//
// 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",
"preinstalled-packages-platform-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,
}
prebuilt_etc {
name: "preinstalled-packages-platform-dspvolume",
relative_install_path: "sysconfig",
src: "preinstalled-packages-platform-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,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2025 crDroid Android 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.
-->
<config>
<!-- Dolby -->
<install-in-user-type package="org.lineageos.dspvolume.xiaomi">
<install-in user-type="FULL" />
<install-in user-type="PROFILE" />
<do-not-install-in user-type="android.os.usertype.profile.CLONE" />
<do-not-install-in user-type="android.os.usertype.profile.PRIVATE" />
</install-in-user-type>
</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

@@ -1,183 +0,0 @@
/*
* SPDX-FileCopyrightText: 2022-2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
package org.ifaa.aidl.manager
import android.app.Service
import android.content.Intent
import android.os.Build
import android.os.IHwBinder
import android.os.SystemProperties
import android.provider.Settings
import android.util.Log
import org.ifaa.aidl.manager.IfaaManagerService
import org.json.JSONObject
import vendor.xiaomi.hardware.mlipay.V1_1.IMlipayService
class IfaaService : Service() {
private var _mlipayService: IMlipayService? = null
private val mlipayServiceDeathRecipient = IHwBinder.DeathRecipient {
Log.i(LOG_TAG, "mlipay service died")
_mlipayService = null
}
private val mBinder = object : IfaaManagerService.Stub() {
override fun getSupportBIOTypes(): Int {
val fpVendor = SystemProperties.get(FP_VENDOR_PROP, "")
val isUdfps = SystemProperties.getBoolean(IS_UDFPS_PROP, false)
val supportedBioMask = when (!invalidFpVendors.contains(fpVendor.lowercase())) {
true -> AUTH_TYPE_FINGERPRINT or AUTH_TYPE_IRIS
else -> AUTH_TYPE_IRIS
}
val ifaaProp = SystemProperties.getInt(
SUPPORTED_BIO_MASK_PROP, 0
) and supportedBioMask or when (isUdfps) {
true -> AUTH_TYPE_OPTICAL_FINGERPRINT
else -> 0
}
return ifaaProp
}
override fun startBIOManager(authType: Int) = when (authType) {
AUTH_TYPE_FINGERPRINT -> {
val intent = Intent(Settings.ACTION_SECURITY_SETTINGS).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
applicationContext.startActivity(intent)
COMMAND_OK
}
else -> COMMAND_FAIL
}
override fun getDeviceModel() = "${Build.MANUFACTURER}-${Build.DEVICE}"
override fun processCmd(param: ByteArray) = getMlipayService()?.let { mlipayService ->
var receiveBuffer: ByteArray? = null
val paramByteArray = ArrayList<Byte>().apply {
for (byte in param) {
add(byte)
}
}
try {
val receiveBufferByteArray = mlipayService.invoke_command(
paramByteArray, paramByteArray.size
)
receiveBuffer = receiveBufferByteArray.toByteArray()
} catch (e: Exception) {
Log.e(LOG_TAG, "processCmdImpl: mlipay invoke_command failed", e)
}
receiveBuffer
}
override fun getVersion() = 4
override fun getExtInfo(authType: Int, keyExtInfo: String) = initExtString()
override fun setExtInfo(authType: Int, keyExtInfo: String, valExtInfo: String) {
// Do nothing
}
override fun getEnabled(bioType: Int) = when (bioType) {
AUTH_TYPE_FINGERPRINT -> BIOMETRICS_AVAILABLE
else -> SCREEN_LOCK_NONE
}
override fun getIDList(bioType: Int): IntArray {
var idList = IntArray(0)
getMlipayService()?.let { mlipayService ->
try {
val idListAL = mlipayService.ifaa_get_idlist(bioType)
idList = idListAL.toIntArray()
} catch (e: Exception) {
Log.e(LOG_TAG, "getIDListImpl: mlipay ifaa_get_idlist failed", e)
}
}
return idList
}
}
override fun onBind(intent: Intent) = mBinder
private fun getMlipayService() = _mlipayService ?: runCatching {
IMlipayService.getService(true)
}.onSuccess {
_mlipayService = it
it.linkToDeath(mlipayServiceDeathRecipient, 0)
}.getOrNull()
private fun initExtString(): String {
val obj = JSONObject()
val keyInfo = JSONObject()
val xy = SystemProperties.get(UDFPS_LOCATION_X_Y_PROP, "")
val wh = SystemProperties.get(UDFPS_SIZE_W_H_PROP, "")
try {
if (!validateVal(xy) || !validateVal(wh)) {
Log.e(LOG_TAG, "initExtString: invalidate, xy: $xy, wh: $wh")
return ""
}
val split = xy.split(",")
val split2 = wh.split(",")
keyInfo.put("startX", split[0].toInt())
keyInfo.put("startY", split[1].toInt())
keyInfo.put("width", split2[0].toInt())
keyInfo.put("height", split2[1].toInt())
keyInfo.put("navConflict", true)
obj.put("type", 0)
obj.put("fullView", keyInfo)
return obj.toString()
} catch (e: Exception) {
Log.e(LOG_TAG, "initExtString: Exception, xy: $xy, wh: $wh", e)
return ""
}
}
private fun validateVal(str: String) = !"".equals(str, ignoreCase = true) && str.contains(",")
companion object {
private val LOG_TAG = IfaaService::class.simpleName!!
private const val AUTH_TYPE_NOT_SUPPORT = 0
private const val AUTH_TYPE_FINGERPRINT = 1
private const val AUTH_TYPE_IRIS = 1.shl(1)
private const val AUTH_TYPE_OPTICAL_FINGERPRINT = 1.shl(2)
private const val BIOMETRICS_AVAILABLE = 1000
private const val SCREEN_LOCK_NONE = 1003
private const val COMMAND_OK = 0
private const val COMMAND_FAIL = -1
private const val SUPPORTED_BIO_MASK_PROP = "persist.vendor.sys.pay.ifaa"
private const val FP_VENDOR_PROP = "persist.vendor.sys.fp.vendor"
private const val IS_UDFPS_PROP = "ro.hardware.fp.udfps"
private const val UDFPS_LOCATION_X_Y_PROP = "persist.vendor.sys.fp.udfps.location.X_Y"
private const val UDFPS_SIZE_W_H_PROP = "persist.vendor.sys.fp.udfps.size.width_height"
private val invalidFpVendors = arrayOf(
"",
"none",
)
}
}

10
README.md Normal file
View File

@@ -0,0 +1,10 @@
# hardware/xiaomi
## Soong options
| Namespace | Variable | Description | Default |
| --------- | -------- | ----------- | ------- |
| XIAOMI_BIOMETRICS_FINGERPRINT | RUN_32BIT | Opt to run service in 32-bit mode only | false |
| XIAOMI_TOUCH | HIGH_TOUCH_POLLING_PATH | HighTouchPollingRate feature control path | |
| XIAOMI_TOUCH | KEY_DISABLER_CONTROL_PATH | KeyDisabler feature control path | |
| XIAOMI_TOUCH | KEY_SWAPPER_CONTROL_PATH | KeySwapper feature control path | |

View File

@@ -0,0 +1,74 @@
//
// Copyright (C) 2024-2025 The LineageOS Project
// 2024 Paranoid Android
//
// SPDX-License-Identifier: Apache-2.0
//
soong_config_module_type {
name: "xiaomi_hardware_biometrics_config_default",
module_type: "cc_defaults",
config_namespace: "XIAOMI_BIOMETRICS_FINGERPRINT",
bool_variables: [
"RUN_32BIT",
],
properties: ["compile_multilib"],
}
xiaomi_hardware_biometrics_config_default {
name: "xiaomi_hardware_biometrics_config_default",
soong_config_variables: {
RUN_32BIT: {
conditions_default: {
compile_multilib: "64",
},
compile_multilib: "prefer32",
},
},
}
cc_binary {
name: "android.hardware.biometrics.fingerprint-service.xiaomi",
defaults: ["xiaomi_hardware_biometrics_config_default"],
relative_install_path: "hw",
init_rc: ["android.hardware.biometrics.fingerprint-service.xiaomi.rc"],
vintf_fragments: ["android.hardware.biometrics.fingerprint-service.xiaomi.xml"],
srcs: [
"CancellationSignal.cpp",
"Fingerprint.cpp",
"FingerprintConfig.cpp",
"LockoutTracker.cpp",
"Session.cpp",
"service.cpp",
],
local_include_dirs: [
"include",
],
shared_libs: [
"libbase",
"libbinder_ndk",
"libcutils",
"libhardware",
"libdl",
"liblog",
"android.hardware.biometrics.fingerprint-V4-ndk",
"android.hardware.biometrics.common-V4-ndk",
"android.hardware.biometrics.common.config",
"android.hardware.biometrics.common.thread",
"android.hardware.biometrics.common.util",
],
static_libs: [
"libandroid.hardware.biometrics.fingerprint.Props",
"libudfpshandlerfactory",
],
vendor: true,
header_libs: ["xiaomifingerprint_headers"],
}
sysprop_library {
name: "android.hardware.biometrics.fingerprint.Props",
srcs: ["fingerprint.sysprop"],
property_owner: "Vendor",
vendor: true,
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "CancellationSignal.h"
namespace aidl::android::hardware::biometrics::fingerprint {
CancellationSignal::CancellationSignal(Session* session) : mSession(session) {}
ndk::ScopedAStatus CancellationSignal::cancel() {
return mSession->cancel();
}
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/android/hardware/biometrics/common/BnCancellationSignal.h>
#include "Session.h"
namespace aidl::android::hardware::biometrics::fingerprint {
class CancellationSignal
: public ::aidl::android::hardware::biometrics::common::BnCancellationSignal {
public:
CancellationSignal(Session* session);
ndk::ScopedAStatus cancel() override;
private:
Session* mSession;
};
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,255 @@
/*
* Copyright (C) 2024-2025 The LineageOS Project
* 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Fingerprint.h"
#include <android-base/properties.h>
#include <fingerprint.sysprop.h>
#include "util/Util.h"
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
using ::android::base::SetProperty;
namespace aidl::android::hardware::biometrics::fingerprint {
namespace {
constexpr int MAX_ENROLLMENTS_PER_USER = 5;
constexpr char HW_COMPONENT_ID[] = "fingerprintSensor";
constexpr char HW_VERSION[] = "vendor/model/revision";
constexpr char FW_VERSION[] = "1.01";
constexpr char SERIAL_NUMBER[] = "00000001";
constexpr char SW_COMPONENT_ID[] = "matchingAlgorithm";
constexpr char SW_VERSION[] = "vendor/version/revision";
typedef struct fingerprint_hal {
const char* class_name;
} fingerprint_hal_t;
static const fingerprint_hal_t kModules[] = {
{"fortsense"}, {"fpc"}, {"fpc_fod"}, {"goodix"}, {"goodix:gf_fingerprint"},
{"goodix_fod"}, {"goodix_fod6"}, {"silead"}, {"syna"},
};
} // namespace
static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(2, 1);
static Fingerprint* sInstance;
Fingerprint::Fingerprint(std::shared_ptr<FingerprintConfig> config) : mConfig(std::move(config)) {
sInstance = this; // keep track of the most recent instance
if (mDevice) {
ALOGI("fingerprint HAL already opened");
} else {
for (auto& [module] : kModules) {
std::string class_name;
std::string class_module_id;
auto parts = ::android::base::Split(module, ":");
if (parts.size() == 2) {
class_name = parts[0];
class_module_id = parts[1];
} else {
class_name = module;
class_module_id = FINGERPRINT_HARDWARE_MODULE_ID;
}
mDevice = openFingerprintHal(class_name.c_str(), class_module_id.c_str());
if (!mDevice) {
ALOGE("Can't open HAL module, class: %s, module_id: %s", class_name.c_str(),
class_module_id.c_str());
continue;
}
ALOGI("Opened fingerprint HAL, class: %s, module_id: %s", class_name.c_str(),
class_module_id.c_str());
SetProperty("persist.vendor.sys.fp.vendor", class_name);
break;
}
if (!mDevice) {
ALOGE("Can't open any fingerprint HAL module");
SetProperty("persist.vendor.sys.fp.vendor", "none");
}
}
std::string sensorTypeProp = mConfig->get<std::string>("type");
if (sensorTypeProp == "udfps" || sensorTypeProp == "udfps_optical") {
SetProperty("ro.hardware.fp.udfps", "true");
if (sensorTypeProp == "udfps") {
mSensorType = FingerprintSensorType::UNDER_DISPLAY_ULTRASONIC;
} else {
mSensorType = FingerprintSensorType::UNDER_DISPLAY_OPTICAL;
}
mUdfpsHandlerFactory = getUdfpsHandlerFactory();
if (!mUdfpsHandlerFactory) {
ALOGE("Can't get UdfpsHandlerFactory");
} else {
mUdfpsHandler = mUdfpsHandlerFactory->create();
if (!mUdfpsHandler) {
ALOGE("Can't create UdfpsHandler");
} else {
mUdfpsHandler->init(mDevice);
}
}
} else if (sensorTypeProp == "side") {
mSensorType = FingerprintSensorType::POWER_BUTTON;
} else if (sensorTypeProp == "home") {
mSensorType = FingerprintSensorType::HOME_BUTTON;
} else if (sensorTypeProp == "rear") {
mSensorType = FingerprintSensorType::REAR;
} else {
mSensorType = FingerprintSensorType::UNKNOWN;
UNIMPLEMENTED(FATAL) << "unrecognized or unimplemented fingerprint behavior: "
<< sensorTypeProp;
}
ALOGI("sensorTypeProp: %s", sensorTypeProp.c_str());
}
Fingerprint::~Fingerprint() {
ALOGV("~Fingerprint()");
if (mUdfpsHandler) {
mUdfpsHandlerFactory->destroy(mUdfpsHandler);
}
if (mDevice == nullptr) {
ALOGE("No valid device");
return;
}
int err;
if (0 != (err = mDevice->common.close(reinterpret_cast<hw_device_t*>(mDevice)))) {
ALOGE("Can't close fingerprint module, error: %d", err);
return;
}
mDevice = nullptr;
}
fingerprint_device_t* Fingerprint::openFingerprintHal(const char* class_name,
const char* module_id) {
const hw_module_t* hw_mdl = nullptr;
ALOGD("Opening fingerprint hal library...");
if (hw_get_module_by_class(module_id, class_name, &hw_mdl) != 0) {
ALOGE("Can't open fingerprint HW Module");
return nullptr;
}
if (!hw_mdl) {
ALOGE("No valid fingerprint module");
return nullptr;
}
auto module = reinterpret_cast<const fingerprint_module_t*>(hw_mdl);
if (!module->common.methods->open) {
ALOGE("No valid open method");
return nullptr;
}
hw_device_t* device = nullptr;
if (module->common.methods->open(hw_mdl, nullptr, &device) != 0) {
ALOGE("Can't open fingerprint methods");
return nullptr;
}
auto fp_device = reinterpret_cast<fingerprint_device_t*>(device);
if (fp_device->set_notify(fp_device, Fingerprint::notify) != 0) {
ALOGE("Can't register fingerprint module callback");
return nullptr;
}
return fp_device;
}
std::vector<SensorLocation> Fingerprint::getSensorLocations() {
std::vector<SensorLocation> locations;
auto loc = mConfig->get<std::string>("sensor_location");
auto entries = ::android::base::Split(loc, ",");
for (const auto& entry : entries) {
auto isValidStr = false;
auto dim = ::android::base::Split(entry, "|");
if (dim.size() != 3 and dim.size() != 4) {
if (!loc.empty()) {
ALOGE("Invalid sensor location input (x|y|radius) or (x|y|radius|display): %s",
loc.c_str());
}
} else {
int32_t x, y, r;
std::string d;
isValidStr = ParseInt(dim[0], &x) && ParseInt(dim[1], &y) && ParseInt(dim[2], &r);
if (dim.size() == 4) {
d = dim[3];
isValidStr = isValidStr && !d.empty();
}
if (isValidStr)
locations.push_back({.sensorLocationX = x,
.sensorLocationY = y,
.sensorRadius = r,
.display = d});
}
}
return locations;
}
void Fingerprint::notify(const fingerprint_msg_t* msg) {
Fingerprint* thisPtr = sInstance;
if (thisPtr == nullptr || thisPtr->mSession == nullptr || thisPtr->mSession->isClosed()) {
ALOGE("Receiving callbacks before a session is opened.");
return;
}
thisPtr->mSession->notify(msg);
}
ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
std::vector<common::ComponentInfo> componentInfo = {
{HW_COMPONENT_ID, HW_VERSION, FW_VERSION, SERIAL_NUMBER, "" /* softwareVersion */},
{SW_COMPONENT_ID, "" /* hardwareVersion */, "" /* firmwareVersion */,
"" /* serialNumber */, SW_VERSION}};
auto sensorId = mConfig->get<std::int32_t>("sensor_id");
auto sensorStrength = mConfig->get<std::int32_t>("sensor_strength");
auto navigationGuesture = mConfig->get<bool>("navigation_gesture");
auto detectInteraction = mConfig->get<bool>("detect_interaction");
auto displayTouch = mConfig->get<bool>("display_touch");
auto controlIllumination = mConfig->get<bool>("control_illumination");
common::CommonProps commonProps = {sensorId, (common::SensorStrength)sensorStrength,
MAX_ENROLLMENTS_PER_USER, componentInfo};
std::vector<SensorLocation> sensorLocations = getSensorLocations();
std::vector<std::string> sensorLocationStrings;
std::transform(sensorLocations.begin(), sensorLocations.end(),
std::back_inserter(sensorLocationStrings),
[](const SensorLocation& obj) { return obj.toString(); });
ALOGI("sensor type: %s, location: %s", ::android::internal::ToString(mSensorType).c_str(),
::android::base::Join(sensorLocationStrings, ", ").c_str());
*out = {{commonProps, mSensorType, sensorLocations, navigationGuesture, detectInteraction,
displayTouch, controlIllumination, std::nullopt}};
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Fingerprint::createSession(int32_t /*sensorId*/, int32_t userId,
const std::shared_ptr<ISessionCallback>& cb,
std::shared_ptr<ISession>* out) {
CHECK(mSession == nullptr || mSession->isClosed()) << "Open session already exists!";
mSession = SharedRefBase::make<Session>(mDevice, mUdfpsHandler, userId, cb, mLockoutTracker);
*out = mSession;
mSession->linkToDeath(cb->asBinder().get());
return ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2024 The LineageOS Project
* 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/android/hardware/biometrics/fingerprint/BnFingerprint.h>
#include "FingerprintConfig.h"
#include "LockoutTracker.h"
#include "Session.h"
#include "UdfpsHandler.h"
using ::aidl::android::hardware::biometrics::fingerprint::FingerprintSensorType;
using ::aidl::android::hardware::biometrics::fingerprint::ISession;
using ::aidl::android::hardware::biometrics::fingerprint::ISessionCallback;
using ::aidl::android::hardware::biometrics::fingerprint::SensorProps;
namespace aidl::android::hardware::biometrics::fingerprint {
class Fingerprint : public BnFingerprint {
public:
Fingerprint(std::shared_ptr<FingerprintConfig> config);
~Fingerprint();
ndk::ScopedAStatus getSensorProps(std::vector<SensorProps>* _aidl_return) override;
ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
const std::shared_ptr<ISessionCallback>& cb,
std::shared_ptr<ISession>* out) override;
private:
fingerprint_device_t* openFingerprintHal(const char* class_name, const char* module_id);
std::vector<SensorLocation> getSensorLocations();
static void notify(const fingerprint_msg_t* msg);
std::shared_ptr<FingerprintConfig> mConfig;
std::shared_ptr<Session> mSession;
LockoutTracker mLockoutTracker;
FingerprintSensorType mSensorType;
fingerprint_device_t* mDevice;
UdfpsHandlerFactory* mUdfpsHandlerFactory;
UdfpsHandler* mUdfpsHandler;
};
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2024 The Android Open Source Project
* 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "FingerprintConfig"
#include "FingerprintConfig.h"
#include <android-base/logging.h>
#include <fingerprint.sysprop.h>
using namespace ::android::fingerprint::xiaomi;
namespace aidl::android::hardware::biometrics::fingerprint {
// Wrapper to system property access functions
#define CREATE_GETTER_SETTER_WRAPPER(_NAME_, _T_) \
ConfigValue _NAME_##Getter() { \
return FingerprintHalProperties::_NAME_(); \
} \
bool _NAME_##Setter(const ConfigValue& v) { \
return FingerprintHalProperties::_NAME_(std::get<_T_>(v)); \
}
CREATE_GETTER_SETTER_WRAPPER(type, OptString)
CREATE_GETTER_SETTER_WRAPPER(sensor_id, OptInt32)
CREATE_GETTER_SETTER_WRAPPER(sensor_location, OptString)
CREATE_GETTER_SETTER_WRAPPER(sensor_strength, OptInt32)
CREATE_GETTER_SETTER_WRAPPER(navigation_gesture, OptBool)
CREATE_GETTER_SETTER_WRAPPER(detect_interaction, OptBool)
CREATE_GETTER_SETTER_WRAPPER(display_touch, OptBool)
CREATE_GETTER_SETTER_WRAPPER(control_illumination, OptBool)
// Name, Getter, Setter, Parser and default value
#define NGS(_NAME_) #_NAME_, _NAME_##Getter, _NAME_##Setter
static Config::Data configData[] = {
{NGS(type), &Config::parseString, ""},
{NGS(sensor_id), &Config::parseInt32, "0"},
{NGS(sensor_location), &Config::parseString, ""},
{NGS(sensor_strength), &Config::parseInt32, "2"}, // STRONG
{NGS(navigation_gesture), &Config::parseBool, "false"},
{NGS(detect_interaction), &Config::parseBool, "false"},
{NGS(display_touch), &Config::parseBool, "false"},
{NGS(control_illumination), &Config::parseBool, "false"},
};
Config::Data* FingerprintConfig::getConfigData(int* size) {
*size = sizeof(configData) / sizeof(configData[0]);
return configData;
}
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) 2024 The Android Open Source Project
* 2024 Paranoid Android
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "config/Config.h"
namespace aidl::android::hardware::biometrics::fingerprint {
class FingerprintConfig : public Config {
Config::Data* getConfigData(int* size) override;
};
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "LockoutTracker.h"
#include <fingerprint.sysprop.h>
#include "Fingerprint.h"
#include "util/Util.h"
using namespace ::android::fingerprint::xiaomi;
namespace aidl::android::hardware::biometrics::fingerprint {
void LockoutTracker::reset(bool clearAttemptCounter) {
if (clearAttemptCounter) {
mFailedCount = 0;
}
mLockoutTimedStart = 0;
mCurrentMode = LockoutMode::kNone;
}
void LockoutTracker::addFailedAttempt() {
mFailedCount++;
if (mFailedCount >= LOCKOUT_PERMANENT_THRESHOLD) {
mCurrentMode = LockoutMode::kPermanent;
} else if (mFailedCount >= LOCKOUT_TIMED_THRESHOLD) {
if (mCurrentMode == LockoutMode::kNone) {
mCurrentMode = LockoutMode::kTimed;
mLockoutTimedStart = Util::getSystemNanoTime();
}
}
}
LockoutTracker::LockoutMode LockoutTracker::getMode() {
if (mCurrentMode == LockoutMode::kTimed) {
if (Util::hasElapsed(mLockoutTimedStart, LOCKOUT_TIMED_DURATION)) {
mCurrentMode = LockoutMode::kNone;
mLockoutTimedStart = 0;
}
}
return mCurrentMode;
}
int64_t LockoutTracker::getLockoutTimeLeft() {
int64_t res = 0;
if (mLockoutTimedStart > 0) {
auto now = Util::getSystemNanoTime();
auto elapsed = (now - mLockoutTimedStart) / 1000000LL;
res = LOCKOUT_TIMED_DURATION - elapsed;
LOG(INFO) << "elapsed=" << elapsed << " now = " << now
<< " mLockoutTimedStart=" << mLockoutTimedStart << " res=" << res;
}
return res;
}
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2022 The Android Open Source Project
* 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <android/binder_to_string.h>
#include <stdint.h>
#include <string>
#define LOCKOUT_TIMED_THRESHOLD 5
#define LOCKOUT_TIMED_DURATION 10000
#define LOCKOUT_PERMANENT_THRESHOLD 20
namespace aidl::android::hardware::biometrics::fingerprint {
class LockoutTracker {
public:
LockoutTracker() : mFailedCount(0) {}
~LockoutTracker() {}
enum class LockoutMode : int8_t { kNone = 0, kTimed, kPermanent };
void reset(bool clearAttemptCounter);
LockoutMode getMode();
void addFailedAttempt();
int64_t getLockoutTimeLeft();
inline std::string toString() const {
std::ostringstream os;
os << "----- LockoutTracker:: -----" << std::endl;
os << "LockoutTracker::mFailedCount:" << mFailedCount;
os << ", LockoutTracker::mCurrentMode:" << (int)mCurrentMode;
os << std::endl;
return os.str();
}
private:
int32_t mFailedCount;
int64_t mLockoutTimedStart;
LockoutMode mCurrentMode;
};
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,394 @@
/*
* Copyright (C) 2024-2025 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <thread>
#include "Legacy2Aidl.h"
#include "Session.h"
#include "CancellationSignal.h"
namespace aidl::android::hardware::biometrics::fingerprint {
void onClientDeath(void* cookie) {
ALOGI("FingerprintService has died");
Session* session = static_cast<Session*>(cookie);
if (session && !session->isClosed()) {
session->close();
}
}
Session::Session(fingerprint_device_t* device, UdfpsHandler* udfpsHandler, int userId,
std::shared_ptr<ISessionCallback> cb, LockoutTracker lockoutTracker)
: mDevice(device),
mLockoutTracker(lockoutTracker),
mUserId(userId),
mCb(cb),
mUdfpsHandler(udfpsHandler) {
mDeathRecipient = AIBinder_DeathRecipient_new(onClientDeath);
auto path = std::format("/data/vendor_de/{}/fpdata/", userId);
mDevice->set_active_group(mDevice, mUserId, path.c_str());
}
ndk::ScopedAStatus Session::generateChallenge() {
uint64_t challenge = mDevice->pre_enroll(mDevice);
ALOGI("generateChallenge: %ld", challenge);
mCb->onChallengeGenerated(challenge);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::revokeChallenge(int64_t challenge) {
ALOGI("revokeChallenge: %ld", challenge);
mDevice->post_enroll(mDevice);
mCb->onChallengeRevoked(challenge);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::enroll(const HardwareAuthToken& hat,
std::shared_ptr<ICancellationSignal>* out) {
hw_auth_token_t authToken;
translate(hat, authToken);
int error = mDevice->enroll(mDevice, &authToken, mUserId, 60);
if (error) {
ALOGE("enroll failed: %d", error);
mCb->onError(Error::UNABLE_TO_PROCESS, error);
}
*out = SharedRefBase::make<CancellationSignal>(this);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::authenticate(int64_t operationId,
std::shared_ptr<ICancellationSignal>* out) {
checkSensorLockout();
int error = mDevice->authenticate(mDevice, operationId, mUserId);
if (error) {
ALOGE("authenticate failed: %d", error);
mCb->onError(Error::UNABLE_TO_PROCESS, error);
}
*out = SharedRefBase::make<CancellationSignal>(this);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::detectInteraction(std::shared_ptr<ICancellationSignal>* out) {
ALOGD("Detect interaction is not supported");
mCb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
*out = SharedRefBase::make<CancellationSignal>(this);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::enumerateEnrollments() {
int error = mDevice->enumerate(mDevice);
if (error) {
ALOGE("enumerate failed: %d", error);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& enrollmentIds) {
ALOGI("removeEnrollments, size: %zu", enrollmentIds.size());
for (int32_t fid : enrollmentIds) {
int error = mDevice->remove(mDevice, mUserId, fid);
if (error) {
ALOGE("remove failed: %d", error);
}
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::getAuthenticatorId() {
uint64_t auth_id = mDevice->get_authenticator_id(mDevice);
ALOGI("getAuthenticatorId: %ld", auth_id);
mCb->onAuthenticatorIdRetrieved(auth_id);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
uint64_t auth_id = mDevice->get_authenticator_id(mDevice);
ALOGI("invalidateAuthenticatorId: %ld", auth_id);
mCb->onAuthenticatorIdInvalidated(auth_id);
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::resetLockout(const HardwareAuthToken& /*hat*/) {
clearLockout(true);
if (mIsLockoutTimerStarted) mIsLockoutTimerAborted = true;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::onPointerDown(int32_t /*pointerId*/, int32_t x, int32_t y, float minor,
float major) {
if (mUdfpsHandler) {
mUdfpsHandler->onFingerDown(x, y, minor, major);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::onPointerUp(int32_t /*pointerId*/) {
if (mUdfpsHandler) {
mUdfpsHandler->onFingerUp();
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::onUiReady() {
// TODO: stub
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::authenticateWithContext(
int64_t operationId, const common::OperationContext& /*context*/,
std::shared_ptr<common::ICancellationSignal>* out) {
return authenticate(operationId, out);
}
ndk::ScopedAStatus Session::enrollWithContext(const keymaster::HardwareAuthToken& hat,
const common::OperationContext& /*context*/,
std::shared_ptr<common::ICancellationSignal>* out) {
return enroll(hat, out);
}
ndk::ScopedAStatus Session::detectInteractionWithContext(
const common::OperationContext& /*context*/,
std::shared_ptr<common::ICancellationSignal>* out) {
return detectInteraction(out);
}
ndk::ScopedAStatus Session::onPointerDownWithContext(const PointerContext& context) {
return onPointerDown(context.pointerId, context.x, context.y, context.minor, context.major);
}
ndk::ScopedAStatus Session::onPointerUpWithContext(const PointerContext& context) {
return onPointerUp(context.pointerId);
}
ndk::ScopedAStatus Session::onContextChanged(const common::OperationContext& /*context*/) {
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::onPointerCancelWithContext(const PointerContext& /*context*/) {
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::setIgnoreDisplayTouches(bool /*shouldIgnore*/) {
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Session::cancel() {
if (mUdfpsHandler) {
mUdfpsHandler->cancel();
}
int ret = mDevice->cancel(mDevice);
if (ret == 0) {
mCb->onError(Error::CANCELED, 0 /* vendorCode */);
return ndk::ScopedAStatus::ok();
}
return ndk::ScopedAStatus::fromServiceSpecificError(ret);
}
ndk::ScopedAStatus Session::close() {
mClosed = true;
mCb->onSessionClosed();
AIBinder_DeathRecipient_delete(mDeathRecipient);
return ndk::ScopedAStatus::ok();
}
binder_status_t Session::linkToDeath(AIBinder* binder) {
return AIBinder_linkToDeath(binder, mDeathRecipient, this);
}
bool Session::isClosed() {
return mClosed;
}
// Translate from errors returned by traditional HAL (see fingerprint.h) to
// AIDL-compliant Error
Error Session::VendorErrorFilter(int32_t error, int32_t* vendorCode) {
*vendorCode = 0;
switch (error) {
case FINGERPRINT_ERROR_HW_UNAVAILABLE:
return Error::HW_UNAVAILABLE;
case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
return Error::UNABLE_TO_PROCESS;
case FINGERPRINT_ERROR_TIMEOUT:
return Error::TIMEOUT;
case FINGERPRINT_ERROR_NO_SPACE:
return Error::NO_SPACE;
case FINGERPRINT_ERROR_CANCELED:
return Error::CANCELED;
case FINGERPRINT_ERROR_UNABLE_TO_REMOVE:
return Error::UNABLE_TO_REMOVE;
case FINGERPRINT_ERROR_LOCKOUT: {
*vendorCode = FINGERPRINT_ERROR_LOCKOUT;
return Error::VENDOR;
}
default:
if (error >= FINGERPRINT_ERROR_VENDOR_BASE) {
// vendor specific code.
*vendorCode = error - FINGERPRINT_ERROR_VENDOR_BASE;
return Error::VENDOR;
}
}
ALOGE("Unknown error from fingerprint vendor library: %d", error);
return Error::UNABLE_TO_PROCESS;
}
// Translate acquired messages returned by traditional HAL (see fingerprint.h)
// to AIDL-compliant AcquiredInfo
AcquiredInfo Session::VendorAcquiredFilter(int32_t info, int32_t* vendorCode) {
*vendorCode = 0;
switch (info) {
case FINGERPRINT_ACQUIRED_GOOD:
return AcquiredInfo::GOOD;
case FINGERPRINT_ACQUIRED_PARTIAL:
return AcquiredInfo::PARTIAL;
case FINGERPRINT_ACQUIRED_INSUFFICIENT:
return AcquiredInfo::INSUFFICIENT;
case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
return AcquiredInfo::SENSOR_DIRTY;
case FINGERPRINT_ACQUIRED_TOO_SLOW:
return AcquiredInfo::TOO_SLOW;
case FINGERPRINT_ACQUIRED_TOO_FAST:
return AcquiredInfo::TOO_FAST;
default:
if (info >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
// vendor specific code.
*vendorCode = info - FINGERPRINT_ACQUIRED_VENDOR_BASE;
return AcquiredInfo::VENDOR;
}
}
ALOGE("Unknown acquired message from fingerprint vendor library: %d", info);
return AcquiredInfo::UNKNOWN;
}
bool Session::checkSensorLockout() {
LockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
if (lockoutMode == LockoutTracker::LockoutMode::kPermanent) {
ALOGE("Fail: lockout permanent");
mCb->onLockoutPermanent();
mIsLockoutTimerAborted = true;
return true;
}
if (lockoutMode == LockoutTracker::LockoutMode::kTimed) {
int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
ALOGE("Fail: lockout timed: %ld", timeLeft);
mCb->onLockoutTimed(timeLeft);
if (!mIsLockoutTimerStarted) startLockoutTimer(timeLeft);
return true;
}
return false;
}
void Session::clearLockout(bool clearAttemptCounter) {
mLockoutTracker.reset(clearAttemptCounter);
mCb->onLockoutCleared();
}
void Session::startLockoutTimer(int64_t timeout) {
std::function<void()> action = std::bind(&Session::lockoutTimerExpired, this);
std::thread([timeout, action]() {
std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
action();
}).detach();
mIsLockoutTimerStarted = true;
}
void Session::lockoutTimerExpired() {
if (!mIsLockoutTimerAborted) clearLockout(false);
mIsLockoutTimerStarted = false;
mIsLockoutTimerAborted = false;
}
void Session::notify(const fingerprint_msg_t* msg) {
// const uint64_t devId = reinterpret_cast<uint64_t>(mDevice);
switch (msg->type) {
case FINGERPRINT_ERROR: {
int32_t vendorCode = 0;
Error result = VendorErrorFilter(msg->data.error, &vendorCode);
ALOGD("onError(%hhd, %d)", result, vendorCode);
mCb->onError(result, vendorCode);
} break;
case FINGERPRINT_ACQUIRED: {
int32_t vendorCode = 0;
AcquiredInfo result =
VendorAcquiredFilter(msg->data.acquired.acquired_info, &vendorCode);
ALOGD("onAcquired(%hhd, %d)", result, vendorCode);
if (mUdfpsHandler) {
mUdfpsHandler->onAcquired(static_cast<int32_t>(result), vendorCode);
}
// don't process vendor messages further since frameworks try to disable
// udfps display mode on vendor acquired messages but our sensors send a
// vendor message during processing...
if (result != AcquiredInfo::VENDOR) {
mCb->onAcquired(result, vendorCode);
}
} break;
case FINGERPRINT_TEMPLATE_ENROLLING: {
ALOGD("onEnrollResult(fid=%d, gid=%d, rem=%d)", msg->data.enroll.finger.fid,
msg->data.enroll.finger.gid, msg->data.enroll.samples_remaining);
mCb->onEnrollmentProgress(msg->data.enroll.finger.fid,
msg->data.enroll.samples_remaining);
} break;
case FINGERPRINT_TEMPLATE_REMOVED: {
ALOGD("onRemove(fid=%d, gid=%d, rem=%d)", msg->data.removed.finger.fid,
msg->data.removed.finger.gid, msg->data.removed.remaining_templates);
std::vector<int> enrollments;
enrollments.push_back(msg->data.removed.finger.fid);
mCb->onEnrollmentsRemoved(enrollments);
} break;
case FINGERPRINT_AUTHENTICATED: {
ALOGD("onAuthenticated(fid=%d, gid=%d)", msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid);
if (msg->data.authenticated.finger.fid != 0) {
const hw_auth_token_t hat = msg->data.authenticated.hat;
HardwareAuthToken authToken;
translate(hat, authToken);
if (mUdfpsHandler) {
mUdfpsHandler->onAuthenticationSucceeded();
}
mCb->onAuthenticationSucceeded(msg->data.authenticated.finger.fid, authToken);
mLockoutTracker.reset(true);
} else {
if (mUdfpsHandler) {
mUdfpsHandler->onAuthenticationFailed();
}
mCb->onAuthenticationFailed();
mLockoutTracker.addFailedAttempt();
checkSensorLockout();
}
} break;
case FINGERPRINT_TEMPLATE_ENUMERATING: {
ALOGD("onEnumerate(fid=%d, gid=%d, rem=%d)", msg->data.enumerated.finger.fid,
msg->data.enumerated.finger.gid, msg->data.enumerated.remaining_templates);
static std::vector<int> enrollments;
enrollments.push_back(msg->data.enumerated.finger.fid);
if (msg->data.enumerated.remaining_templates == 0) {
mCb->onEnrollmentsEnumerated(enrollments);
enrollments.clear();
}
} break;
}
}
} // namespace aidl::android::hardware::biometrics::fingerprint

100
aidl/fingerprint/Session.h Normal file
View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#define LOG_TAG "android.hardware.biometrics.fingerprint-service.xiaomi"
#include <aidl/android/hardware/biometrics/fingerprint/BnSession.h>
#include <aidl/android/hardware/biometrics/fingerprint/ISessionCallback.h>
#include <android/log.h>
#include <hardware/hardware.h>
#include <log/log.h>
#include "fingerprint.h"
#include "LockoutTracker.h"
#include "UdfpsHandler.h"
using ::aidl::android::hardware::biometrics::common::ICancellationSignal;
using ::aidl::android::hardware::biometrics::common::OperationContext;
using ::aidl::android::hardware::biometrics::fingerprint::PointerContext;
using ::aidl::android::hardware::keymaster::HardwareAuthToken;
namespace aidl::android::hardware::biometrics::fingerprint {
void onClientDeath(void* cookie);
class Session : public BnSession {
public:
Session(fingerprint_device_t* device, UdfpsHandler* udfpsHandler, int userId,
std::shared_ptr<ISessionCallback> cb, LockoutTracker lockoutTracker);
ndk::ScopedAStatus generateChallenge() override;
ndk::ScopedAStatus revokeChallenge(int64_t challenge) override;
ndk::ScopedAStatus enroll(const HardwareAuthToken& hat,
std::shared_ptr<ICancellationSignal>* out) override;
ndk::ScopedAStatus authenticate(int64_t operationId,
std::shared_ptr<ICancellationSignal>* out) override;
ndk::ScopedAStatus detectInteraction(std::shared_ptr<ICancellationSignal>* out) override;
ndk::ScopedAStatus enumerateEnrollments() override;
ndk::ScopedAStatus removeEnrollments(const std::vector<int32_t>& enrollmentIds) override;
ndk::ScopedAStatus getAuthenticatorId() override;
ndk::ScopedAStatus invalidateAuthenticatorId() override;
ndk::ScopedAStatus resetLockout(const HardwareAuthToken& hat) override;
ndk::ScopedAStatus close() override;
ndk::ScopedAStatus onPointerDown(int32_t pointerId, int32_t x, int32_t y, float minor,
float major) override;
ndk::ScopedAStatus onPointerUp(int32_t pointerId) override;
ndk::ScopedAStatus onUiReady() override;
ndk::ScopedAStatus authenticateWithContext(int64_t operationId, const OperationContext& context,
std::shared_ptr<ICancellationSignal>* out) override;
ndk::ScopedAStatus enrollWithContext(const HardwareAuthToken& hat,
const OperationContext& context,
std::shared_ptr<ICancellationSignal>* out) override;
ndk::ScopedAStatus detectInteractionWithContext(
const OperationContext& context, std::shared_ptr<ICancellationSignal>* out) override;
ndk::ScopedAStatus onPointerDownWithContext(const PointerContext& context) override;
ndk::ScopedAStatus onPointerUpWithContext(const PointerContext& context) override;
ndk::ScopedAStatus onContextChanged(const OperationContext& context) override;
ndk::ScopedAStatus onPointerCancelWithContext(const PointerContext& context) override;
ndk::ScopedAStatus setIgnoreDisplayTouches(bool shouldIgnore) override;
ndk::ScopedAStatus cancel();
binder_status_t linkToDeath(AIBinder* binder);
bool isClosed();
void notify(const fingerprint_msg_t* msg);
private:
fingerprint_device_t* mDevice;
LockoutTracker mLockoutTracker;
bool mClosed = false;
// static ndk::ScopedAStatus ErrorFilter(int32_t error);
static Error VendorErrorFilter(int32_t error, int32_t* vendorCode);
static AcquiredInfo VendorAcquiredFilter(int32_t info, int32_t* vendorCode);
bool checkSensorLockout();
void clearLockout(bool clearAttemptCounter);
void startLockoutTimer(int64_t timeout);
void lockoutTimerExpired();
// lockout timer
bool mIsLockoutTimerStarted = false;
bool mIsLockoutTimerAborted = false;
// The user ID for which this session was created.
int32_t mUserId;
// Callback for talking to the framework. This callback must only be called from non-binder
// threads to prevent nested binder calls and consequently a binder thread exhaustion.
// Practically, it means that this callback should always be called from the worker thread.
std::shared_ptr<ISessionCallback> mCb;
// Binder death handler.
AIBinder_DeathRecipient* mDeathRecipient;
UdfpsHandler* mUdfpsHandler;
};
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,10 @@
service vendor.fingerprint-default /vendor/bin/hw/android.hardware.biometrics.fingerprint-service.xiaomi
# "class hal" causes a race condition on some devices due to files created
# in /data. As a workaround, postpone startup until later in boot once
# /data is mounted.
class late_start
user system
group system input uhid
capabilities SYS_NICE
shutdown critical
task_profiles ProcessCapacityHigh MaxPerformance

View File

@@ -0,0 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.biometrics.fingerprint</name>
<version>4</version>
<fqname>IFingerprint/default</fqname>
</hal>
</manifest>

View File

@@ -0,0 +1,79 @@
# fingerprint.sysprop
# module becomes static class (Java) / namespace (C++) for serving API
module: "android.fingerprint.xiaomi.FingerprintHalProperties"
owner: Vendor
# type of fingerprint sensor (default: none)
prop {
prop_name: "persist.vendor.fingerprint.type"
type: String
scope: Internal
access: ReadWrite
enum_values: "udfps|udfps_optical|side|home|rear"
api_name: "type"
}
# sensor location
# <x>|<y>|<radius>|<display> in pixel, can have multiple values separated by comma
prop {
prop_name: "persist.vendor.fingerprint.sensor_location"
type: String
scope: Internal
access: ReadWrite
api_name: "sensor_location"
}
# sensor id (default: 0)
prop {
prop_name: "persist.vendor.fingerprint.sensor_id"
type: Integer
scope: Internal
access: ReadWrite
api_name: "sensor_id"
}
# sensor strength (default: 2)
# [0=CONVENIENCE, 1=WEAK, 2=STRONG]
prop {
prop_name: "persist.vendor.fingerprint.sensor_strength"
type: Integer
scope: Internal
access: ReadWrite
api_name: "sensor_strength"
}
# whether support navigation guestures (default: false)
prop {
prop_name: "persist.vendor.fingerprint.navigation_gesture"
type: Boolean
scope: Internal
access: ReadWrite
api_name: "navigation_gesture"
}
# whether support detect interaction (default: false)
prop {
prop_name: "persist.vendor.fingerprint.detect_interaction"
type: Boolean
scope: Internal
access: ReadWrite
api_name: "detect_interaction"
}
# whether support display touch by hal (default: false)
prop {
prop_name: "persist.vendor.fingerprint.udfps.display_touch"
type: Boolean
scope: Internal
access: ReadWrite
api_name: "display_touch"
}
# whether support illumination control by hal (default: false)
prop {
prop_name: "persist.vendor.fingerprint.udfps.control_illumination"
type: Boolean
scope: Internal
access: ReadWrite
api_name: "control_illumination"
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/android/hardware/keymaster/HardwareAuthToken.h>
#include <hardware/hw_auth_token.h>
#include <endian.h>
namespace aidl::android::hardware::biometrics::fingerprint {
inline void translate(const ::aidl::android::hardware::keymaster::HardwareAuthToken& authToken,
hw_auth_token_t& hat) {
hat.challenge = authToken.challenge;
hat.user_id = authToken.userId;
hat.authenticator_id = authToken.authenticatorId;
// these are in host order: translate to network order
hat.authenticator_type = htobe32(static_cast<uint32_t>(authToken.authenticatorType));
hat.timestamp = htobe64(authToken.timestamp.milliSeconds);
std::copy(authToken.mac.begin(), authToken.mac.end(), hat.hmac);
}
inline void translate(const hw_auth_token_t& hat,
::aidl::android::hardware::keymaster::HardwareAuthToken& authToken) {
authToken.challenge = hat.challenge;
authToken.userId = hat.user_id;
authToken.authenticatorId = hat.authenticator_id;
// these are in network order: translate to host
authToken.authenticatorType =
static_cast<::aidl::android::hardware::keymaster::HardwareAuthenticatorType>(
be32toh(hat.authenticator_type));
authToken.timestamp.milliSeconds = be64toh(hat.timestamp);
authToken.mac.insert(authToken.mac.begin(), std::begin(hat.hmac), std::end(hat.hmac));
}
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Fingerprint.h"
#include "FingerprintConfig.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using ::aidl::android::hardware::biometrics::fingerprint::Fingerprint;
using ::aidl::android::hardware::biometrics::fingerprint::FingerprintConfig;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<FingerprintConfig> config = std::make_shared<FingerprintConfig>();
config->init();
std::shared_ptr<Fingerprint> fingerprint = ndk::SharedRefBase::make<Fingerprint>(config);
const std::string instance = std::string() + Fingerprint::descriptor + "/default";
binder_status_t status =
AServiceManager_addService(fingerprint->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}

48
aidl/health/Android.bp Normal file
View File

@@ -0,0 +1,48 @@
cc_defaults {
name: "android.hardware.health-service.xiaomi-defaults",
relative_install_path: "hw",
vintf_fragments: ["android.hardware.health-service.xiaomi.xml"],
vendor: true,
recovery_available: true,
defaults: [
"libhealth_aidl_impl_user",
],
include_dirs: [
"system/core/healthd",
"system/core/healthd/include",
"system/core/healthd/include_charger"
],
static_libs: [
"libhealth_aidl_impl",
],
srcs: [
"main.cpp",
],
cflags: [
"-Wall",
"-Werror",
],
}
cc_binary {
name: "android.hardware.health-service.xiaomi",
recovery: false,
vendor: true,
defaults: ["android.hardware.health-service.xiaomi-defaults"],
init_rc: ["android.hardware.health-service.xiaomi.rc"],
overrides: ["charger","android.hardware.health-service.qti"],
}
cc_binary {
name: "android.hardware.health-service.xiaomi_recovery",
vendor: false,
recovery: true,
defaults: ["android.hardware.health-service.xiaomi-defaults"],
init_rc: ["android.hardware.health-service.xiaomi_recovery.rc"],
overrides: ["charger.recovery", "android.hardware.health-service.qti_recovery"],
}

View File

@@ -0,0 +1,14 @@
service vendor.health-default /vendor/bin/hw/android.hardware.health-service.xiaomi
class hal
user system
group system
capabilities WAKE_ALARM BLOCK_SUSPEND
file /dev/kmsg w
service vendor.charger /vendor/bin/hw/android.hardware.health-service.xiaomi --charger
class charger
seclabel u:r:charger_vendor:s0
user system
group system wakelock input graphics
capabilities SYS_BOOT WAKE_ALARM BLOCK_SUSPEND
file /dev/kmsg w

View File

@@ -0,0 +1,12 @@
<!--
Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear
-->
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.health</name>
<version>3</version>
<fqname>IHealth/default</fqname>
</hal>
</manifest>

View File

@@ -0,0 +1,7 @@
service vendor.health-recovery /system/bin/hw/android.hardware.health-service.xiaomi_recovery
class hal
seclabel u:r:hal_health_default:s0
user system
group system
capabilities WAKE_ALARM BLOCK_SUSPEND
file /dev/kmsg w

123
aidl/health/main.cpp Normal file
View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#define LOG_TAG "android.hardware.health-service.xiaomi"
#include <android-base/logging.h>
#include <android/binder_interface_utils.h>
#include <health/utils.h>
#include <health-impl/ChargerUtils.h>
#include <health-impl/Health.h>
#include <cutils/klog.h>
using aidl::android::hardware::health::HalHealthLoop;
using aidl::android::hardware::health::Health;
#if !CHARGER_FORCE_NO_UI
using aidl::android::hardware::health::charger::ChargerCallback;
using aidl::android::hardware::health::charger::ChargerModeMain;
namespace aidl::android::hardware::health {
class ChargerCallbackImpl : public ChargerCallback {
public:
ChargerCallbackImpl(const std::shared_ptr<Health>& service) : ChargerCallback(service) {}
bool ChargerEnableSuspend() override { return true; }
};
} //namespace aidl::android::hardware::health
#endif
namespace aidl::android::hardware::health {
static constexpr int kChargeCounterMultiplier = 1000; // mAh to uAh
static constexpr int kChargeTimeToFullMultiplier = 60; // mins to secs
class HealthImpl : public Health {
public:
using Health::Health;
virtual ~HealthImpl() {}
ndk::ScopedAStatus getChargeCounterUah(int32_t* out) override;
protected:
void UpdateHealthInfo(HealthInfo* health_info) override;
};
void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
if (health_info->batteryChargeTimeToFullNowSeconds == 65535) {
health_info->batteryChargeTimeToFullNowSeconds = -1;
} else {
health_info->batteryChargeTimeToFullNowSeconds *= kChargeTimeToFullMultiplier;
}
health_info->batteryChargeCounterUah *= kChargeCounterMultiplier;
}
ndk::ScopedAStatus HealthImpl::getChargeCounterUah(int32_t* out) {
*out *= kChargeCounterMultiplier;
return ndk::ScopedAStatus::ok();
}
} // namespace aidl::android::hardware::health
static constexpr const char* gInstanceName = "default";
static constexpr std::string_view gChargerArg{"--charger"};
constexpr char ucsiPSYName[]{"ucsi-source-psy-soc:qcom,pmic_glink:qcom,ucsi1"};
#define RETRY_COUNT 100
void qti_healthd_board_init(struct healthd_config *hc)
{
int fd;
unsigned char retries = RETRY_COUNT;
int ret = 0;
unsigned char buf;
hc->ignorePowerSupplyNames.push_back(android::String8(ucsiPSYName));
retry:
if (!retries) {
KLOG_ERROR(LOG_TAG, "Cannot open battery/capacity, fd=%d\n", fd);
return;
}
fd = open("/sys/class/power_supply/battery/capacity", 0440);
if (fd >= 0) {
KLOG_INFO(LOG_TAG, "opened battery/capacity after %d retries\n", RETRY_COUNT - retries);
while (retries) {
ret = read(fd, &buf, 1);
if(ret >= 0) {
KLOG_INFO(LOG_TAG, "Read Batt Capacity after %d retries ret : %d\n", RETRY_COUNT - retries, ret);
close(fd);
return;
}
retries--;
usleep(100000);
}
KLOG_ERROR(LOG_TAG, "Failed to read Battery Capacity ret=%d\n", ret);
close(fd);
return;
}
retries--;
usleep(100000);
goto retry;
}
int main(int argc, char** argv) {
#ifdef __ANDROID_RECOVERY__
android::base::InitLogging(argv, android::base::KernelLogger);
#endif
auto config = std::make_unique<healthd_config>();
qti_healthd_board_init(config.get());
::android::hardware::health::InitHealthdConfig(config.get());
auto binder = ndk::SharedRefBase::make<aidl::android::hardware::health::HealthImpl>(gInstanceName, std::move(config));
if (argc >= 2 && argv[1] == gChargerArg) {
#if !CHARGER_FORCE_NO_UI
KLOG_INFO(LOG_TAG, "Starting charger mode with UI.");
auto charger_callback = std::make_shared<aidl::android::hardware::health::ChargerCallbackImpl>(binder);
return ChargerModeMain(binder, charger_callback);
#endif
KLOG_INFO(LOG_TAG, "Starting charger mode without UI.");
} else {
KLOG_INFO(LOG_TAG, "Starting health HAL.");
}
auto hal_health_loop = std::make_shared<HalHealthLoop>(binder, binder);
return hal_health_loop->StartLoop();
}

View File

@@ -1,21 +0,0 @@
//
// SPDX-FileCopyrightText: 2024 The LineageOS Project
// SPDX-License-Identifier: Apache-2.0
//
cc_binary {
name: "android.hardware.ir-service.xiaomi",
relative_install_path: "hw",
vendor: true,
init_rc: ["android.hardware.ir-service.xiaomi.rc"],
vintf_fragments: ["android.hardware.ir-service.xiaomi.xml"],
srcs: [
"ConsumerIr.cpp",
"service.cpp",
],
shared_libs: [
"libbase",
"libbinder_ndk",
"android.hardware.ir-V1-ndk",
],
}

View File

@@ -1,80 +0,0 @@
/*
* SPDX-FileCopyrightText: 2017-2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "ConsumerIr"
#include "ConsumerIr.h"
#include <android-base/logging.h>
#include <fcntl.h>
#include <linux/lirc.h>
#include <string>
using std::vector;
namespace aidl {
namespace android {
namespace hardware {
namespace ir {
static const std::string kIrDevice = "/dev/lirc0";
static vector<ConsumerIrFreqRange> kRangeVec{
{.minHz = 30000, .maxHz = 60000},
};
::ndk::ScopedAStatus ConsumerIr::getCarrierFreqs(vector<ConsumerIrFreqRange>* _aidl_return) {
*_aidl_return = kRangeVec;
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus ConsumerIr::transmit(int32_t carrierFreqHz, const vector<int32_t>& pattern) {
size_t entries = pattern.size();
if (entries == 0) {
return ::ndk::ScopedAStatus::ok();
}
int fd = open(kIrDevice.c_str(), O_RDWR);
if (fd < 0) {
LOG(ERROR) << "Failed to open " << kIrDevice << ", error " << fd;
return ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
int rc = ioctl(fd, LIRC_SET_SEND_CARRIER, &carrierFreqHz);
if (rc < 0) {
LOG(ERROR) << "Failed to set carrier " << carrierFreqHz << ", error: " << errno;
close(fd);
return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
if ((entries & 1) != 0) {
rc = write(fd, pattern.data(), entries * sizeof(int32_t));
} else {
rc = write(fd, pattern.data(), (entries - 1) * sizeof(int32_t));
usleep(pattern[entries - 1]);
}
if (rc < 0) {
LOG(ERROR) << "Failed to write pattern, " << entries << " entries, error: " << errno;
close(fd);
return ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
close(fd);
return ::ndk::ScopedAStatus::ok();
}
} // namespace ir
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,27 +0,0 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/android/hardware/ir/BnConsumerIr.h>
namespace aidl {
namespace android {
namespace hardware {
namespace ir {
class ConsumerIr : public BnConsumerIr {
public:
::ndk::ScopedAStatus getCarrierFreqs(
::std::vector<::aidl::android::hardware::ir::ConsumerIrFreqRange>* _aidl_return)
override;
::ndk::ScopedAStatus transmit(int32_t carrierFreqHz,
const ::std::vector<int32_t>& pattern) override;
};
} // namespace ir
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,14 +0,0 @@
#
# SPDX-FileCopyrightText: 2024 The LineageOS Project
# SPDX-License-Identifier: Apache-2.0
#
on early-boot
# IR device
chown system system /dev/lirc0
service vendor.ir-default /vendor/bin/hw/android.hardware.ir-service.xiaomi
class hal
user system
group system
shutdown critical

View File

@@ -1,11 +0,0 @@
<!--
SPDX-FileCopyrightText: 2024 The LineageOS Project
SPDX-License-Identifier: Apache-2.0
-->
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.ir</name>
<version>1</version>
<fqname>IConsumerIr/default</fqname>
</hal>
</manifest>

View File

@@ -1,24 +0,0 @@
/*
* SPDX-FileCopyrightText: 2024 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#include "ConsumerIr.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using aidl::android::hardware::ir::ConsumerIr;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<ConsumerIr> hal = ::ndk::SharedRefBase::make<ConsumerIr>();
const std::string instance = std::string(ConsumerIr::descriptor) + "/default";
binder_status_t status = AServiceManager_addService(hal->asBinder().get(), instance.c_str());
CHECK_EQ(status, STATUS_OK);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}

View File

@@ -1,28 +0,0 @@
//
// Copyright (C) 2021-2024 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
cc_binary {
name: "android.hardware.light-service.xiaomi",
defaults: ["hidl_defaults"],
vendor: true,
relative_install_path: "hw",
init_rc: ["android.hardware.light-service.xiaomi.rc"],
vintf_fragments: ["android.hardware.light-service.xiaomi.xml"],
srcs: [
"BacklightDevice.cpp",
"Devices.cpp",
"LedDevice.cpp",
"Lights.cpp",
"RgbLedDevice.cpp",
"Utils.cpp",
"service.cpp",
],
shared_libs: [
"libbase",
"libbinder_ndk",
"android.hardware.light-V2-ndk",
],
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright (C) 2022-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "BacklightDevice.h"
#define LOG_TAG "BacklightDevice"
#include <android-base/logging.h>
#include <fstream>
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
static const std::string kBacklightBasePath = "/sys/class/backlight/";
static const uint32_t kDefaultMaxBrightness = 255;
static const std::string kBrightnessNode = "brightness";
static const std::string kMaxBrightnessNode = "max_brightness";
BacklightDevice::BacklightDevice(std::string name)
: mName(name), mBasePath(kBacklightBasePath + name + "/") {
if (!readFromFile(mBasePath + kMaxBrightnessNode, mMaxBrightness)) {
mMaxBrightness = kDefaultMaxBrightness;
}
};
std::string BacklightDevice::getName() const {
return mName;
}
bool BacklightDevice::exists() const {
return std::ifstream(mBasePath + kBrightnessNode).good();
}
bool BacklightDevice::setBrightness(uint8_t value) {
return writeToFile(mBasePath + kBrightnessNode, scaleBrightness(value, mMaxBrightness));
}
void BacklightDevice::dump(int fd) const {
dprintf(fd, "Name: %s", mName.c_str());
dprintf(fd, ", exists: %d", exists());
dprintf(fd, ", base path: %s", mBasePath.c_str());
dprintf(fd, ", max brightness: %u", mMaxBrightness);
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,66 +0,0 @@
/*
* Copyright (C) 2022-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstdint>
#include <string>
#include "IDumpable.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
/**
* A Linux backlight device.
* @see https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-backlight
*/
class BacklightDevice : public IDumpable {
public:
BacklightDevice() = delete;
/**
* Constructor.
*
* @param name The name of the backlight device
*/
BacklightDevice(std::string name);
/**
* Get the name of the backlight device.
*
* @return std::string The name of the backlight device
*/
std::string getName() const;
/**
* Return whether this backlight device exists.
*
* @return bool true if the backlight device exists, false otherwise
*/
bool exists() const;
/**
* Set the brightness of this backlight device.
*
* @param value The brightness value to set
* @return bool true if the brightness was set successfully, false otherwise
*/
bool setBrightness(uint8_t value);
void dump(int fd) const override;
private:
std::string mName;
std::string mBasePath;
uint32_t mMaxBrightness;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,220 +0,0 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Devices.h"
#define LOG_TAG "Devices"
#include <android-base/logging.h>
namespace aidl {
namespace android {
namespace hardware {
namespace light {
static const std::string kBacklightDevices[] = {
"backlight",
"panel0-backlight",
};
static std::vector<BacklightDevice> getBacklightDevices() {
std::vector<BacklightDevice> devices;
for (const auto& device : kBacklightDevices) {
BacklightDevice backlight(device);
if (backlight.exists()) {
LOG(INFO) << "Found backlight device: " << backlight.getName();
devices.push_back(backlight);
}
}
return devices;
}
static const std::string kLedBacklightDevices[] = {
"lcd-backlight",
};
static std::vector<LedDevice> getBacklightLedDevices() {
std::vector<LedDevice> devices;
for (const auto& device : kLedBacklightDevices) {
LedDevice backlight(device);
if (backlight.exists()) {
LOG(INFO) << "Found backlight LED device: " << backlight.getName();
devices.push_back(backlight);
}
}
return devices;
}
static const std::string kButtonLedDevices[] = {
"button-backlight",
"button-backlight1",
"button-backlight2",
};
static std::vector<LedDevice> getButtonLedDevices() {
std::vector<LedDevice> devices;
for (const auto& device : kButtonLedDevices) {
LedDevice button(device);
if (button.exists()) {
LOG(INFO) << "Found button LED device: " << button.getName();
devices.emplace_back(button);
}
}
return devices;
}
static const std::string kRgbLedDevices[][4] = {
{"red", "green", "blue", "/sys/class/leds/rgb/rgb_blink"},
};
static std::vector<RgbLedDevice> getNotificationRgbLedDevices() {
std::vector<RgbLedDevice> devices;
for (const auto& device : kRgbLedDevices) {
LedDevice red(device[0]);
LedDevice green(device[1]);
LedDevice blue(device[2]);
RgbLedDevice rgbLedDevice(red, green, blue, device[3]);
if (rgbLedDevice.exists()) {
LOG(INFO) << "Found notification RGB LED device: " << red.getName() << ", "
<< green.getName() << ", " << blue.getName();
devices.emplace_back(red, green, blue, device[3]);
}
}
return devices;
}
static const std::string kNotificationLedDevices[] = {
"left",
"white",
};
static std::vector<LedDevice> getNotificationLedDevices() {
std::vector<LedDevice> devices;
for (const auto& device : kNotificationLedDevices) {
LedDevice notification(device);
if (notification.exists()) {
LOG(INFO) << "Found notification LED device: " << notification.getName();
devices.emplace_back(notification);
}
}
return devices;
}
Devices::Devices()
: mBacklightDevices(getBacklightDevices()),
mBacklightLedDevices(getBacklightLedDevices()),
mButtonLedDevices(getButtonLedDevices()),
mNotificationRgbLedDevices(getNotificationRgbLedDevices()),
mNotificationLedDevices(getNotificationLedDevices()) {
if (!hasBacklightDevices()) {
LOG(INFO) << "No backlight devices found";
}
if (!hasButtonDevices()) {
LOG(INFO) << "No button devices found";
}
if (!hasNotificationDevices()) {
LOG(INFO) << "No notification devices found";
}
}
bool Devices::hasBacklightDevices() const {
return !mBacklightDevices.empty() || !mBacklightLedDevices.empty();
}
bool Devices::hasButtonDevices() const {
return !mButtonLedDevices.empty();
}
bool Devices::hasNotificationDevices() const {
return !mNotificationRgbLedDevices.empty() || !mNotificationLedDevices.empty();
}
void Devices::setBacklightColor(rgb color) {
for (auto& device : mBacklightDevices) {
device.setBrightness(color.toBrightness());
}
for (auto& device : mBacklightLedDevices) {
device.setBrightness(color.toBrightness());
}
}
void Devices::setButtonsColor(rgb color) {
for (auto& device : mButtonLedDevices) {
device.setBrightness(color.toBrightness());
}
}
void Devices::setNotificationColor(rgb color, LightMode mode, uint32_t flashOnMs,
uint32_t flashOffMs) {
for (auto& device : mNotificationRgbLedDevices) {
device.setBrightness(color, mode, flashOnMs, flashOffMs);
}
for (auto& device : mNotificationLedDevices) {
device.setBrightness(color.toBrightness(), mode, flashOnMs, flashOffMs);
}
}
void Devices::dump(int fd) const {
dprintf(fd, "Backlight devices:\n");
for (const auto& device : mBacklightDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
dprintf(fd, "\n");
dprintf(fd, "Backlight LED devices:\n");
for (const auto& device : mBacklightLedDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
dprintf(fd, "\n");
dprintf(fd, "Button LED devices:\n");
for (const auto& device : mButtonLedDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
dprintf(fd, "\n");
dprintf(fd, "Notification RGB LED devices:\n");
for (const auto& device : mNotificationRgbLedDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
dprintf(fd, "\n");
dprintf(fd, "Notification LED devices:\n");
for (const auto& device : mNotificationLedDevices) {
dprintf(fd, "- ");
device.dump(fd);
dprintf(fd, "\n");
}
return;
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,52 +0,0 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <vector>
#include "BacklightDevice.h"
#include "IDumpable.h"
#include "LedDevice.h"
#include "RgbLedDevice.h"
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
class Devices : public IDumpable {
public:
Devices();
bool hasBacklightDevices() const;
bool hasButtonDevices() const;
bool hasNotificationDevices() const;
void setBacklightColor(rgb color);
void setButtonsColor(rgb color);
void setNotificationColor(rgb color, LightMode mode = LightMode::STATIC, uint32_t flashOnMs = 0,
uint32_t flashOffMs = 0);
void dump(int fd) const override;
private:
// Backlight
std::vector<BacklightDevice> mBacklightDevices;
std::vector<LedDevice> mBacklightLedDevices;
// Buttons
std::vector<LedDevice> mButtonLedDevices;
// Notifications
std::vector<RgbLedDevice> mNotificationRgbLedDevices;
std::vector<LedDevice> mNotificationLedDevices;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
namespace aidl {
namespace android {
namespace hardware {
namespace light {
/**
* Interface for dumpable objects using AIDL dump()'s file descriptor.
*/
class IDumpable {
public:
virtual ~IDumpable() = default;
/**
* Write information regarding this object to the given file descriptor using dprintf().
* You should avoid ending newline, since the caller will add it.
* @param fd The file descriptor to write to.
*/
virtual void dump(int fd) const = 0;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,158 +0,0 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "LedDevice.h"
#define LOG_TAG "LedDevice"
#include <android-base/logging.h>
#include <fstream>
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
static const uint32_t kDefaultMaxBrightness = 255;
static const std::string kBaseLedsPath = "/sys/class/leds/";
static const std::string kBrightnessNode = "brightness";
static const std::string kMaxBrightnessNode = "max_brightness";
static const std::string kBreathNodes[] = {
"breath",
"blink",
};
static const std::string kBlinkNode = "blink";
static const std::string kStartIdxNode = "start_idx";
static const std::string kDutyPctsNode = "duty_pcts";
static const std::string kPauseLoNode = "pause_lo";
static const std::string kPauseHiNode = "pause_hi";
static const std::string kRampStepMsNode = "ramp_step_ms";
static constexpr int kRampSteps = 8;
static constexpr int kRampMaxStepDurationMs = 50;
LedDevice::LedDevice(std::string name)
: mName(name), mIdx(0), mBasePath(kBaseLedsPath + name + "/") {
if (!readFromFile(mBasePath + kMaxBrightnessNode, mMaxBrightness)) {
mMaxBrightness = kDefaultMaxBrightness;
}
for (const auto& node : kBreathNodes) {
if (std::ifstream(mBasePath + node).good()) {
mBreathNode = node;
break;
}
}
mSupportsTimed = std::ifstream(mBasePath + kBlinkNode).good() &&
std::ifstream(mBasePath + kStartIdxNode).good() &&
std::ifstream(mBasePath + kDutyPctsNode).good() &&
std::ifstream(mBasePath + kPauseLoNode).good() &&
std::ifstream(mBasePath + kPauseHiNode).good() &&
std::ifstream(mBasePath + kRampStepMsNode).good();
}
std::string LedDevice::getName() const {
return mName;
}
bool LedDevice::supportsBreath() const {
return !mBreathNode.empty();
}
bool LedDevice::supportsTimed() const {
return mSupportsTimed;
}
bool LedDevice::exists() const {
return std::ifstream(mBasePath + kBrightnessNode).good();
}
static std::string getScaledDutyPercent(uint8_t brightness) {
std::string output;
for (int i = 0; i < kRampSteps; i++) {
if (i != 0) {
output += ",";
}
output += std::to_string(i * 100 * brightness / (0xFF * kRampSteps));
}
return output;
}
bool LedDevice::setBrightness(uint8_t value, LightMode mode, uint32_t flashOnMs,
uint32_t flashOffMs) {
// Disable current blinking
if (mSupportsTimed) {
writeToFile(mBasePath + kBlinkNode, 0);
}
if (supportsBreath()) {
writeToFile(mBasePath + mBreathNode, 0);
}
switch (mode) {
case LightMode::TIMED:
if (mSupportsTimed) {
int32_t stepDuration = kRampMaxStepDurationMs;
int32_t pauseLo = flashOffMs;
int32_t pauseHi = flashOnMs - (stepDuration * kRampSteps * 2);
if (pauseHi < 0) {
stepDuration = flashOnMs / (kRampSteps * 2);
pauseHi = 0;
}
return writeToFile(mBasePath + kStartIdxNode, mIdx * kRampSteps) &&
writeToFile(mBasePath + kDutyPctsNode, getScaledDutyPercent(value)) &&
writeToFile(mBasePath + kPauseLoNode, pauseLo) &&
writeToFile(mBasePath + kPauseHiNode, pauseHi) &&
writeToFile(mBasePath + kRampStepMsNode, stepDuration) &&
writeToFile(mBasePath + kBlinkNode, 1);
}
// Fallthrough to breath mode if timed is not supported
FALLTHROUGH_INTENDED;
case LightMode::BREATH:
if (supportsBreath()) {
return writeToFile(mBasePath + mBreathNode, value > 0 ? 1 : 0);
break;
}
// Fallthrough to static mode if breath is not supported
FALLTHROUGH_INTENDED;
case LightMode::STATIC:
return writeToFile(mBasePath + kBrightnessNode, scaleBrightness(value, mMaxBrightness));
break;
default:
LOG(ERROR) << "Unknown mode: " << mode;
return false;
break;
}
}
void LedDevice::setIdx(int idx) {
mIdx = idx;
}
void LedDevice::dump(int fd) const {
dprintf(fd, "Name: %s", mName.c_str());
dprintf(fd, ", index: %d", mIdx);
dprintf(fd, ", exists: %d", exists());
dprintf(fd, ", base path: %s", mBasePath.c_str());
dprintf(fd, ", max brightness: %u", mMaxBrightness);
dprintf(fd, ", supports breath: %d", supportsBreath());
dprintf(fd, ", supports timed: %d", supportsTimed());
dprintf(fd, ", breath node: %s", mBreathNode.c_str());
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,102 +0,0 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstdint>
#include <string>
#include "IDumpable.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
enum LightMode {
STATIC,
BREATH,
TIMED,
};
/**
* A Linux LED device.
* @see https://docs.kernel.org/leds/leds-class.html
*/
class LedDevice : public IDumpable {
public:
LedDevice() = delete;
/**
* Constructor.
*
* @param name The name of the LED device
*/
LedDevice(std::string name);
/**
* Get the name of the LED device.
*
* @return std::string The name of the LED device
*/
std::string getName() const;
/**
* Return whether this LED device exists.
*
* @return bool true if the LED device exists, false otherwise
*/
bool exists() const;
/**
* Return whether this LED device supports breathing.
* When it doesn't, calling setBrightness with LightMode::BREATH will behave like
* LightMode::STATIC.
*
* @return bool true if the LED device supports breathing, false otherwise
*/
bool supportsBreath() const;
/**
* Return whether this LED device supports timed mode.
* When it doesn't, calling setBrightness with LightMode::TIMED will behave like
* LightMode::BREATH.
*
* @return bool true if the LED device supports timed mode, false otherwise
*/
bool supportsTimed() const;
/**
* Set the brightness of the LED device.
*
* @param value The brightness value to set
* @param mode The light mode to use
* @return bool true if the brightness was set successfully, false otherwise
*/
bool setBrightness(uint8_t value, LightMode mode = LightMode::STATIC, uint32_t flashOnMs = 0,
uint32_t flashOffMs = 0);
/**
* Set the index of the LED device.
*
* @param idx The index to set
*/
void setIdx(int idx);
void dump(int fd) const override;
private:
std::string mName;
int mIdx;
std::string mBasePath;
uint32_t mMaxBrightness;
std::string mBreathNode;
bool mSupportsTimed;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,133 +0,0 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Lights.h"
#define LOG_TAG "Lights"
#include <android-base/logging.h>
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
#define AutoHwLight(light) \
{ .id = static_cast<int32_t>(light), .ordinal = 0, .type = light }
Lights::Lights() {
if (mDevices.hasBacklightDevices()) {
mLights.push_back(AutoHwLight(LightType::BACKLIGHT));
}
if (mDevices.hasButtonDevices()) {
mLights.push_back(AutoHwLight(LightType::BUTTONS));
}
if (mDevices.hasNotificationDevices()) {
mLights.push_back(AutoHwLight(LightType::BATTERY));
mLights.push_back(AutoHwLight(LightType::NOTIFICATIONS));
mLights.push_back(AutoHwLight(LightType::ATTENTION));
}
}
ndk::ScopedAStatus Lights::setLightState(int32_t id, const HwLightState& state) {
rgb color(state.color);
LightType type = static_cast<LightType>(id);
switch (type) {
case LightType::BACKLIGHT:
mDevices.setBacklightColor(color);
break;
case LightType::BUTTONS:
mDevices.setButtonsColor(color);
break;
case LightType::BATTERY:
mLastBatteryState = state;
updateNotificationColor();
break;
case LightType::NOTIFICATIONS:
mLastNotificationsState = state;
updateNotificationColor();
break;
case LightType::ATTENTION:
mLastAttentionState = state;
updateNotificationColor();
break;
default:
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
break;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* _aidl_return) {
for (const auto& light : mLights) {
_aidl_return->push_back(light);
}
return ndk::ScopedAStatus::ok();
}
binder_status_t Lights::dump(int fd, const char** /*args*/, uint32_t /*numArgs*/) {
dprintf(fd, "Lights AIDL:\n");
dprintf(fd, "\n");
dprintf(fd, "Lights:\n");
for (const auto& light : mLights) {
dprintf(fd, "- %d: LightType::%s\n", light.id, toString(light.type).c_str());
}
dprintf(fd, "\n");
dprintf(fd, "Devices:\n");
mDevices.dump(fd);
dprintf(fd, "\n");
return STATUS_OK;
}
void Lights::updateNotificationColor() {
std::lock_guard<std::mutex> lock(mLedMutex);
bool isBatteryLit = rgb(mLastBatteryState.color).isLit();
bool isAttentionLit = rgb(mLastAttentionState.color).isLit();
bool isNotificationsLit = rgb(mLastNotificationsState.color).isLit();
const HwLightState state = isNotificationsLit ? mLastNotificationsState
: isAttentionLit ? mLastAttentionState
: isBatteryLit ? mLastBatteryState
: HwLightState();
rgb color(state.color);
LightMode lightMode;
switch (state.flashMode) {
case FlashMode::NONE:
lightMode = LightMode::STATIC;
break;
case FlashMode::TIMED:
lightMode = LightMode::TIMED;
break;
case FlashMode::HARDWARE:
lightMode = LightMode::BREATH;
break;
default:
LOG(ERROR) << "Unknown flash mode: " << static_cast<int>(state.flashMode);
lightMode = LightMode::STATIC;
break;
}
mDevices.setNotificationColor(color, lightMode, state.flashOnMs, state.flashOffMs);
return;
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,43 +0,0 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/android/hardware/light/BnLights.h>
#include <mutex>
#include "Devices.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
class Lights : public BnLights {
public:
Lights();
ndk::ScopedAStatus setLightState(int32_t id, const HwLightState& state) override;
ndk::ScopedAStatus getLights(std::vector<HwLight>* _aidl_return) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
std::vector<HwLight> mLights;
Devices mDevices;
HwLightState mLastBatteryState;
HwLightState mLastNotificationsState;
HwLightState mLastAttentionState;
std::mutex mLedMutex;
void updateNotificationColor();
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,146 +0,0 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "RgbLedDevice.h"
#define LOG_TAG "RgbLedDevice"
#include <android-base/logging.h>
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
RgbLedDevice::RgbLedDevice(LedDevice red, LedDevice green, LedDevice blue, std::string rgbSyncNode)
: mRed(red), mGreen(green), mBlue(blue), mRgbSyncNode(rgbSyncNode), mColors(Color::NONE) {
if (mRed.exists()) {
mColors |= Color::RED;
}
if (mGreen.exists()) {
mColors |= Color::GREEN;
}
if (mBlue.exists()) {
mColors |= Color::BLUE;
}
if (supportsRgbSync()) {
mRed.setIdx(0);
mGreen.setIdx(1);
mBlue.setIdx(2);
}
}
bool RgbLedDevice::exists() const {
return mColors != Color::NONE;
}
bool RgbLedDevice::supportsBreath() const {
return (!mRed.exists() || mRed.supportsBreath()) &&
(!mGreen.exists() || mGreen.supportsBreath()) &&
(!mBlue.exists() || mBlue.supportsBreath());
}
bool RgbLedDevice::supportsTimed() const {
return (!mRed.exists() || mRed.supportsTimed()) &&
(!mGreen.exists() || mGreen.supportsTimed()) &&
(!mBlue.exists() || mBlue.supportsTimed());
}
bool RgbLedDevice::supportsRgbSync() const {
return std::ifstream(mRgbSyncNode).good();
}
bool RgbLedDevice::setBrightness(rgb color, LightMode mode, uint32_t flashOnMs,
uint32_t flashOffMs) {
bool rc = true;
if (mColors == Color::NONE) {
LOG(ERROR) << "No LEDs found";
return false;
}
if (mode == LightMode::TIMED && !supportsTimed()) {
// Not all LEDs support timed mode, force breathing mode
mode = LightMode::BREATH;
}
if (mode == LightMode::BREATH && !supportsBreath()) {
// Not all LEDs support breathing, force static mode
mode = LightMode::STATIC;
}
if (mode == LightMode::TIMED && supportsRgbSync()) {
rc &= writeToFile(mRgbSyncNode, 0);
}
if (mColors == Color::ALL) {
rc &= mRed.setBrightness(color.red, mode, flashOnMs, flashOffMs);
rc &= mGreen.setBrightness(color.green, mode, flashOnMs, flashOffMs);
rc &= mBlue.setBrightness(color.blue, mode, flashOnMs, flashOffMs);
} else {
// Check if we have only one LED
if (mColors == Color::RED) {
rc &= mRed.setBrightness(color.toBrightness(), mode, flashOnMs, flashOffMs);
} else if (mColors == Color::GREEN) {
rc &= mGreen.setBrightness(color.toBrightness(), mode, flashOnMs, flashOffMs);
} else if (mColors == Color::BLUE) {
rc &= mBlue.setBrightness(color.toBrightness(), mode, flashOnMs, flashOffMs);
} else {
// We only have two LEDs, blend the missing color in the other two
if ((mColors & Color::RED) == Color::NONE) {
rc &= mBlue.setBrightness((color.blue + color.red) / 2, mode, flashOnMs,
flashOffMs);
rc &= mGreen.setBrightness((color.green + color.red) / 2, mode, flashOnMs,
flashOffMs);
} else if ((mColors & Color::GREEN) == Color::NONE) {
rc &= mRed.setBrightness((color.red + color.green) / 2, mode, flashOnMs,
flashOffMs);
rc &= mBlue.setBrightness((color.blue + color.green) / 2, mode, flashOnMs,
flashOffMs);
} else if ((mColors & Color::BLUE) == Color::NONE) {
rc &= mRed.setBrightness((color.red + color.blue) / 2, mode, flashOnMs, flashOffMs);
rc &= mGreen.setBrightness((color.green + color.blue) / 2, mode, flashOnMs,
flashOffMs);
}
}
}
if (mode == LightMode::TIMED && supportsRgbSync()) {
rc &= writeToFile(mRgbSyncNode, 1);
}
return rc;
}
void RgbLedDevice::dump(int fd) const {
dprintf(fd, "Exists: %d", exists());
dprintf(fd, ", supports breath: %d", supportsBreath());
dprintf(fd, ", supports timed: %d", supportsTimed());
dprintf(fd, ", supports RGB sync: %d", supportsRgbSync());
dprintf(fd, ", colors:");
if (mColors != Color::NONE) {
if (mColors & Color::RED) {
dprintf(fd, "\nRed: ");
mRed.dump(fd);
}
if (mColors & Color::GREEN) {
dprintf(fd, "\nGreen: ");
mGreen.dump(fd);
}
if (mColors & Color::BLUE) {
dprintf(fd, "\nBlue: ");
mBlue.dump(fd);
}
} else {
dprintf(fd, " None");
}
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,104 +0,0 @@
/*
* Copyright (C) 2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "IDumpable.h"
#include "LedDevice.h"
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
/**
* A pool of LED devices that will be toggled based on the wanted color.
* Support all types of LED combinations, with a maximum of 3 LEDs.
* Also supports 2 color LEDs (*cough* ASUS *cough*).
*/
class RgbLedDevice : public IDumpable {
public:
RgbLedDevice() = delete;
/**
* Constructor.
*
* @param red The red LED device
* @param green The green LED device
* @param blue The blue LED device
* @param rgbSyncNode The path to RGB sync trigger
*/
RgbLedDevice(LedDevice red, LedDevice green, LedDevice blue, std::string rgbSyncNode);
/**
* Return whether this RGB LED device exists.
* This is true when at least one of the LEDs exists.
*
* @return bool true if the RGB LED device exists, false otherwise
*/
bool exists() const;
/**
* Return whether this RGB LED device supports breathing.
* This is true when all existing LEDs support breathing.
* In case this is false, calling setBrightness with LightMode::BREATH will behave like
* LightMode::STATIC.
*
* @return bool true if the RGB LED device supports breathing, false otherwise
*/
bool supportsBreath() const;
/**
* Return whether this RGB LED device supports timed mode.
* This is true when all existing LEDs support timed mode.
* In case this is false, calling setBrightness with LightMode::TIMED will behave like
* LightMode::BREATH.
*
* @return bool true if the RGB LED device supports timed mode, false otherwise
*/
bool supportsTimed() const;
/**
* Return whether this RGB LED device supports RGB sync.
*
* @return bool true if the RGB LED device supports RGB sync, false otherwise
*/
bool supportsRgbSync() const;
/**
* Set the brightness of this RGB LED device.
*
* @param color The color to set
* @param mode The mode to set
* @return bool true if the brightness was set successfully, false otherwise
*/
bool setBrightness(rgb color, LightMode mode = LightMode::STATIC, uint32_t flashOnMs = 0,
uint32_t flashOffMs = 0);
void dump(int fd) const override;
enum Color {
NONE = 0,
RED = 1 << 0,
GREEN = 1 << 1,
BLUE = 1 << 2,
ALL = RED | GREEN | BLUE,
};
private:
LedDevice mRed;
LedDevice mGreen;
LedDevice mBlue;
std::string mRgbSyncNode;
int mColors;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Utils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace light {
rgb::rgb() : red(0), green(0), blue(0) {}
rgb::rgb(uint8_t r, uint8_t g, uint8_t b) : red(r), green(g), blue(b){};
rgb::rgb(uint32_t color) {
// Extract brightness from AARRGGBB.
uint8_t alpha = (color >> 24) & 0xFF;
// Retrieve each of the RGB colors
red = (color >> 16) & 0xFF;
green = (color >> 8) & 0xFF;
blue = color & 0xFF;
// Scale RGB colors if a brightness has been applied by the user
if (alpha > 0 && alpha < 0xFF) {
red = red * alpha / 0xFF;
green = green * alpha / 0xFF;
blue = blue * alpha / 0xFF;
}
}
bool rgb::isLit() {
return !!red || !!green || !!blue;
}
static constexpr uint8_t kRedWeight = 77;
static constexpr uint8_t kGreenWeight = 150;
static constexpr uint8_t kBlueWeight = 29;
uint8_t rgb::toBrightness() {
return (kRedWeight * red + kGreenWeight * green + kBlueWeight * blue) >> 8;
}
uint32_t scaleBrightness(uint8_t brightness, uint32_t maxBrightness) {
return brightness * maxBrightness / 0xFF;
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,60 +0,0 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <cstdint>
#include <fstream>
#include <string>
namespace aidl {
namespace android {
namespace hardware {
namespace light {
struct rgb {
rgb();
rgb(uint8_t r, uint8_t g, uint8_t b);
rgb(uint32_t color);
uint8_t red;
uint8_t green;
uint8_t blue;
bool isLit();
uint8_t toBrightness();
};
uint32_t scaleBrightness(uint8_t brightness, uint32_t maxBrightness);
template <typename T>
bool readFromFile(const std::string& file, T& content) {
std::ifstream fileStream(file);
if (!fileStream) {
return false;
}
fileStream >> content;
return true;
}
template <typename T>
bool writeToFile(const std::string& file, const T content) {
std::ofstream fileStream(file);
if (!fileStream) {
return false;
}
fileStream << content;
return true;
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -1,106 +0,0 @@
on early-boot
# Backlight devices
chown system system /sys/class/backlight/backlight/brightness
chown system system /sys/class/backlight/backlight/max_brightness
chown system system /sys/class/backlight/panel0-backlight/brightness
chown system system /sys/class/backlight/panel0-backlight/max_brightness
# LED devices
chown system system /sys/class/leds/blue/blink
chown system system /sys/class/leds/blue/breath
chown system system /sys/class/leds/blue/brightness
chown system system /sys/class/leds/blue/duty_pcts
chown system system /sys/class/leds/blue/max_brightness
chown system system /sys/class/leds/blue/pause_hi
chown system system /sys/class/leds/blue/pause_lo
chown system system /sys/class/leds/blue/ramp_step_ms
chown system system /sys/class/leds/blue/start_idx
chown system system /sys/class/leds/button-backlight/blink
chown system system /sys/class/leds/button-backlight/breath
chown system system /sys/class/leds/button-backlight/brightness
chown system system /sys/class/leds/button-backlight/duty_pcts
chown system system /sys/class/leds/button-backlight/max_brightness
chown system system /sys/class/leds/button-backlight/pause_hi
chown system system /sys/class/leds/button-backlight/pause_lo
chown system system /sys/class/leds/button-backlight/ramp_step_ms
chown system system /sys/class/leds/button-backlight/start_idx
chown system system /sys/class/leds/button-backlight1/blink
chown system system /sys/class/leds/button-backlight1/breath
chown system system /sys/class/leds/button-backlight1/brightness
chown system system /sys/class/leds/button-backlight1/duty_pcts
chown system system /sys/class/leds/button-backlight1/max_brightness
chown system system /sys/class/leds/button-backlight1/pause_hi
chown system system /sys/class/leds/button-backlight1/pause_lo
chown system system /sys/class/leds/button-backlight1/ramp_step_ms
chown system system /sys/class/leds/button-backlight1/start_idx
chown system system /sys/class/leds/button-backlight2/blink
chown system system /sys/class/leds/button-backlight2/breath
chown system system /sys/class/leds/button-backlight2/brightness
chown system system /sys/class/leds/button-backlight2/duty_pcts
chown system system /sys/class/leds/button-backlight2/max_brightness
chown system system /sys/class/leds/button-backlight2/pause_hi
chown system system /sys/class/leds/button-backlight2/pause_lo
chown system system /sys/class/leds/button-backlight2/ramp_step_ms
chown system system /sys/class/leds/button-backlight2/start_idx
chown system system /sys/class/leds/green/blink
chown system system /sys/class/leds/green/breath
chown system system /sys/class/leds/green/brightness
chown system system /sys/class/leds/green/duty_pcts
chown system system /sys/class/leds/green/max_brightness
chown system system /sys/class/leds/green/pause_hi
chown system system /sys/class/leds/green/pause_lo
chown system system /sys/class/leds/green/ramp_step_ms
chown system system /sys/class/leds/green/start_idx
chown system system /sys/class/leds/lcd-backlight/blink
chown system system /sys/class/leds/lcd-backlight/breath
chown system system /sys/class/leds/lcd-backlight/brightness
chown system system /sys/class/leds/lcd-backlight/duty_pcts
chown system system /sys/class/leds/lcd-backlight/max_brightness
chown system system /sys/class/leds/lcd-backlight/pause_hi
chown system system /sys/class/leds/lcd-backlight/pause_lo
chown system system /sys/class/leds/lcd-backlight/ramp_step_ms
chown system system /sys/class/leds/lcd-backlight/start_idx
chown system system /sys/class/leds/left/blink
chown system system /sys/class/leds/left/breath
chown system system /sys/class/leds/left/brightness
chown system system /sys/class/leds/left/duty_pcts
chown system system /sys/class/leds/left/max_brightness
chown system system /sys/class/leds/left/pause_hi
chown system system /sys/class/leds/left/pause_lo
chown system system /sys/class/leds/left/ramp_step_ms
chown system system /sys/class/leds/left/start_idx
chown system system /sys/class/leds/red/blink
chown system system /sys/class/leds/red/breath
chown system system /sys/class/leds/red/brightness
chown system system /sys/class/leds/red/duty_pcts
chown system system /sys/class/leds/red/max_brightness
chown system system /sys/class/leds/red/pause_hi
chown system system /sys/class/leds/red/pause_lo
chown system system /sys/class/leds/red/ramp_step_ms
chown system system /sys/class/leds/red/start_idx
chown system system /sys/class/leds/rgb/rgb_blink
chown system system /sys/class/leds/white/blink
chown system system /sys/class/leds/white/breath
chown system system /sys/class/leds/white/brightness
chown system system /sys/class/leds/white/duty_pcts
chown system system /sys/class/leds/white/max_brightness
chown system system /sys/class/leds/white/pause_hi
chown system system /sys/class/leds/white/pause_lo
chown system system /sys/class/leds/white/ramp_step_ms
chown system system /sys/class/leds/white/start_idx
service vendor.light-default /vendor/bin/hw/android.hardware.light-service.xiaomi
class hal
user system
group system
shutdown critical

View File

@@ -1,7 +0,0 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.light</name>
<version>2</version>
<fqname>ILights/default</fqname>
</hal>
</manifest>

View File

@@ -1,27 +0,0 @@
/*
* Copyright (C) 2021-2024 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Lights.h"
#define LOG_TAG "android.hardware.light-service.xiaomi"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using ::aidl::android::hardware::light::Lights;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<Lights> lights = ndk::SharedRefBase::make<Lights>();
const std::string instance = std::string() + Lights::descriptor + "/default";
binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}

View File

@@ -19,6 +19,12 @@ package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
vintf_fragment {
name: "android.hardware.sensors.xiaomi-multihal.xml",
src: "android.hardware.sensors.xiaomi-multihal.xml",
vendor: true,
}
cc_binary {
name: "android.hardware.sensors-service.xiaomi-multihal",
vendor: true,
@@ -33,12 +39,12 @@ cc_binary {
"android.hardware.sensors@2.X-shared-utils",
],
init_rc: ["android.hardware.sensors-service.xiaomi-multihal.rc"],
vintf_fragments: ["android.hardware.sensors.xiaomi-multihal.xml"],
vintf_fragment_modules: ["android.hardware.sensors.xiaomi-multihal.xml"],
shared_libs: [
"android.hardware.sensors@2.0-ScopedWakelock",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
"android.hardware.sensors-V2-ndk",
"android.hardware.sensors-V3-ndk",
"libbase",
"libcutils",
"libfmq",

View File

@@ -147,9 +147,9 @@ Return<void> HalProxy::getSensorsList_2_1(ISensorsV2_1::getSensorsList_2_1_cb _h
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));
}
if (iter.second.type != SensorType::HINGE_ANGLE) {
sensors.push_back(convertToOldSensorInfo(iter.second));
}
}
_hidl_cb(sensors);
return Void();
@@ -612,7 +612,8 @@ void HalProxy::handlePendingWrites() {
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);
ALOGE("Dropping %zu events after blockingWrite failed (is system_server running?).",
numToWrite);
if (numWakeupEvents > 0) {
if (pendingWriteEvents.size() > eventQueueSize) {
decrementRefCountAndMaybeReleaseWakelock(
@@ -735,8 +736,7 @@ void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
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);
ALOGE("Decrementing wakelock ref count by %zu when count is %zu", delta, mWakelockRefCount);
}
if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;

View File

@@ -74,8 +74,7 @@ std::vector<V2_1::Event> HalProxyCallbackBase::processEvents(const std::vector<V
}
const V2_1::SensorInfo& sensor = mCallback->getSensorInfo(event.sensorHandle);
if (sensor.type == V2_1::SensorType::PICK_UP_GESTURE
&& event.u.scalar != 1) {
if (sensor.type == V2_1::SensorType::PICK_UP_GESTURE && event.u.scalar != 1) {
continue;
}

View File

@@ -1,3 +1,6 @@
on boot
setprop vendor.sensors.dynamic_sensor_op_timeout_ms 1600
service vendor.sensors-hal-multihal /vendor/bin/hw/android.hardware.sensors-service.xiaomi-multihal
class hal
user system

View File

@@ -17,7 +17,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.sensors</name>
<version>2</version>
<version>3</version>
<fqname>ISensors/default</fqname>
</hal>
</manifest>

48
aidl/touch/Android.bp Normal file
View File

@@ -0,0 +1,48 @@
//
// SPDX-FileCopyrightText: 2025 The LineageOS Project
// SPDX-License-Identifier: Apache-2.0
//
cc_binary {
name: "vendor.lineage.touch-service.xiaomi",
init_rc: ["vendor.lineage.touch-service.xiaomi.rc"],
vintf_fragments: select(soong_config_variable("XIAOMI_TOUCH", "HIGH_TOUCH_POLLING_PATH"), {
any: ["vendor.lineage.touch-service.xiaomi-htpr.xml"],
default: [],
}) + select(soong_config_variable("XIAOMI_TOUCH", "KEY_DISABLER_CONTROL_PATH"), {
any: ["vendor.lineage.touch-service.xiaomi-kd.xml"],
default: [],
}) + select(soong_config_variable("XIAOMI_TOUCH", "KEY_SWAPPER_CONTROL_PATH"), {
any: ["vendor.lineage.touch-service.xiaomi-ks.xml"],
default: [],
}),
relative_install_path: "hw",
proprietary: true,
cppflags: select(soong_config_variable("XIAOMI_TOUCH", "HIGH_TOUCH_POLLING_PATH"), {
any @ flag_val: ["-DHTPR_CONTROL_PATH=\"" + flag_val + "\""],
default: [],
}) + select(soong_config_variable("XIAOMI_TOUCH", "KEY_DISABLER_CONTROL_PATH"), {
any @ flag_val: ["-DKD_CONTROL_PATH=\"" + flag_val + "\""],
default: [],
}) + select(soong_config_variable("XIAOMI_TOUCH", "KEY_SWAPPER_CONTROL_PATH"), {
any @ flag_val: ["-DKS_CONTROL_PATH=\"" + flag_val + "\""],
default: [],
}),
srcs: select(soong_config_variable("XIAOMI_TOUCH", "HIGH_TOUCH_POLLING_PATH"), {
any: ["HighTouchPollingRate.cpp"],
default: [],
}) + select(soong_config_variable("XIAOMI_TOUCH", "KEY_DISABLER_CONTROL_PATH"), {
any: ["KeyDisabler.cpp"],
default: [],
}) + select(soong_config_variable("XIAOMI_TOUCH", "KEY_SWAPPER_CONTROL_PATH"), {
any: ["KeySwapper.cpp"],
default: [],
}) + ["service.cpp"],
shared_libs: [
"libbase",
"libbinder_ndk",
"liblog",
"libutils",
"vendor.lineage.touch-V1-ndk",
],
}

View File

@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "vendor.lineage.touch-service.xiaomi"
#include "HighTouchPollingRate.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
using ::android::base::ReadFileToString;
using ::android::base::Trim;
using ::android::base::WriteStringToFile;
namespace aidl {
namespace vendor {
namespace lineage {
namespace touch {
ndk::ScopedAStatus HighTouchPollingRate::getEnabled(bool* _aidl_return) {
std::string buf;
if (!ReadFileToString(HTPR_CONTROL_PATH, &buf)) {
LOG(ERROR) << "Failed to read current HighTouchPollingRate state";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
*_aidl_return = Trim(buf) == "1";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus HighTouchPollingRate::setEnabled(bool enabled) {
if (!WriteStringToFile(enabled ? "1" : "0", HTPR_CONTROL_PATH)) {
LOG(ERROR) << "Failed to write HighTouchPollingRate state";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
return ndk::ScopedAStatus::ok();
}
} // namespace touch
} // namespace lineage
} // namespace vendor
} // namespace aidl

View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/vendor/lineage/touch/BnHighTouchPollingRate.h>
namespace aidl {
namespace vendor {
namespace lineage {
namespace touch {
class HighTouchPollingRate : public BnHighTouchPollingRate {
public:
ndk::ScopedAStatus getEnabled(bool* _aidl_return) override;
ndk::ScopedAStatus setEnabled(bool enabled) override;
};
} // namespace touch
} // namespace lineage
} // namespace vendor
} // namespace aidl

View File

@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "vendor.lineage.touch-service.xiaomi"
#include "KeyDisabler.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
using ::android::base::ReadFileToString;
using ::android::base::Trim;
using ::android::base::WriteStringToFile;
namespace aidl {
namespace vendor {
namespace lineage {
namespace touch {
ndk::ScopedAStatus KeyDisabler::getEnabled(bool* _aidl_return) {
std::string buf;
if (!ReadFileToString(KD_CONTROL_PATH, &buf)) {
LOG(ERROR) << "Failed to read current KeyDisabler state";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
*_aidl_return = Trim(buf) == "0";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus KeyDisabler::setEnabled(bool enabled) {
if (!WriteStringToFile(enabled ? "0" : "1", KD_CONTROL_PATH, true)) {
LOG(ERROR) << "Failed to write KeyDisabler state";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
return ndk::ScopedAStatus::ok();
}
} // namespace touch
} // namespace lineage
} // namespace vendor
} // namespace aidl

24
aidl/touch/KeyDisabler.h Normal file
View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/vendor/lineage/touch/BnKeyDisabler.h>
namespace aidl {
namespace vendor {
namespace lineage {
namespace touch {
class KeyDisabler : public BnKeyDisabler {
public:
ndk::ScopedAStatus getEnabled(bool* _aidl_return) override;
ndk::ScopedAStatus setEnabled(bool enabled) override;
};
} // namespace touch
} // namespace lineage
} // namespace vendor
} // namespace aidl

46
aidl/touch/KeySwapper.cpp Normal file
View File

@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "vendor.lineage.touch-service.xiaomi"
#include "KeySwapper.h"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/strings.h>
using ::android::base::ReadFileToString;
using ::android::base::Trim;
using ::android::base::WriteStringToFile;
namespace aidl {
namespace vendor {
namespace lineage {
namespace touch {
ndk::ScopedAStatus KeySwapper::getEnabled(bool* _aidl_return) {
std::string buf;
if (!ReadFileToString(KS_CONTROL_PATH, &buf)) {
LOG(ERROR) << "Failed to read current KeySwapper state";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
*_aidl_return = Trim(buf) == "1";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus KeySwapper::setEnabled(bool enabled) {
if (!WriteStringToFile(enabled ? "1" : "0", KS_CONTROL_PATH, true)) {
LOG(ERROR) << "Failed to write KeySwapper state";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
return ndk::ScopedAStatus::ok();
}
} // namespace touch
} // namespace lineage
} // namespace vendor
} // namespace aidl

24
aidl/touch/KeySwapper.h Normal file
View File

@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/vendor/lineage/touch/BnKeySwapper.h>
namespace aidl {
namespace vendor {
namespace lineage {
namespace touch {
class KeySwapper : public BnKeySwapper {
public:
ndk::ScopedAStatus getEnabled(bool* _aidl_return) override;
ndk::ScopedAStatus setEnabled(bool enabled) override;
};
} // namespace touch
} // namespace lineage
} // namespace vendor
} // namespace aidl

48
aidl/touch/service.cpp Normal file
View File

@@ -0,0 +1,48 @@
/*
* SPDX-FileCopyrightText: 2025 The LineageOS Project
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "vendor.lineage.touch-service.xiaomi"
#include "HighTouchPollingRate.h"
#include "KeyDisabler.h"
#include "KeySwapper.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using aidl::vendor::lineage::touch::HighTouchPollingRate;
using aidl::vendor::lineage::touch::KeyDisabler;
using aidl::vendor::lineage::touch::KeySwapper;
int main() {
binder_status_t status = STATUS_OK;
ABinderProcess_setThreadPoolMaxThreadCount(0);
#ifdef HTPR_CONTROL_PATH
std::shared_ptr<HighTouchPollingRate> htpr = ndk::SharedRefBase::make<HighTouchPollingRate>();
const std::string htpr_instance = std::string(HighTouchPollingRate::descriptor) + "/default";
status = AServiceManager_addService(htpr->asBinder().get(), htpr_instance.c_str());
CHECK_EQ(status, STATUS_OK) << "Failed to add service " << htpr_instance << " " << status;
#endif
#ifdef KD_CONTROL_PATH
std::shared_ptr<KeyDisabler> kd = ndk::SharedRefBase::make<KeyDisabler>();
const std::string kd_instance = std::string(KeyDisabler::descriptor) + "/default";
status = AServiceManager_addService(kd->asBinder().get(), kd_instance.c_str());
CHECK_EQ(status, STATUS_OK) << "Failed to add service " << kd_instance << " " << status;
#endif
#ifdef KS_CONTROL_PATH
std::shared_ptr<KeySwapper> ks = ndk::SharedRefBase::make<KeySwapper>();
const std::string ks_instance = std::string(KeySwapper::descriptor) + "/default";
status = AServiceManager_addService(ks->asBinder().get(), ks_instance.c_str());
CHECK_EQ(status, STATUS_OK) << "Failed to add service " << ks_instance << " " << status;
#endif
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}

View File

@@ -1,8 +1,7 @@
<manifest version="1.0" type="device">
<hal format="hidl">
<hal format="aidl">
<name>vendor.lineage.touch</name>
<transport>hwbinder</transport>
<version>1.0</version>
<version>1</version>
<interface>
<name>IHighTouchPollingRate</name>
<instance>default</instance>

View File

@@ -0,0 +1,10 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>vendor.lineage.touch</name>
<version>1</version>
<interface>
<name>IKeyDisabler</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View File

@@ -0,0 +1,10 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>vendor.lineage.touch</name>
<version>1</version>
<interface>
<name>IKeySwapper</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View File

@@ -0,0 +1,4 @@
service vendor.touch-hal /vendor/bin/hw/vendor.lineage.touch-service.xiaomi
class hal
user system
group system

31
fingerprint/Android.bp Normal file
View File

@@ -0,0 +1,31 @@
//
// Copyright (C) 2022-2024 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
cc_library_static {
name: "libudfpshandlerfactory",
srcs: ["UdfpsHandler.cpp"],
vendor: true,
header_libs: ["xiaomifingerprint_headers"],
}
cc_library_headers {
name: "xiaomifingerprint_headers",
export_include_dirs: ["include"],
vendor: true,
header_libs: ["libhardware_headers"],
export_header_lib_headers: ["libhardware_headers"],
}
cc_library_static {
name: "libudfps_extension.xiaomi",
srcs: ["UdfpsExtension.cpp"],
include_dirs: [
"frameworks/native/services/surfaceflinger/CompositionEngine/include",
],
header_libs: [
"generated_kernel_headers",
],
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2022 The LineageOS Project
* Copyright (C) 2022,2025 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -13,12 +13,14 @@ class UdfpsHandler {
public:
virtual ~UdfpsHandler() = default;
virtual void init(fingerprint_device_t* device) = 0;
virtual void onFingerDown(uint32_t x, uint32_t y, float minor, float major) = 0;
virtual void onFingerUp() = 0;
virtual void init(fingerprint_device_t* device) {};
virtual void onFingerDown(uint32_t x, uint32_t y, float minor, float major) {};
virtual void onFingerUp() {};
virtual void onAcquired(int32_t result, int32_t vendorCode) = 0;
virtual void cancel() = 0;
virtual void onAcquired(int32_t result, int32_t vendorCode) {};
virtual void onAuthenticationSucceeded() {};
virtual void onAuthenticationFailed() {};
virtual void cancel() {};
};
struct UdfpsHandlerFactory {

View File

@@ -14,7 +14,6 @@ cc_binary {
relative_install_path: "hw",
srcs: [
"BiometricsFingerprint.cpp",
"UdfpsHandler.cpp",
"service.cpp",
],
@@ -31,24 +30,9 @@ cc_binary {
"android.hardware.biometrics.fingerprint@2.3",
],
static_libs: [
"libudfpshandlerfactory",
],
header_libs: ["xiaomifingerprint_headers"],
}
cc_library_headers {
name: "xiaomifingerprint_headers",
export_include_dirs: ["include"],
vendor: true,
header_libs: ["libhardware_headers"],
export_header_lib_headers: ["libhardware_headers"],
}
cc_library_static {
name: "libudfps_extension.xiaomi",
srcs: ["UdfpsExtension.cpp"],
include_dirs: [
"frameworks/native/services/surfaceflinger/CompositionEngine/include",
],
header_libs: [
"generated_kernel_headers",
],
}

View File

@@ -1,45 +0,0 @@
//
// Copyright (C) 2022 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
soong_config_module_type {
name: "xiaomi_touch_hal_cc_defaults",
module_type: "cc_defaults",
config_namespace: "XIAOMI_TOUCH",
value_variables: ["HIGH_TOUCH_POLLING_PATH"],
properties: ["cppflags"],
}
xiaomi_touch_hal_cc_defaults {
name: "xiaomi_touch_hal_defaults",
soong_config_variables: {
HIGH_TOUCH_POLLING_PATH: {
cppflags: ["-DHIGH_TOUCH_POLLING_PATH=\"%s\""],
},
},
}
cc_binary {
name: "vendor.lineage.touch@1.0-service.xiaomi",
defaults: [
"hidl_defaults",
"xiaomi_touch_hal_defaults",
],
vintf_fragments: ["vendor.lineage.touch@1.0-service.xiaomi.xml"],
init_rc: ["vendor.lineage.touch@1.0-service.xiaomi.rc"],
relative_install_path: "hw",
proprietary: true,
srcs: [
"HighTouchPollingRate.cpp",
"service.cpp",
],
shared_libs: [
"libbase",
"libbinder",
"libhidlbase",
"libutils",
"vendor.lineage.touch@1.0",
],
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (C) 2022 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "HighTouchPollingRateService"
#include "HighTouchPollingRate.h"
#include <fstream>
namespace vendor {
namespace lineage {
namespace touch {
namespace V1_0 {
namespace implementation {
Return<bool> HighTouchPollingRate::isEnabled() {
std::ifstream file(HIGH_TOUCH_POLLING_PATH);
int enabled;
file >> enabled;
return enabled == 1;
}
Return<bool> HighTouchPollingRate::setEnabled(bool enabled) {
std::ofstream file(HIGH_TOUCH_POLLING_PATH);
file << (enabled ? "1" : "0");
return !file.fail();
}
} // namespace implementation
} // namespace V1_0
} // namespace touch
} // namespace lineage
} // namespace vendor

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2022 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <vendor/lineage/touch/1.0/IHighTouchPollingRate.h>
namespace vendor {
namespace lineage {
namespace touch {
namespace V1_0 {
namespace implementation {
using ::android::hardware::Return;
class HighTouchPollingRate : public IHighTouchPollingRate {
public:
// Methods from ::vendor::lineage::touch::V1_0::IHighTouchPollingRate follow.
Return<bool> isEnabled() override;
Return<bool> setEnabled(bool enabled) override;
};
} // namespace implementation
} // namespace V1_0
} // namespace touch
} // namespace lineage
} // namespace vendor

View File

@@ -1,33 +0,0 @@
/*
* Copyright (C) 2022 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "lineage.touch@1.0-service.xiaomi"
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include "HighTouchPollingRate.h"
using ::vendor::lineage::touch::V1_0::IHighTouchPollingRate;
using ::vendor::lineage::touch::V1_0::implementation::HighTouchPollingRate;
int main() {
android::sp<IHighTouchPollingRate> highTouchPollingRate = new HighTouchPollingRate();
android::hardware::configureRpcThreadpool(1, true);
if (highTouchPollingRate->registerAsService() != android::OK) {
LOG(ERROR) << "Cannot register touchscreen high polling rate HAL service.";
return 1;
}
LOG(INFO) << "Touchscreen HAL service ready.";
android::hardware::joinRpcThreadpool();
LOG(ERROR) << "Touchscreen HAL service failed to join thread pool.";
return 1;
}

View File

@@ -1,5 +0,0 @@
service vendor.touch-hal-1-0 /vendor/bin/hw/vendor.lineage.touch@1.0-service.xiaomi
interface vendor.lineage.touch@1.0::IHighTouchPollingRate default
class hal
user system
group system

View File

@@ -1,3 +1,8 @@
//
// SPDX-FileCopyrightText: 2020-2025 The LineageOS Project
// SPDX-License-Identifier: Apache-2.0
//
hidl_package_root {
name: "com.fingerprints",
path: "hardware/xiaomi/interfaces/fingerprints",
@@ -12,3 +17,129 @@ hidl_package_root {
name: "vendor.xiaomi",
path: "hardware/xiaomi/interfaces/xiaomi",
}
prebuilt_hidl_interfaces {
name: "hidl_com_fingerprints_extension_interface",
interfaces: [
"com.fingerprints.extension@3.0::IFingerprintAuthenticator",
"com.fingerprints.extension@3.0::IFingerprintCalibration",
"com.fingerprints.extension@3.0::IFingerprintEngineering",
"com.fingerprints.extension@3.0::IFingerprintNavigation",
"com.fingerprints.extension@3.0::IFingerprintOptical",
"com.fingerprints.extension@3.0::IFingerprintRecalibration",
"com.fingerprints.extension@3.0::IFingerprintSenseTouch",
"com.fingerprints.extension@3.0::IFingerprintSensorTest",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_focaltech_fingerprint_interface",
interfaces: [
"vendor.focaltech.fingerprint@1.0::IFocalFingerprintService",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_goodix_hardware_cap_biometrics_fingerprint_interface",
interfaces: [
"vendor.goodix.hardware.cap.biometrics.fingerprint@2.1::IGoodixFingerprintDaemon",
"vendor.goodix.hardware.cap.biometrics.fingerprint@2.1::IGoodixFingerprintDaemonExt",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_pixelworks_hardware_display_interface",
interfaces: [
"vendor.pixelworks.hardware.display@1.0::IIris",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_silead_hardware_fingerprintext_interface",
interfaces: [
"vendor.silead.hardware.fingerprintext@1.0::ISileadFingerprint",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_synaptics_fingerprints_interfaces_extensions_interface",
interfaces: [
"vendor.synaptics.fingerprints.interfaces.extensions@1.0::IFpCollection",
"vendor.synaptics.fingerprints.interfaces.extensions@1.0::INavigation",
"vendor.synaptics.fingerprints.interfaces.extensions@1.0::ISensorTest",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_hardware_bgservice_interface",
interfaces: [
"vendor.xiaomi.hardware.bgservice@1.0::IBGService",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_hardware_cameraperf_interface",
interfaces: [
"vendor.xiaomi.hardware.cameraperf@1.0::IMiCameraPerfService",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_hardware_campostproc_interface",
interfaces: [
"vendor.xiaomi.hardware.campostproc@1.0::IMiPostProcService",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_hardware_citsensorservice_interface",
interfaces: [
"vendor.xiaomi.hardware.citsensorservice@1.0::ICitSensorService",
"vendor.xiaomi.hardware.citsensorservice@1.1::ICitSensorService",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_hardware_dtool_interface",
interfaces: [
"vendor.xiaomi.hardware.dtool@1.0::IDtool",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_hardware_micharge_interface",
interfaces: [
"vendor.xiaomi.hardware.micharge@1.0::IMiCharge",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_hardware_quickcamera_interface",
interfaces: [
"vendor.xiaomi.hardware.quickcamera@1.0::IQuickCameraService",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_hardware_tidaservice_interface",
interfaces: [
"vendor.xiaomi.hardware.tidaservice@1.0::ITidaService",
"vendor.xiaomi.hardware.tidaservice@1.1::ITidaService",
"vendor.xiaomi.hardware.tidaservice@1.2::ITidaService",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_sensor_citsensorservice_interface",
interfaces: [
"vendor.xiaomi.sensor.citsensorservice@1.1::ICitSensorService",
"vendor.xiaomi.sensor.citsensorservice@2.0::ICitSensorService",
],
}
prebuilt_hidl_interfaces {
name: "hidl_vendor_xiaomi_sensor_communicate_interface",
interfaces: [
"vendor.xiaomi.sensor.communicate@1.0::ISensorCommunicate",
],
}

View File

@@ -19,12 +19,12 @@ package vendor.xiaomi.hardware.displayfeature@1.0;
import @1.0::IDisplayFeatureCallback;
interface IDisplayFeature {
notifyBrightness(uint32_t brightness);
registerCallback(uint32_t displayId, IDisplayFeatureCallback callback) generates (Status status);
sendMessage(uint32_t index, uint32_t value, string cmd);
sendPanelCommand(string cmd) generates (Status status);
sendPostProcCommand(uint32_t cmd, uint32_t value) generates (Status status);
sendRefreshCommand() generates (Status status);
setFeature(uint32_t displayId, uint32_t caseId, uint32_t modeId, uint32_t cookie) generates (Status status);
registerCallback(uint32_t displayId, IDisplayFeatureCallback callback) generates (Status status);
setFunction(uint32_t displayId, uint32_t caseId, uint32_t modeId, uint32_t cookie) generates (Status status);
sendMessage(uint32_t index, uint32_t value, string cmd);
notifyBrightness(uint32_t brightness);
sendPanelCommand(string cmd) generates (Status status);
sendRefreshCommand() generates (Status status);
sendPostProcCommand(uint32_t cmd, uint32_t value) generates (Status status);
};

View File

@@ -0,0 +1,27 @@
aidl_interface {
name: "vendor.xiaomi.hardware.displayfeature",
vendor_available: true,
srcs: [
"vendor/xiaomi/hardware/displayfeature_aidl/*.aidl",
],
stability: "vintf",
backend: {
java: {
sdk_version: "module_current",
min_sdk_version: "30",
lint: {
// Disable linter to avoid error about fixed size arrays.
// Interface will only be accessed on devices >= U.
enabled: false,
},
},
},
owner: "xiaomi",
versions_with_info: [
{
version: "2",
imports: [],
},
],
frozen: true,
}

View File

@@ -0,0 +1 @@
cd486b29c0e2df9789995f54ffb594530db39428

View File

@@ -0,0 +1,15 @@
package vendor.xiaomi.hardware.displayfeature_aidl;
import vendor.xiaomi.hardware.displayfeature_aidl.IDisplayFeatureCallback;
@VintfStability
interface IDisplayFeature {
void notifyBrightness(int brightness);
void registerCallback(int displayId, IDisplayFeatureCallback callback);
void sendMessage(int messageId, int param, String message);
void sendPanelCommand(String command);
void sendPostProcCommand(int commandId, int param);
void sendRefreshCommand();
void setFeature(int featureId, int param1, int param2, int param3);
void setFunction(int functionId, int param1, int param2, int param3);
}

View File

@@ -0,0 +1,6 @@
package vendor.xiaomi.hardware.displayfeature_aidl;
@VintfStability
interface IDisplayFeatureCallback {
float displayfeatureInfoChanged(int displayId, int caseId, float modeId, float cookie);
}

View File

@@ -0,0 +1,30 @@
///////////////////////////////////////////////////////////////////////////////
// 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.xiaomi.hardware.displayfeature_aidl;
@VintfStability
interface IDisplayFeature {
void notifyBrightness(int brightness);
void registerCallback(int displayId, vendor.xiaomi.hardware.displayfeature_aidl.IDisplayFeatureCallback callback);
void sendMessage(int messageId, int param, String message);
void sendPanelCommand(String command);
void sendPostProcCommand(int commandId, int param);
void sendRefreshCommand();
void setFeature(int featureId, int param1, int param2, int param3);
void setFunction(int functionId, int param1, int param2, int param3);
}

View File

@@ -0,0 +1,23 @@
///////////////////////////////////////////////////////////////////////////////
// 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.xiaomi.hardware.displayfeature_aidl;
@VintfStability
interface IDisplayFeatureCallback {
float displayfeatureInfoChanged(int displayId, int caseId, float modeId, float cookie);
}

View File

@@ -0,0 +1,15 @@
package vendor.xiaomi.hardware.displayfeature_aidl;
import vendor.xiaomi.hardware.displayfeature_aidl.IDisplayFeatureCallback;
@VintfStability
interface IDisplayFeature {
void notifyBrightness(int brightness);
void registerCallback(int displayId, IDisplayFeatureCallback callback);
void sendMessage(int messageId, int param, String message);
void sendPanelCommand(String command);
void sendPostProcCommand(int commandId, int param);
void sendRefreshCommand();
void setFeature(int featureId, int param1, int param2, int param3);
void setFunction(int functionId, int param1, int param2, int param3);
}

View File

@@ -0,0 +1,6 @@
package vendor.xiaomi.hardware.displayfeature_aidl;
@VintfStability
interface IDisplayFeatureCallback {
float displayfeatureInfoChanged(int displayId, int caseId, float modeId, float cookie);
}

View File

@@ -0,0 +1,27 @@
aidl_interface {
name: "vendor.xiaomi.hardware.fingerprintextension",
vendor_available: true,
srcs: [
"vendor/xiaomi/hardware/fingerprintextension/*.aidl",
],
stability: "vintf",
backend: {
java: {
sdk_version: "module_current",
min_sdk_version: "30",
lint: {
// Disable linter to avoid error about fixed size arrays.
// Interface will only be accessed on devices >= U.
enabled: false,
},
},
},
owner: "xiaomi",
versions_with_info: [
{
version: "1",
imports: [],
},
],
frozen: true,
}

View File

@@ -0,0 +1 @@
86a025226d979f72a91d348bd1f5e904e4ac64a1

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