自从Android Q API 29发布以来,AOSP就已經在推广建议使用统一的生物识别API,BiometricPrompt。
其号称兼容Iris, fingerprint, facekey.
那么这个怎么用呢?
举个栗子:
public static void showBiometricPromptDialog(Context context) {
final KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService(
Context.KEYGUARD_SERVICE);
if (keyguardManager.isKeyguardSecure()) {
final BiometricPrompt.AuthenticationCallback authenticationCallback =
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationSucceeded(
BiometricPrompt.AuthenticationResult result) {
//successRunnable.run();
Log.d("TAG", "onAuthenticationSucceeded: ");
}
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
//Do nothing
Log.d("TAG", "onAuthenticationError: " + errorCode + ", str: " + errString);
}
};
final Handler handler = new Handler(Looper.getMainLooper());
final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(context)
.setTitle("verify it is you?")
.setNegativeButton("Negative Btn", runnable -> handler.post(runnable), (dialog, which) -> {
Log.d("TAG", "showLockScreen: negative btn clicked, do nothing");
})
.setSubtitle("that is subtitile");
if (keyguardManager.isDeviceSecure()) {
builder.setDeviceCredentialAllowed(false);
}
final BiometricPrompt bp = builder.build();
bp.authenticate(new CancellationSignal(),
runnable -> handler.post(runnable),
authenticationCallback);
} else {
Log.d("TAG", "showLockScreen: no in scrue.... no password");
}
}
API 29运行效果:
如运行效果,
你可以设置Titile, subtitle,以及negative button的文本及其点击事件响应。
分别使用如下API:
setTitle()
setSubTitle()
setNegativeButton() , 此时只能setDeviceCredentialAllowed(false)或者不设。
注意:
setDeviceCredentialAllowed(true)和 setNegativeButton()不能同时使用,因为true表示使用系统默认设置的NegativeButton, 即Use PIN/ Use Pattern/ Use Password,且起点击事件监听也变成默认调转至Pattern/PIN/Password验证界面。
以上实现方便用户只需要通过生物识别验证,Negative灵活自己实现。
是不还有一个疑问,
有没有setPositiveButton()?
有,只不过只给平台应用内部使用,不开放给第三方普通app。
///Android/Sdk/sources/android-29/android/hardware/biometrics/BiometricPrompt.java
/**
* Optional: Set the text for the positive button. If not set, the positive button
* will not show.
* @param text
* @return
* @hide
*/
@NonNull public Builder setPositiveButton(@NonNull CharSequence text,
@NonNull @CallbackExecutor Executor executor,
@NonNull DialogInterface.OnClickListener listener) {
if (TextUtils.isEmpty(text)) {
throw new IllegalArgumentException("Text must be set and non-empty");
}
if (executor == null) {
throw new IllegalArgumentException("Executor must not be null");
}
if (listener == null) {
throw new IllegalArgumentException("Listener must not be null");
}
mBundle.putCharSequence(KEY_POSITIVE_TEXT, text);
mPositiveButtonInfo = new ButtonInfo(executor, listener);
return this;
}
注意以上一段代码,
我们使用了lambda表达式,biometricPrompt传递进去的参数是Excutor,它的原型是怎么样的呢?
首先是lambda表达方式:
// lambda
public void adc(){
final Handler handler = new Handler(Looper.getMainLooper());
Executor executor = runnable -> handler.post(runnable);
}
翻译成普通函数表达方式:
// non lambda
public void adc(){
final Handler handler = new Handler(Looper.getMainLooper());
Executor executor = new Executor() {
@Override
public void execute(Runnable runnable) {
handler.post(runnable);
}
};
}
再看一个更简单的匿名内部类的例子,
// non-lambda
public void abc(){
Runnable runnable = new Runnable() {
@Override
public void run() {
Log.d("TAG", "showLockScreen: xxx");
}
};
}
// lambda
public void abc(){
Runnable runnable = () -> Log.d("TAG", "showLockScreen: xxx");
}
当匿名内部类不带参时,直接一个空括号表示,
当内名内部累方法带参时,直接使用参数即可,省略了括号。