Compare commits
35 Commits
vic
...
bka-no-dol
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24d924a690 | ||
|
|
3f98ab0409 | ||
|
|
fdb7f5a07c | ||
|
|
9918fab7e8 | ||
|
|
73460c17a7 | ||
|
|
b70a8d1901 | ||
|
|
f29df9dd3b | ||
|
|
bd29fa8f94 | ||
|
|
307bed2f81 | ||
|
|
c556e4a329 | ||
|
|
16e431ce2f | ||
|
|
8c2abcf067 | ||
|
|
6bb35480ed | ||
|
|
5a02b6a1c4 | ||
|
|
cf8dc72b88 | ||
|
|
e0435f1a92 | ||
|
|
d44baa90c8 | ||
|
|
3846de048d | ||
|
|
8b9f87316a | ||
|
|
181b9c2f75 | ||
|
|
ea30c0736a | ||
|
|
91d15fa7af | ||
|
|
dbf0dc9428 | ||
|
|
2c14234077 | ||
|
|
f18dcb8e17 | ||
|
|
aae52ffce4 | ||
|
|
f677ebecd8 | ||
|
|
40ef19ab76 | ||
|
|
e400c781e8 | ||
|
|
b0a11aa8b4 | ||
|
|
5bb09cf6fa | ||
|
|
2eaa37731a | ||
|
|
04c945f5b3 | ||
|
|
15e7009f6f | ||
|
|
94a8ea7957 |
@@ -1 +0,0 @@
|
||||
../../build/soong/scripts/system-clang-format
|
||||
13
.clang-format
Normal file
13
.clang-format
Normal 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
13
.github/workflows/build/action.yml
vendored
Normal 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
38
.github/workflows/gerrit.yml
vendored
Normal 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
20
.pre-commit-config.yaml
Normal 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]
|
||||
48
DSPVolumeSynchronizer/Android.bp
Normal file
48
DSPVolumeSynchronizer/Android.bp
Normal 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,
|
||||
}
|
||||
30
DSPVolumeSynchronizer/AndroidManifest.xml
Normal file
30
DSPVolumeSynchronizer/AndroidManifest.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.lineageos.dspvolume.xiaomi"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
android:sharedUserId="android.uid.system">
|
||||
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
|
||||
<application
|
||||
android:label="@string/app_name"
|
||||
android:persistent="true"
|
||||
android:defaultToDeviceProtectedStorage="true"
|
||||
android:directBootAware="true">
|
||||
|
||||
<receiver
|
||||
android:name=".BootReceiver"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
|
||||
<intent-filter android:priority="999">
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service
|
||||
android:name=".VolumeListenerService" />
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
5
DSPVolumeSynchronizer/config-dspvolume.xml
Normal file
5
DSPVolumeSynchronizer/config-dspvolume.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<config>
|
||||
<allow-in-power-save package="org.lineageos.dspvolume.xiaomi" />
|
||||
<hidden-api-whitelisted-app package="org.lineageos.dspvolume.xiaomi" />
|
||||
</config>
|
||||
@@ -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>
|
||||
9
DSPVolumeSynchronizer/privapp-permissions-dspvolume.xml
Normal file
9
DSPVolumeSynchronizer/privapp-permissions-dspvolume.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<permissions>
|
||||
<privapp-permissions package="org.lineageos.dspvolume.xiaomi">
|
||||
<permission name="android.permission.INTERACT_ACROSS_USERS" />
|
||||
<permission name="android.permission.INTERACT_ACROSS_USERS_FULL" />
|
||||
<permission name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<permission name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
</privapp-permissions>
|
||||
</permissions>
|
||||
5
DSPVolumeSynchronizer/res/values/strings.xml
Normal file
5
DSPVolumeSynchronizer/res/values/strings.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- App Name -->
|
||||
<string name="app_name">DSP Volume Synchronizer</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.lineageos.dspvolume.xiaomi;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
context.startService(new Intent(context, VolumeListenerService.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.lineageos.dspvolume.xiaomi;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.util.Log;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class VolumeListenerReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(intent.getIntExtra("android.media.EXTRA_VOLUME_STREAM_TYPE", 0) == AudioManager.STREAM_MUSIC) {
|
||||
AudioManager audioManager = context.getSystemService(AudioManager.class);
|
||||
int current = intent.getIntExtra(
|
||||
"android.media.EXTRA_VOLUME_STREAM_VALUE",
|
||||
0
|
||||
);
|
||||
audioManager.setParameters("volume_change=" + current + ";flags=8");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.lineageos.dspvolume.xiaomi;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class VolumeListenerService extends Service {
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction("android.media.VOLUME_CHANGED_ACTION");
|
||||
registerReceiver(new VolumeListenerReceiver(), intentFilter);
|
||||
|
||||
AudioManager audioManager = getSystemService(AudioManager.class);
|
||||
int current = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
|
||||
audioManager.setParameters("volume_change=" + current + ";flags=8");
|
||||
|
||||
return super.onStartCommand(intent, flags, startId);
|
||||
}
|
||||
}
|
||||
@@ -1,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",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,4 @@ service vendor.fingerprint-default /vendor/bin/hw/android.hardware.biometrics.fi
|
||||
group system input uhid
|
||||
capabilities SYS_NICE
|
||||
shutdown critical
|
||||
task_profiles ProcessCapacityHigh MaxPerformance
|
||||
|
||||
48
aidl/health/Android.bp
Normal file
48
aidl/health/Android.bp
Normal 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"],
|
||||
}
|
||||
14
aidl/health/android.hardware.health-service.xiaomi.rc
Normal file
14
aidl/health/android.hardware.health-service.xiaomi.rc
Normal 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
|
||||
12
aidl/health/android.hardware.health-service.xiaomi.xml
Normal file
12
aidl/health/android.hardware.health-service.xiaomi.xml
Normal 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>
|
||||
@@ -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
123
aidl/health/main.cpp
Normal 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();
|
||||
}
|
||||
@@ -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,7 +39,7 @@ 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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
27
interfaces/xiaomi/hardware/displayfeature/aidl/Android.bp
Normal file
27
interfaces/xiaomi/hardware/displayfeature/aidl/Android.bp
Normal 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,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
cd486b29c0e2df9789995f54ffb594530db39428
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package vendor.xiaomi.hardware.displayfeature_aidl;
|
||||
|
||||
@VintfStability
|
||||
interface IDisplayFeatureCallback {
|
||||
float displayfeatureInfoChanged(int displayId, int caseId, float modeId, float cookie);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package vendor.xiaomi.hardware.displayfeature_aidl;
|
||||
|
||||
@VintfStability
|
||||
interface IDisplayFeatureCallback {
|
||||
float displayfeatureInfoChanged(int displayId, int caseId, float modeId, float cookie);
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
86a025226d979f72a91d348bd1f5e904e4ac64a1
|
||||
@@ -0,0 +1,6 @@
|
||||
package vendor.xiaomi.hardware.fingerprintextension;
|
||||
|
||||
@VintfStability
|
||||
interface IXiaomiFingerprint {
|
||||
int extCmd(int cmd, int param1);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
30ed1571b7fec61cb1386b8d3a2081c88db6283e
|
||||
@@ -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.fingerprintextension;
|
||||
@VintfStability
|
||||
interface IXiaomiFingerprint {
|
||||
int extCmd(int cmd, int param1);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package vendor.xiaomi.hardware.fingerprintextension;
|
||||
|
||||
@VintfStability
|
||||
interface IXiaomiFingerprint {
|
||||
int extCmd(int cmd, int param1);
|
||||
}
|
||||
27
interfaces/xiaomi/hw/touchfeature/aidl/Android.bp
Normal file
27
interfaces/xiaomi/hw/touchfeature/aidl/Android.bp
Normal file
@@ -0,0 +1,27 @@
|
||||
aidl_interface {
|
||||
name: "vendor.xiaomi.hw.touchfeature",
|
||||
vendor_available: true,
|
||||
srcs: [
|
||||
"vendor/xiaomi/hw/touchfeature/*.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,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
2c3f4fe227305cd02c47fd3e1f847ac139b353cf
|
||||
@@ -0,0 +1,14 @@
|
||||
package vendor.xiaomi.hw.touchfeature;
|
||||
|
||||
@VintfStability
|
||||
interface ITouchFeature {
|
||||
int getModeCurValueString(int touchId, int mode);
|
||||
int getModeValues(int touchId, int mode);
|
||||
int getTouchModeCurValue(int touchId, int mode);
|
||||
int getTouchModeDefValue(int touchId, int mode);
|
||||
int getTouchModeMaxValue(int touchId, int mode);
|
||||
int getTouchModeMinValue(int touchId, int mode);
|
||||
boolean resetTouchMode(int touchId, int mode);
|
||||
boolean setEdgeMode(int touchId, int mode, in int[] value, int length);
|
||||
void setTouchMode(int touchId, int mode, int value);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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.hw.touchfeature;
|
||||
@VintfStability
|
||||
interface ITouchFeature {
|
||||
int getModeCurValueString(int touchId, int mode);
|
||||
int getModeValues(int touchId, int mode);
|
||||
int getTouchModeCurValue(int touchId, int mode);
|
||||
int getTouchModeDefValue(int touchId, int mode);
|
||||
int getTouchModeMaxValue(int touchId, int mode);
|
||||
int getTouchModeMinValue(int touchId, int mode);
|
||||
boolean resetTouchMode(int touchId, int mode);
|
||||
boolean setEdgeMode(int touchId, int mode, in int[] value, int length);
|
||||
void setTouchMode(int touchId, int mode, int value);
|
||||
}
|
||||
31
interfaces/xiaomi/hw/touchfeature/aidl/vendor/xiaomi/hw/touchfeature/ITouchFeature.aidl
vendored
Normal file
31
interfaces/xiaomi/hw/touchfeature/aidl/vendor/xiaomi/hw/touchfeature/ITouchFeature.aidl
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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.hw.touchfeature;
|
||||
@VintfStability
|
||||
interface ITouchFeature {
|
||||
int getModeCurValueString(int touchId, int mode);
|
||||
int getModeValues(int touchId, int mode);
|
||||
int getTouchModeCurValue(int touchId, int mode);
|
||||
int getTouchModeDefValue(int touchId, int mode);
|
||||
int getTouchModeMaxValue(int touchId, int mode);
|
||||
int getTouchModeMinValue(int touchId, int mode);
|
||||
boolean resetTouchMode(int touchId, int mode);
|
||||
boolean setEdgeMode(int touchId, int mode, in int[] value, int length);
|
||||
void setTouchMode(int touchId, int mode, int value);
|
||||
}
|
||||
@@ -2,42 +2,19 @@
|
||||
* Copyright (C) 2022 The LineageOS Project
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
*/
|
||||
|
||||
static int stub_fail() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char *stub_fail_str() {
|
||||
static char* stub_fail_str() {
|
||||
return "stub";
|
||||
}
|
||||
|
||||
void *mg_facepp[] = {
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail_str,
|
||||
&stub_fail_str,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
&stub_fail,
|
||||
void* mg_facepp[] = {
|
||||
&stub_fail, &stub_fail, &stub_fail, &stub_fail_str, &stub_fail_str, &stub_fail, &stub_fail,
|
||||
&stub_fail, &stub_fail, &stub_fail, &stub_fail, &stub_fail, &stub_fail, &stub_fail,
|
||||
&stub_fail, &stub_fail, &stub_fail, &stub_fail, &stub_fail, &stub_fail, &stub_fail,
|
||||
&stub_fail, &stub_fail, &stub_fail, &stub_fail, &stub_fail, &stub_fail,
|
||||
};
|
||||
|
||||
18
packages/Euicc/Android.bp
Normal file
18
packages/Euicc/Android.bp
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
//
|
||||
// SPDX-FileCopyrightText: The LineageOS Project
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
phony {
|
||||
name: "XiaomiEuicc",
|
||||
required: [
|
||||
"EuiccPolicy",
|
||||
"EuiccPolicyXiaomi",
|
||||
],
|
||||
}
|
||||
|
||||
runtime_resource_overlay {
|
||||
name: "EuiccPolicyXiaomi",
|
||||
product_specific: true,
|
||||
}
|
||||
10
packages/Euicc/AndroidManifest.xml
Normal file
10
packages/Euicc/AndroidManifest.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.lineageos.euicc.overlay.xiaomi">
|
||||
<overlay android:targetPackage="org.lineageos.euicc"
|
||||
android:isStatic="true" />
|
||||
</manifest>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
42
packages/Euicc/res/values/strings.xml
Normal file
42
packages/Euicc/res/values/strings.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
SPDX-FileCopyrightText: The LineageOS Project
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<resources>
|
||||
<string name="sim_slot_mappings_json" translatable="false">
|
||||
{
|
||||
\"sim-slot-mappings\": [
|
||||
{
|
||||
\"devices\": [
|
||||
\"XIG05\",
|
||||
\"fuxi\",
|
||||
\"garnet\",
|
||||
\"nuwa\"
|
||||
],
|
||||
\"esim-slot-ids\": [
|
||||
1
|
||||
],
|
||||
\"psim-slot-ids\": [
|
||||
0
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</string>
|
||||
<string name="sim_illustration_lottie_mappings_json" translatable="false">
|
||||
{
|
||||
\"sim_illustration_lottie_mappings\": [
|
||||
{
|
||||
\"devices\": [
|
||||
\"XIG05\",
|
||||
\"fuxi\",
|
||||
\"garnet\",
|
||||
\"nuwa\"
|
||||
],
|
||||
\"illustration_lottie\": \"sim_illustration_lottie_bottom\"
|
||||
}
|
||||
]
|
||||
}
|
||||
</string>
|
||||
</resources>
|
||||
188
packages/IFAAService/src/org/ifaa/aidl/manager/IfaaService.kt
Normal file
188
packages/IFAAService/src/org/ifaa/aidl/manager/IfaaService.kt
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2025 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.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 -> {
|
||||
applicationContext.startActivity(
|
||||
Intent(Settings.ACTION_SECURITY_SETTINGS).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
)
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <string.h>
|
||||
#include <utils/SystemClock.h>
|
||||
|
||||
static const char *udfps_state_paths[] = {
|
||||
static const char* udfps_state_paths[] = {
|
||||
"/sys/devices/virtual/touch/tp_dev/fp_state",
|
||||
"/sys/touchpanel/fp_state",
|
||||
NULL,
|
||||
|
||||
@@ -221,7 +221,7 @@ SysfsPollingOneShotSensor::SysfsPollingOneShotSensor(
|
||||
int32_t sensorHandle, ISensorsEventCallback* callback, const std::string& pollPath,
|
||||
const std::string& enablePath, const std::string& name, const std::string& typeAsString,
|
||||
SensorType type)
|
||||
: OneShotSensor(sensorHandle, callback) {
|
||||
: OneShotSensor(sensorHandle, callback), mEnablePath(enablePath) {
|
||||
mSensorInfo.name = name;
|
||||
mSensorInfo.type = type;
|
||||
mSensorInfo.typeAsString = typeAsString;
|
||||
@@ -230,8 +230,6 @@ SysfsPollingOneShotSensor::SysfsPollingOneShotSensor(
|
||||
mSensorInfo.power = 0;
|
||||
mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
|
||||
|
||||
mEnableStream.open(enablePath);
|
||||
|
||||
int rc;
|
||||
|
||||
rc = pipe(mWaitPipeFd);
|
||||
@@ -267,8 +265,12 @@ SysfsPollingOneShotSensor::~SysfsPollingOneShotSensor() {
|
||||
}
|
||||
|
||||
void SysfsPollingOneShotSensor::writeEnable(bool enable) {
|
||||
std::call_once(mEnableOpenOnce, [&] { mEnableStream.open(mEnablePath); });
|
||||
|
||||
if (mEnableStream) {
|
||||
mEnableStream << (enable ? '1' : '0') << std::flush;
|
||||
} else {
|
||||
ALOGE("Failed to write enable to %s", mEnablePath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace implementation {
|
||||
|
||||
class ISensorsEventCallback {
|
||||
public:
|
||||
virtual ~ISensorsEventCallback(){};
|
||||
virtual ~ISensorsEventCallback() {};
|
||||
virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
|
||||
};
|
||||
|
||||
@@ -119,6 +119,8 @@ class SysfsPollingOneShotSensor : public OneShotSensor {
|
||||
struct pollfd mPolls[2];
|
||||
int mWaitPipeFd[2];
|
||||
int mPollFd;
|
||||
std::string mEnablePath;
|
||||
std::once_flag mEnableOpenOnce;
|
||||
};
|
||||
|
||||
class DoubleTapSensor : public SysfsPollingOneShotSensor {
|
||||
|
||||
@@ -14,8 +14,5 @@ cc_library_shared {
|
||||
"libcutils",
|
||||
"libutils",
|
||||
],
|
||||
static_libs: [
|
||||
"libc++fs",
|
||||
],
|
||||
export_include_dirs: ["."],
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
SPDX-License-Identifier: Apache-2.0
|
||||
-->
|
||||
<compatibility-matrix version="1.0" type="framework">
|
||||
<hal format="hidl" optional="true">
|
||||
<name>android.hardware.media.c2</name>
|
||||
<version>1.0</version>
|
||||
<interface>
|
||||
<name>IComponentStore</name>
|
||||
<instance>dolby</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>com.fingerprints.extension</name>
|
||||
<version>1.0</version>
|
||||
@@ -89,6 +97,30 @@
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>vendor.dolby.hardware.dms</name>
|
||||
<version>2.0</version>
|
||||
<interface>
|
||||
<name>IDms</name>
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>vendor.dolby_sp.hardware.dmssp</name>
|
||||
<version>2.0</version>
|
||||
<interface>
|
||||
<name>IDms</name>
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>vendor.dolby_v3_6.hardware.dms360</name>
|
||||
<version>2.0</version>
|
||||
<interface>
|
||||
<name>IDms</name>
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>vendor.goodix.hardware.fingerprintextension</name>
|
||||
<version>1.0</version>
|
||||
@@ -209,6 +241,17 @@
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>vendor.xiaomi.hardware.misys</name>
|
||||
<version>1.0</version>
|
||||
<version>2.0</version>
|
||||
<version>3.0</version>
|
||||
<version>4.0</version>
|
||||
<interface>
|
||||
<name>IMiSys</name>
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>vendor.xiaomi.hardware.mlipay</name>
|
||||
<version>1.0-1</version>
|
||||
@@ -249,6 +292,14 @@
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>vendor.xiaomi.hw.touchfeature</name>
|
||||
<version>1.0</version>
|
||||
<interface>
|
||||
<name>ITouchFeature</name>
|
||||
<instance>default</instance>
|
||||
</interface>
|
||||
</hal>
|
||||
<hal format="hidl" optional="true">
|
||||
<name>vendor.xiaomi.sensor.citsensorservice</name>
|
||||
<version>1.1</version>
|
||||
|
||||
Reference in New Issue
Block a user