• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.biometrics;
18 
19 import static android.hardware.biometrics.BiometricManager.Authenticators.BIOMETRIC_STRONG;
20 import static android.provider.Settings.ACTION_BIOMETRIC_ENROLL;
21 
22 import static androidx.test.espresso.intent.Intents.intended;
23 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent;
24 import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra;
25 
26 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
27 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
28 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
29 
30 import static com.google.common.truth.Truth.assertThat;
31 
32 import static org.junit.Assume.assumeTrue;
33 
34 import android.content.Context;
35 import android.content.Intent;
36 import android.content.pm.PackageManager;
37 import android.hardware.biometrics.SensorProperties;
38 import android.hardware.face.FaceManager;
39 import android.hardware.face.FaceSensorPropertiesInternal;
40 import android.hardware.fingerprint.FingerprintManager;
41 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
42 import android.os.UserHandle;
43 import android.provider.Settings;
44 
45 import androidx.test.core.app.ActivityScenario;
46 import androidx.test.core.app.ApplicationProvider;
47 import androidx.test.espresso.intent.Intents;
48 import androidx.test.ext.junit.runners.AndroidJUnit4;
49 import androidx.test.filters.MediumTest;
50 
51 import com.android.internal.widget.LockPatternChecker;
52 import com.android.internal.widget.LockPatternUtils;
53 import com.android.internal.widget.LockscreenCredential;
54 import com.android.settings.biometrics.face.FaceEnrollIntroduction;
55 import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
56 import com.android.settings.password.ChooseLockGeneric;
57 import com.android.settings.password.ChooseLockSettingsHelper;
58 import com.android.settings.password.ConfirmLockPassword;
59 import com.android.settings.testutils.AdbUtils;
60 
61 import org.junit.After;
62 import org.junit.Before;
63 import org.junit.Test;
64 import org.junit.runner.RunWith;
65 
66 import java.util.List;
67 
68 @RunWith(AndroidJUnit4.class)
69 @MediumTest
70 public class BiometricEnrollActivityTest {
71 
72     private static final String TAG = "BiometricEnrollActivityTest";
73     private static final int ADB_TIMEOUT_MS = 5000;
74     private static final String TEST_PIN = "1234";
75 
76     private final Context  mContext = ApplicationProvider.getApplicationContext();
77     private boolean mHasFace;
78     private boolean mHasFingerprint;
79     private boolean mIsFaceStrong;
80     private boolean mIsFingerprintStrong;
81 
82     @Before
setup()83     public void setup() {
84         Intents.init();
85         final PackageManager pm = mContext.getPackageManager();
86         mHasFingerprint = pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT);
87         mHasFace = pm.hasSystemFeature(PackageManager.FEATURE_FACE);
88 
89         if (mHasFace) {
90             final FaceManager faceManager = mContext.getSystemService(FaceManager.class);
91             final List<FaceSensorPropertiesInternal> faceProperties =
92                     faceManager.getSensorPropertiesInternal();
93             if (!faceProperties.isEmpty()) {
94                 final FaceSensorPropertiesInternal faceProp = faceProperties.get(0);
95                 mIsFaceStrong = faceProp.sensorStrength == SensorProperties.STRENGTH_STRONG;
96             }
97         }
98 
99         if (mHasFingerprint) {
100             final FingerprintManager fingerprintManager = mContext.getSystemService(
101                     FingerprintManager.class);
102             final List<FingerprintSensorPropertiesInternal> fingerProperties =
103                     fingerprintManager.getSensorPropertiesInternal();
104             if (!fingerProperties.isEmpty()) {
105                 final FingerprintSensorPropertiesInternal fingerProp = fingerProperties.get(0);
106                 mIsFingerprintStrong =
107                         fingerProp.sensorStrength == SensorProperties.STRENGTH_STRONG;
108             }
109         }
110     }
111 
112     @After
teardown()113     public void teardown() throws Exception {
114         Intents.release();
115         AdbUtils.checkStringInAdbCommandOutput(TAG, "locksettings clear --old " + TEST_PIN,
116                 "", "", ADB_TIMEOUT_MS);
117     }
118 
119     @Test
launchWithoutPin_setsPin()120     public void launchWithoutPin_setsPin() {
121         try (ActivityScenario<BiometricEnrollActivity> scenario =
122                      ActivityScenario.launch(getIntent())) {
123             intended(hasComponent(ChooseLockGeneric.class.getName()));
124             if (mHasFace && mHasFingerprint) {
125                 intended(hasExtra(EXTRA_KEY_FOR_BIOMETRICS, true));
126             } else if (mHasFace) {
127                 intended(hasExtra(EXTRA_KEY_FOR_FACE, true));
128             } else if (mHasFingerprint) {
129                 intended(hasExtra(EXTRA_KEY_FOR_FINGERPRINT, true));
130             }
131         }
132     }
133 
134     @Test
launchWithPin_confirmsPin()135     public void launchWithPin_confirmsPin() throws Exception  {
136         setPin();
137         try (ActivityScenario<BiometricEnrollActivity> scenario =
138                      ActivityScenario.launch(getIntent())) {
139             intended(hasComponent(ConfirmLockPassword.InternalActivity.class.getName()));
140         }
141     }
142 
143     @Test
launchWithPinAndPwHandle_confirmsPin()144     public void launchWithPinAndPwHandle_confirmsPin() throws Exception {
145         assumeTrue(mHasFace || mHasFingerprint);
146 
147         setPin();
148         final Intent intent = getIntent(true /* useInternal */);
149         LockPatternChecker.verifyCredential(new LockPatternUtils(mContext),
150                 LockscreenCredential.createPin(TEST_PIN), UserHandle.myUserId(),
151                 LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE, (response, timeoutMs) -> {
152                     assertThat(response.containsGatekeeperPasswordHandle()).isTrue();
153                     intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
154                             response.getGatekeeperPasswordHandle());
155                 }).get();
156 
157         try (ActivityScenario<BiometricEnrollActivity> scenario =
158                      ActivityScenario.launch(intent)) {
159             intended(hasComponent(mHasFace && !mHasFingerprint
160                     ? FaceEnrollIntroduction.class.getName()
161                     : FingerprintEnrollIntroduction.class.getName()));
162         }
163     }
164 
165     @Test
launchWithStrongBiometricAllowed_doNotEnrollWeak()166     public void launchWithStrongBiometricAllowed_doNotEnrollWeak() throws Exception {
167         assumeTrue(mHasFace || mHasFingerprint);
168 
169         // Allow only strong biometrics
170         Intent intent = getIntent();
171         intent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, BIOMETRIC_STRONG);
172 
173         try (ActivityScenario<BiometricEnrollActivity> scenario =
174                      ActivityScenario.launch(intent)) {
175             intended(hasComponent(ChooseLockGeneric.class.getName()));
176             if (mIsFaceStrong && mIsFingerprintStrong) {
177                 intended(hasExtra(EXTRA_KEY_FOR_BIOMETRICS, true));
178             } else if (mIsFaceStrong) {
179                 intended(hasExtra(EXTRA_KEY_FOR_FACE, true));
180             } else if (mIsFingerprintStrong) {
181                 intended(hasExtra(EXTRA_KEY_FOR_FINGERPRINT, true));
182             }
183         }
184     }
185 
getIntent()186     private Intent getIntent() {
187         return getIntent(false /* useInternal */);
188     }
189 
getIntent(boolean useInternal)190     private Intent getIntent(boolean useInternal) {
191         final Intent intent = new Intent(mContext, useInternal
192                 ? BiometricEnrollActivity.InternalActivity.class : BiometricEnrollActivity.class);
193         intent.setAction(ACTION_BIOMETRIC_ENROLL);
194         return intent;
195     }
196 
setPin()197     private static void setPin() throws Exception  {
198         assertThat(AdbUtils.checkStringInAdbCommandOutput(TAG, "locksettings set-pin " + TEST_PIN,
199                 "Pin set to ", "'" + TEST_PIN + "'", ADB_TIMEOUT_MS)).isTrue();
200     }
201 }
202