• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.robolectric.shadows;
2 
3 import static android.Manifest.permission.USE_BIOMETRIC;
4 import static android.os.Build.VERSION_CODES.Q;
5 import static android.os.Build.VERSION_CODES.R;
6 import static org.robolectric.util.reflector.Reflector.reflector;
7 
8 import android.annotation.RequiresPermission;
9 import android.content.Context;
10 import android.hardware.biometrics.BiometricManager;
11 import org.robolectric.RuntimeEnvironment;
12 import org.robolectric.annotation.Implementation;
13 import org.robolectric.annotation.Implements;
14 import org.robolectric.annotation.RealObject;
15 import org.robolectric.annotation.Resetter;
16 import org.robolectric.util.ReflectionHelpers;
17 import org.robolectric.util.reflector.Direct;
18 import org.robolectric.util.reflector.ForType;
19 
20 /** Provides testing APIs for {@link BiometricManager} */
21 @Implements(
22     className = "android.hardware.biometrics.BiometricManager",
23     minSdk = Q,
24     isInAndroidSdk = false)
25 public class ShadowBiometricManager {
26 
27   protected static boolean biometricServiceConnected = true;
28   private static int authenticatorType = BiometricManager.Authenticators.EMPTY_SET;
29 
30   @RealObject private BiometricManager realBiometricManager;
31 
32   @Resetter
reset()33   public static void reset() {
34     biometricServiceConnected = true;
35     authenticatorType = BiometricManager.Authenticators.EMPTY_SET;
36   }
37 
38   @SuppressWarnings("deprecation")
39   @RequiresPermission(USE_BIOMETRIC)
40   @Implementation
canAuthenticate()41   protected int canAuthenticate() {
42     if (RuntimeEnvironment.getApiLevel() >= R) {
43       return reflector(BiometricManagerReflector.class, realBiometricManager).canAuthenticate();
44     } else {
45       int biometricResult =
46           canAuthenticateInternal(0, BiometricManager.Authenticators.BIOMETRIC_WEAK);
47       if (biometricServiceConnected) {
48         return BiometricManager.BIOMETRIC_SUCCESS;
49       } else if (biometricResult != BiometricManager.BIOMETRIC_SUCCESS) {
50         return biometricResult;
51       } else {
52         boolean hasBiometrics =
53             ReflectionHelpers.callStaticMethod(
54                 BiometricManager.class,
55                 "hasBiometrics",
56                 ReflectionHelpers.ClassParameter.from(
57                     Context.class, RuntimeEnvironment.getApplication().getApplicationContext()));
58         if (!hasBiometrics) {
59           return BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
60         } else {
61           return BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE;
62         }
63       }
64     }
65   }
66 
67   @RequiresPermission(USE_BIOMETRIC)
68   @Implementation(minSdk = R)
canAuthenticate(int authenticators)69   protected int canAuthenticate(int authenticators) {
70     return canAuthenticateInternal(0, authenticators);
71   }
72 
73   @RequiresPermission(USE_BIOMETRIC)
74   @Implementation(minSdk = R)
canAuthenticate(int userId, int authenticators)75   protected int canAuthenticate(int userId, int authenticators) {
76     return canAuthenticateInternal(userId, authenticators);
77   }
78 
canAuthenticateInternal(int userId, int authenticators)79   private int canAuthenticateInternal(int userId, int authenticators) {
80     if (authenticatorType == BiometricManager.Authenticators.BIOMETRIC_STRONG
81         && biometricServiceConnected) {
82       return BiometricManager.BIOMETRIC_SUCCESS;
83     }
84     if ((authenticatorType & BiometricManager.Authenticators.DEVICE_CREDENTIAL)
85         == BiometricManager.Authenticators.DEVICE_CREDENTIAL) {
86       return BiometricManager.BIOMETRIC_SUCCESS;
87     }
88     if (authenticatorType != BiometricManager.Authenticators.EMPTY_SET) {
89       return authenticatorType;
90     }
91     if (!biometricServiceConnected) {
92       return BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
93     } else {
94       return BiometricManager.BIOMETRIC_SUCCESS;
95     }
96   }
97 
98   /**
99    * Sets the value {@code true} to allow {@link #canAuthenticate()} return {@link
100    * BIOMETRIC_SUCCESS} If sets the value to {@code false}, result will depend on {@link
101    * BiometricManager#hasBiometrics(Context context)}
102    *
103    * @param flag to set can authenticate or not
104    */
setCanAuthenticate(boolean flag)105   public void setCanAuthenticate(boolean flag) {
106     biometricServiceConnected = flag;
107   }
108 
109   /**
110    * Allow different result {@link #canAuthenticate(int)}, result will depend on the combination as
111    * described <a
112    * href="https://developer.android.com/reference/android/hardware/biometrics/BiometricManager#canAuthenticate(int)">here</a>
113    * For example, you can set the value {@code BiometricManager.Authenticators.BIOMETRIC_STRONG} to
114    * allow {@link #canAuthenticate(int)} return {@link BiometricManager#BIOMETRIC_SUCCESS} when you
115    * passed {@code BiometricManager.Authenticators.BIOMETRIC_WEAK} as parameter in {@link
116    * #canAuthenticate(int)}
117    *
118    * @param type to set the authenticatorType
119    * @see <a
120    *     href="https://developer.android.com/reference/android/hardware/biometrics/BiometricManager#canAuthenticate(int)">BiometricManager#canAuthenticate(int)</a>
121    */
setAuthenticatorType(int type)122   public void setAuthenticatorType(int type) {
123     authenticatorType = type;
124   }
125 
126   @ForType(BiometricManager.class)
127   interface BiometricManagerReflector {
128 
129     @Direct
canAuthenticate()130     int canAuthenticate();
131   }
132 }
133