291 lines
12 KiB
Python
291 lines
12 KiB
Python
"""
|
|
Android Biometrics 组件 — BiometricManager, BiometricPrompt, 等
|
|
方法签名完全对齐 Android SDK
|
|
"""
|
|
|
|
from typing import Any, Callable, Dict, List, Optional, Tuple
|
|
|
|
from .._core import Stub, AndroidOnlyError, android_context
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# BiometricConstants
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class BiometricConstants(Stub):
|
|
"""BiometricConstants — 生物识别常量"""
|
|
|
|
BIOMETRIC_SUCCESS = 0
|
|
BIOMETRIC_ERROR_HW_UNAVAILABLE = 1
|
|
BIOMETRIC_ERROR_VENDOR = 8
|
|
BIOMETRIC_ERROR_LOCKOUT = 7
|
|
BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 9
|
|
BIOMETRIC_ERROR_USER_CANCELED = 10
|
|
BIOMETRIC_ERROR_NO_BIOMETRIC = 11
|
|
BIOMETRIC_ERROR_HW_NOT_PRESENT = 12
|
|
BIOMETRIC_ERROR_NEGATIVE_BUTTON = 13
|
|
BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14
|
|
BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = 15
|
|
BIOMETRIC_ERROR_UNSUPPORTED = 65536
|
|
BIOMETRIC_ERROR_CANCELED = 5
|
|
BIOMETRIC_ERROR_TIMEOUT = 3
|
|
BIOMETRIC_ERROR_NONE_ENROLLED = 11
|
|
BIOMETRIC_ERROR_NO_HARDWARE = 12
|
|
BIOMETRIC_STATUS_OK = 0
|
|
|
|
# Authenticator types
|
|
BIOMETRIC_STRONG = 0x0F
|
|
BIOMETRIC_WEAK = 0xFF
|
|
DEVICE_CREDENTIAL = 0x8000
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# BiometricPrompt
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class BiometricPrompt(Stub):
|
|
"""BiometricPrompt — 生物识别提示 (API 28+)"""
|
|
|
|
class AuthenticationCallback(Stub):
|
|
"""BiometricPrompt.AuthenticationCallback — 认证回调"""
|
|
|
|
def onAuthenticationError(self, errorCode: int, errString: str):
|
|
pass
|
|
|
|
def onAuthenticationSucceeded(self, result: "BiometricPrompt.AuthenticationResult"):
|
|
pass
|
|
|
|
def onAuthenticationFailed(self):
|
|
pass
|
|
|
|
def onAuthenticationAcquired(self, acquireInfo: int):
|
|
pass
|
|
|
|
class AuthenticationResult(Stub):
|
|
"""BiometricPrompt.AuthenticationResult — 认证结果"""
|
|
|
|
def __init__(self, cryptoObject: "BiometricPromptCryptoObject" = None,
|
|
authenticationType: int = BiometricConstants.BIOMETRIC_STRONG):
|
|
super().__init__()
|
|
self._crypto_object = cryptoObject
|
|
self._authentication_type = authenticationType
|
|
|
|
def getCryptoObject(self) -> Optional["BiometricPromptCryptoObject"]:
|
|
return self._crypto_object
|
|
|
|
def getAuthenticationType(self) -> int:
|
|
return self._authentication_type
|
|
|
|
class PromptInfo(Stub):
|
|
"""BiometricPrompt.PromptInfo — 提示信息"""
|
|
|
|
class Builder(Stub):
|
|
"""BiometricPrompt.PromptInfo.Builder — 提示信息构建器"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._title = ""
|
|
self._subtitle = ""
|
|
self._description = ""
|
|
self._device_credential_allowed = False
|
|
self._allowed_authenticators = 0
|
|
self._confirmation_required = True
|
|
self._negative_button_text = ""
|
|
|
|
def setTitle(self, title: str) -> "BiometricPrompt.PromptInfo.Builder":
|
|
self._title = title
|
|
return self
|
|
|
|
def setSubtitle(self, subtitle: str) -> "BiometricPrompt.PromptInfo.Builder":
|
|
self._subtitle = subtitle
|
|
return self
|
|
|
|
def setDescription(self, description: str) -> "BiometricPrompt.PromptInfo.Builder":
|
|
self._description = description
|
|
return self
|
|
|
|
def setDeviceCredentialAllowed(self, allowed: bool) -> "BiometricPrompt.PromptInfo.Builder":
|
|
self._device_credential_allowed = allowed
|
|
return self
|
|
|
|
def setAllowedAuthenticators(self, authenticators: int) -> "BiometricPrompt.PromptInfo.Builder":
|
|
self._allowed_authenticators = authenticators
|
|
return self
|
|
|
|
def setConfirmationRequired(self, required: bool) -> "BiometricPrompt.PromptInfo.Builder":
|
|
self._confirmation_required = required
|
|
return self
|
|
|
|
def setNegativeButtonText(self, text: str) -> "BiometricPrompt.PromptInfo.Builder":
|
|
self._negative_button_text = text
|
|
return self
|
|
|
|
def build(self) -> "BiometricPrompt.PromptInfo":
|
|
info = BiometricPrompt.PromptInfo()
|
|
info._title = self._title
|
|
info._subtitle = self._subtitle
|
|
info._description = self._description
|
|
info._device_credential_allowed = self._device_credential_allowed
|
|
info._allowed_authenticators = self._allowed_authenticators
|
|
info._confirmation_required = self._confirmation_required
|
|
info._negative_button_text = self._negative_button_text
|
|
return info
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
self._title = ""
|
|
self._subtitle = ""
|
|
self._description = ""
|
|
self._device_credential_allowed = False
|
|
self._allowed_authenticators = 0
|
|
self._confirmation_required = True
|
|
self._negative_button_text = ""
|
|
|
|
def getTitle(self) -> str:
|
|
return self._title
|
|
|
|
def getSubtitle(self) -> str:
|
|
return self._subtitle
|
|
|
|
def getDescription(self) -> str:
|
|
return self._description
|
|
|
|
def isDeviceCredentialAllowed(self) -> bool:
|
|
return self._device_credential_allowed
|
|
|
|
def getAllowedAuthenticators(self) -> int:
|
|
return self._allowed_authenticators
|
|
|
|
def isConfirmationRequired(self) -> bool:
|
|
return self._confirmation_required
|
|
|
|
def getNegativeButtonText(self) -> str:
|
|
return self._negative_button_text
|
|
|
|
def __init__(self, context, callback: AuthenticationCallback = None,
|
|
handler=None):
|
|
super().__init__()
|
|
self._context = context
|
|
self._callback = callback
|
|
self._cancelled = False
|
|
|
|
def authenticate(self, crypto: "BiometricPromptCryptoObject" = None,
|
|
cancel: Any = None, executor=None,
|
|
callback: AuthenticationCallback = None):
|
|
self._cancelled = False
|
|
if callback:
|
|
self._callback = callback
|
|
if self._callback:
|
|
# Simulate failed authentication on desktop
|
|
self._callback.onAuthenticationError(
|
|
BiometricConstants.BIOMETRIC_ERROR_NO_HARDWARE,
|
|
"No biometric hardware available on this device"
|
|
)
|
|
|
|
def authenticate(self, promptInfo: PromptInfo, crypto: "BiometricPromptCryptoObject" = None):
|
|
self._cancelled = False
|
|
if self._callback:
|
|
self._callback.onAuthenticationError(
|
|
BiometricConstants.BIOMETRIC_ERROR_NO_HARDWARE,
|
|
"No biometric hardware available on this device"
|
|
)
|
|
|
|
def cancelAuthentication(self):
|
|
self._cancelled = True
|
|
if self._callback:
|
|
self._callback.onAuthenticationError(
|
|
BiometricConstants.BIOMETRIC_ERROR_CANCELED,
|
|
"Authentication cancelled"
|
|
)
|
|
|
|
def cancel(self):
|
|
self.cancelAuthentication()
|
|
|
|
def isCancelled(self) -> bool:
|
|
return self._cancelled
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# BiometricPromptCryptoObject
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class BiometricPromptCryptoObject(Stub):
|
|
"""BiometricPromptCryptoObject — 加密对象"""
|
|
|
|
def __init__(self, signature=None, cipher=None, mac=None):
|
|
super().__init__()
|
|
self._signature = signature
|
|
self._cipher = cipher
|
|
self._mac = mac
|
|
|
|
def getSignature(self):
|
|
return self._signature
|
|
|
|
def getCipher(self):
|
|
return self._cipher
|
|
|
|
def getMac(self):
|
|
return self._mac
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# BiometricPromptAuthenticationResult
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
BiometricPromptAuthenticationResult = BiometricPrompt.AuthenticationResult
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# BiometricManager
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
class BiometricManager(Stub):
|
|
"""BiometricManager — 生物识别管理器 (API 29+)"""
|
|
|
|
BIOMETRIC_SUCCESS = BiometricConstants.BIOMETRIC_SUCCESS
|
|
BIOMETRIC_ERROR_HW_UNAVAILABLE = BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE
|
|
BIOMETRIC_ERROR_NONE_ENROLLED = BiometricConstants.BIOMETRIC_ERROR_NONE_ENROLLED
|
|
BIOMETRIC_ERROR_NO_HARDWARE = BiometricConstants.BIOMETRIC_ERROR_NO_HARDWARE
|
|
BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED = BiometricConstants.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED
|
|
BIOMETRIC_ERROR_UNSUPPORTED = BiometricConstants.BIOMETRIC_ERROR_UNSUPPORTED
|
|
BIOMETRIC_STATUS_OK = BiometricConstants.BIOMETRIC_STATUS_OK
|
|
BIOMETRIC_ERROR_VENDOR = BiometricConstants.BIOMETRIC_ERROR_VENDOR
|
|
BIOMETRIC_ERROR_USER_CANCELED = BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED
|
|
BIOMETRIC_ERROR_CANCELED = BiometricConstants.BIOMETRIC_ERROR_CANCELED
|
|
BIOMETRIC_ERROR_TIMEOUT = BiometricConstants.BIOMETRIC_ERROR_TIMEOUT
|
|
BIOMETRIC_ERROR_LOCKOUT = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT
|
|
BIOMETRIC_ERROR_LOCKOUT_PERMANENT = BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT
|
|
|
|
# Authenticators
|
|
AUTHENTICATOR_BIOMETRIC_STRONG = BiometricConstants.BIOMETRIC_STRONG
|
|
AUTHENTICATOR_BIOMETRIC_WEAK = BiometricConstants.BIOMETRIC_WEAK
|
|
AUTHENTICATOR_DEVICE_CREDENTIAL = BiometricConstants.DEVICE_CREDENTIAL
|
|
|
|
def __init__(self, context=None):
|
|
super().__init__()
|
|
self._context = context
|
|
|
|
def canAuthenticate(self, authenticators: int = AUTHENTICATOR_BIOMETRIC_STRONG) -> int:
|
|
"""Check if biometric authentication is available"""
|
|
return BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE
|
|
|
|
@staticmethod
|
|
def fromContext(context) -> "BiometricManager":
|
|
"""Get BiometricManager from context"""
|
|
return BiometricManager(context)
|
|
|
|
def toString(self) -> str:
|
|
return "BiometricManager(desktop - no hardware)"
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# __all__
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
__all__ = [
|
|
"BiometricManager",
|
|
"BiometricPrompt",
|
|
"BiometricPromptAuthenticationResult",
|
|
"BiometricPromptCryptoObject",
|
|
"BiometricConstants",
|
|
] |