日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BiometricPrompt之三 - Fingerprint, Iris, Face UI优先级

發布時間:2023/12/20 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BiometricPrompt之三 - Fingerprint, Iris, Face UI优先级 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android Q以來,一直在推廣建議鼓勵三方應用BiometricPrompt API。

其效果見:

?

其號稱BiometricService兼容了Fingerprint, Iris, Face這幾種識別方案。

有貼《BiometricPrompt之一 - 簡單用法》可以看出,BiometricPrompt并沒有提供API讓3rd-app來決策選擇哪種方式來驗證,例如:Fingerprint ? Face?

那么當三者均支持時,UI顯示規則是怎樣子的??

功能如何? 三者可同時使用嗎?

?

先上【結論】:

三者均支持時,應當是BiometricService查詢到第一個支持驗證三方應用的feature為 優先,且是獨占,具有排他性,并非像鎖屏上同時兼容三者。

以Android Q AOSP的代碼來看,第一優先是Fingerprint, 其次Iris, 最后Face。

Fingerprint -> Iris -> Face

?

關鍵代碼如下:

frameworks/base/services/core/java/com/android/server/biometrics/BiometricService.java

914 /** 915 * Checks if there are any available biometrics, and returns the modality. This method also 916 * returns errors through the callback (no biometric feature, hardware not detected, no 917 * templates enrolled, etc). This service must not start authentication if errors are sent. 918 * 919 * @Returns A pair [Modality, Error] with Modality being one of 920 * {@link BiometricAuthenticator#TYPE_NONE}, 921 * {@link BiometricAuthenticator#TYPE_FINGERPRINT}, 922 * {@link BiometricAuthenticator#TYPE_IRIS}, 923 * {@link BiometricAuthenticator#TYPE_FACE} 924 * and the error containing one of the {@link BiometricConstants} errors. 925 */ 926 private Pair<Integer, Integer> checkAndGetBiometricModality(int userId) { 927 int modality = TYPE_NONE; 928 929 // No biometric features, send error 930 if (mAuthenticators.isEmpty()) { 931 return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT); 932 } 933 934 // Assuming that authenticators are listed in priority-order, the rest of this function 935 // will go through and find the first authenticator that's available, enrolled, and enabled. 936 // The tricky part is returning the correct error. Error strings that are modality-specific 937 // should also respect the priority-order. 938 939 // Find first authenticator that's detected, enrolled, and enabled. 940 boolean isHardwareDetected = false; 941 boolean hasTemplatesEnrolled = false; 942 boolean enabledForApps = false; 943 944 int firstHwAvailable = TYPE_NONE; 945 for (int i = 0; i < mAuthenticators.size(); i++) { 946 modality = mAuthenticators.get(i).getType(); 947 BiometricAuthenticator authenticator = mAuthenticators.get(i).getAuthenticator(); 948 if (authenticator.isHardwareDetected()) { 949 isHardwareDetected = true; 950 if (firstHwAvailable == TYPE_NONE) { 951 // Store the first one since we want to return the error in correct priority 952 // order. 953 firstHwAvailable = modality; 954 } 955 if (authenticator.hasEnrolledTemplates(userId)) { 956 hasTemplatesEnrolled = true; 957 if (isEnabledForApp(modality, userId)) { 958 // TODO(b/110907543): When face settings (and other settings) have both a 959 // user toggle as well as a work profile settings page, this needs to be 960 // updated to reflect the correct setting. 961 enabledForApps = true; 962 break; // 找到第一個符合條件的biometric type即止 963 } 964 } 965 } 966 } 967 968 // Check error conditions 969 if (!isHardwareDetected) { 970 return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE); 971 } else if (!hasTemplatesEnrolled) { 972 // Return the modality here so the correct error string can be sent. This error is 973 // preferred over !enabledForApps 974 return new Pair<>(firstHwAvailable, BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS); 975 } else if (!enabledForApps) { 976 return new Pair<>(TYPE_NONE, BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE); 977 } 978 979 return new Pair<>(modality, BiometricConstants.BIOMETRIC_SUCCESS); 980 }

由上段代碼可知,從第0個元素開始查詢,關鍵在于mAuthenticators這個List里邊存儲的第0個對象是誰 以及順序?

266 // Get and cache the available authenticator (manager) classes. Used since aidl doesn't support 267 // polymorphism :/ 268 final ArrayList<Authenticator> mAuthenticators = new ArrayList<>();

這個要回溯到BiometricService服務啟動初始化時。

850 /** 851 * Initializes the system service. 852 * <p> 853 * Subclasses must define a single argument constructor that accepts the context 854 * and passes it to super. 855 * </p> 856 * 857 * @param context The system server context. 858 */ 859 public BiometricService(Context context) { 860 super(context); 861 862 mAppOps = context.getSystemService(AppOpsManager.class); 863 mEnabledOnKeyguardCallbacks = new ArrayList<>(); 864 mSettingObserver = new SettingObserver(mHandler); 865 866 final PackageManager pm = context.getPackageManager(); 867 mHasFeatureFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT); 868 mHasFeatureIris = pm.hasSystemFeature(PackageManager.FEATURE_IRIS); 869 mHasFeatureFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE); 870 871 try { 872 ActivityManager.getService().registerUserSwitchObserver( 873 new UserSwitchObserver() { 874 @Override 875 public void onUserSwitchComplete(int newUserId) { 876 mSettingObserver.updateContentObserver(); 877 mSettingObserver.notifyEnabledOnKeyguardCallbacks(newUserId); 878 } 879 }, BiometricService.class.getName() 880 ); 881 } catch (RemoteException e) { 882 Slog.e(TAG, "Failed to register user switch observer", e); 883 } 884 } 885 886 @Override 887 public void onStart() { 888 // TODO: maybe get these on-demand 889 if (mHasFeatureFingerprint) { 890 mFingerprintService = IFingerprintService.Stub.asInterface( 891 ServiceManager.getService(Context.FINGERPRINT_SERVICE)); 892 } 893 if (mHasFeatureFace) { 894 mFaceService = IFaceService.Stub.asInterface( 895 ServiceManager.getService(Context.FACE_SERVICE)); 896 } 897 898 mActivityTaskManager = ActivityTaskManager.getService(); 899 mStatusBarService = IStatusBarService.Stub.asInterface( 900 ServiceManager.getService(Context.STATUS_BAR_SERVICE)); 901 902 // Cache the authenticators 903 for (int i = 0; i < FEATURE_ID.length; i++) { 904 if (hasFeature(FEATURE_ID[i])) { 905 Authenticator authenticator = 906 new Authenticator(FEATURE_ID[i], getAuthenticator(FEATURE_ID[i])); 907 mAuthenticators.add(authenticator);// 添加支持feature manager, 例如:FingerprintManager, FaceManager 908 } 909 } 910 911 publishBinderService(Context.BIOMETRIC_SERVICE, new BiometricServiceWrapper()); 912 }

加入到mAuthenticators的順序是取決于FEATURE_ID這個數組,從第0個元素開始添加。

105 private static final int[] FEATURE_ID = { 106 TYPE_FINGERPRINT, 107 TYPE_IRIS, 108 TYPE_FACE 109 };

【結論】

有以上可知,三者同時支持的情況下,有且僅有Fingerprint功能是支持的,優先級最高。

?

?

最后來看下isEnabledForApp()這個函數。

981 982 private boolean isEnabledForApp(int modality, int userId) { 983 switch(modality) { 984 case TYPE_FINGERPRINT: 985 return true; 986 case TYPE_IRIS: 987 return true; 988 case TYPE_FACE: 989 return mSettingObserver.getFaceEnabledForApps(userId); 990 default: 991 Slog.w(TAG, "Unsupported modality: " + modality); 992 return false; 993 } 994 }

以及BiometricService調用決策方案checkandgetbiometricmodality()的地方:

1463 1464 private void handleAuthenticate(IBinder token, long sessionId, int userId, 1465 IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, 1466 int callingUid, int callingPid, int callingUserId, 1467 IBiometricConfirmDeviceCredentialCallback callback) { 1468 1469 mHandler.post(() -> { 1470 final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId); /// 決策來源 1471 final int modality = result.first; 1472 final int error = result.second; 1473 1474 // Check for errors, notify callback, and return 1475 if (error != BiometricConstants.BIOMETRIC_SUCCESS) { 1476 try { 1477 final String hardwareUnavailable = 1478 getContext().getString(R.string.biometric_error_hw_unavailable); 1479 switch (error) { 1480 case BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT: 1481 receiver.onError(error, hardwareUnavailable); 1482 break; 1483 case BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE: 1484 receiver.onError(error, hardwareUnavailable); 1485 break; 1486 case BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS: 1487 receiver.onError(error, 1488 getErrorString(modality, error, 0 /* vendorCode */)); 1489 break; 1490 default: 1491 Slog.e(TAG, "Unhandled error"); 1492 break; 1493 } 1494 } catch (RemoteException e) { 1495 Slog.e(TAG, "Unable to send error", e); 1496 } 1497 return; 1498 } 1499 1500 mCurrentModality = modality; // 得到的決策biometric type 1501 1502 // Start preparing for authentication. Authentication starts when 1503 // all modalities requested have invoked onReadyForAuthentication. 1504 authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle, 1505 callingUid, callingPid, callingUserId, modality, callback); 1506 }); 1507 } 1508 1509 /** 1510 * authenticate() (above) which is called from BiometricPrompt determines which 1511 * modality/modalities to start authenticating with. authenticateInternal() should only be 1512 * used for: 1513 * 1) Preparing <Biometric>Services for authentication when BiometricPrompt#authenticate is, 1514 * invoked, shortly after which BiometricPrompt is shown and authentication starts 1515 * 2) Preparing <Biometric>Services for authentication when BiometricPrompt is already shown 1516 * and the user has pressed "try again" 1517 */ 1518 private void authenticateInternal(IBinder token, long sessionId, int userId, 1519 IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle, 1520 int callingUid, int callingPid, int callingUserId, int modality, 1521 IBiometricConfirmDeviceCredentialCallback callback) { 1522 try { 1523 boolean requireConfirmation = bundle.getBoolean( 1524 BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */); 1525 if ((modality & TYPE_FACE) != 0) { 1526 // Check if the user has forced confirmation to be required in Settings. 1527 requireConfirmation = requireConfirmation 1528 || mSettingObserver.getFaceAlwaysRequireConfirmation(userId); 1529 } 1530 // Generate random cookies to pass to the services that should prepare to start 1531 // authenticating. Store the cookie here and wait for all services to "ack" 1532 // with the cookie. Once all cookies are received, we can show the prompt 1533 // and let the services start authenticating. The cookie should be non-zero. 1534 final int cookie = mRandom.nextInt(Integer.MAX_VALUE - 1) + 1; 1535 Slog.d(TAG, "Creating auth session. Modality: " + modality 1536 + ", cookie: " + cookie); 1537 final HashMap<Integer, Integer> authenticators = new HashMap<>(); 1538 authenticators.put(modality, cookie); 1539 mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId, 1540 receiver, opPackageName, bundle, callingUid, callingPid, callingUserId, 1541 modality, requireConfirmation, callback); 1542 mPendingAuthSession.mState = STATE_AUTH_CALLED; 1543 // No polymorphism :( 1544 if ((modality & TYPE_FINGERPRINT) != 0) { 1545 mFingerprintService.prepareForAuthentication(token, sessionId, userId, 1546 mInternalReceiver, opPackageName, cookie, 1547 callingUid, callingPid, callingUserId); 1548 } 1549 if ((modality & TYPE_IRIS) != 0) { 1550 Slog.w(TAG, "Iris unsupported"); // Android Q暫時不支持Iris 1551 } 1552 if ((modality & TYPE_FACE) != 0) { 1553 mFaceService.prepareForAuthentication(requireConfirmation, 1554 token, sessionId, userId, mInternalReceiver, opPackageName, 1555 cookie, callingUid, callingPid, callingUserId); 1556 } 1557 } catch (RemoteException e) { 1558 Slog.e(TAG, "Unable to start authentication", e); 1559 } 1560 }

上面看起來并沒有使用else if 結構,看起來像是可以二者同時兼容,但從決策方法來看,一次只能有一個,modality不可能同時支持。

總結

以上是生活随笔為你收集整理的BiometricPrompt之三 - Fingerprint, Iris, Face UI优先级的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。