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