[PM-30394] PM-29960: Skip biometric prompt on Xiaomi HyperOS (#6316)

This commit is contained in:
Gavin Gui 2026-01-14 09:08:57 -07:00 committed by GitHub
parent 2d824f96f5
commit 353e7e9a4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 41 additions and 2 deletions

View File

@ -7,6 +7,7 @@ import androidx.credentials.provider.PasswordCredentialEntry
import androidx.credentials.provider.PublicKeyCredentialEntry
import com.bitwarden.annotation.OmitFromCoverage
import com.bitwarden.core.util.isBuildVersionAtLeast
import com.bitwarden.core.util.isHyperOS
import javax.crypto.Cipher
/**
@ -15,7 +16,7 @@ import javax.crypto.Cipher
fun PublicKeyCredentialEntry.Builder.setBiometricPromptDataIfSupported(
cipher: Cipher?,
): PublicKeyCredentialEntry.Builder =
if (isBuildVersionAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM) && cipher != null) {
if (isBiometricPromptDataSupported() && cipher != null) {
setBiometricPromptData(
biometricPromptData = buildPromptDataWithCipher(cipher),
)
@ -29,10 +30,19 @@ fun PublicKeyCredentialEntry.Builder.setBiometricPromptDataIfSupported(
fun PasswordCredentialEntry.Builder.setBiometricPromptDataIfSupported(
cipher: Cipher?,
): PasswordCredentialEntry.Builder =
if (isBuildVersionAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM) && cipher != null) {
if (isBiometricPromptDataSupported() && cipher != null) {
setBiometricPromptData(
biometricPromptData = buildPromptDataWithCipher(cipher),
)
} else {
this
}
/**
* Returns whether biometric prompt data is supported on this device.
* Note: Xiaomi HyperOS is known to be incompatible.
*/
private fun isBiometricPromptDataSupported(): Boolean {
return isBuildVersionAtLeast(Build.VERSION_CODES.VANILLA_ICE_CREAM) &&
!isHyperOS()
}

View File

@ -0,0 +1,29 @@
@file:OmitFromCoverage
package com.bitwarden.core.util
import com.bitwarden.annotation.OmitFromCoverage
private const val KEY_XIAOMI_HYPER_OS_NAME = "ro.mi.os.version.name"
/**
* Returns true if the device is running Xiaomi HyperOS.
*/
fun isHyperOS(): Boolean = !getSystemProperty(KEY_XIAOMI_HYPER_OS_NAME).isNullOrEmpty()
/**
* Reads an Android system property using the android.os.SystemProperties API
*
* @param key the name of the system property
* @return the property value, or null if unavailable
*/
@Suppress("SameParameterValue", "PrivateApi")
private fun getSystemProperty(key: String): String? {
return try {
val systemProperties = Class.forName("android.os.SystemProperties")
val getMethod = systemProperties.getMethod("get", String::class.java)
getMethod.invoke(null, key) as? String
} catch (_: Throwable) {
null
}
}