1 /* 2 * Copyright (C) 2020 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.cts.verifier.biometrics; 18 19 import android.content.Intent; 20 import android.hardware.biometrics.BiometricManager; 21 import android.hardware.biometrics.BiometricManager.Authenticators; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.os.Looper; 25 import android.provider.Settings; 26 import android.util.Log; 27 import android.widget.Button; 28 import android.widget.Toast; 29 30 import com.android.cts.verifier.PassFailButtons; 31 32 import java.util.concurrent.Executor; 33 34 /** 35 * Abstract base class for tests in this directory. 36 */ 37 public abstract class AbstractBaseTest extends PassFailButtons.Activity { 38 39 private static final int REQUEST_ENROLL_WHEN_NONE_ENROLLED = 1; 40 getTag()41 abstract protected String getTag(); isOnPauseAllowed()42 abstract protected boolean isOnPauseAllowed(); 43 44 protected final Handler mHandler = new Handler(Looper.getMainLooper()); 45 protected final Executor mExecutor = mHandler::post; 46 47 protected boolean mCurrentlyEnrolling; 48 49 BiometricManager mBiometricManager; 50 51 @Override onCreate(Bundle savedInstanceState)52 protected void onCreate(Bundle savedInstanceState) { 53 super.onCreate(savedInstanceState); 54 mBiometricManager = getSystemService(BiometricManager.class); 55 } 56 57 @Override onPause()58 protected void onPause() { 59 super.onPause(); 60 61 // Assume we only enable the pass button when all tests pass. There actually isn't a way 62 // to easily do something like `this.isTestPassed()` 63 if (!getPassButton().isEnabled() && !isOnPauseAllowed()) { 64 showToastAndLog("This test must be completed without pausing the app"); 65 // Do not allow the test to continue if it loses foreground. Testers must start over. 66 // 1) This is to avoid any potential change to the current enrollment / biometric state. 67 // 2) The authentication UI must not affect the caller's activity lifecycle. 68 finish(); 69 } 70 } 71 72 @Override onActivityResult(int requestCode, int resultCode, Intent data)73 public void onActivityResult(int requestCode, int resultCode, Intent data) { 74 mCurrentlyEnrolling = false; 75 76 if (requestCode == REQUEST_ENROLL_WHEN_NONE_ENROLLED) { 77 onBiometricEnrollFinished(); 78 } 79 } 80 showToastAndLog(String s)81 void showToastAndLog(String s) { 82 Log.d(getTag(), s); 83 Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); 84 } 85 showToastAndLog(String s, Exception e)86 void showToastAndLog(String s, Exception e) { 87 Log.d(getTag(), s, e); 88 Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); 89 } 90 onBiometricEnrollFinished()91 protected void onBiometricEnrollFinished() { 92 } 93 checkAndEnroll(Button enrollButton, int requestedStrength)94 void checkAndEnroll(Button enrollButton, int requestedStrength) { 95 // Check that no biometrics (of any strength) are enrolled 96 int result = mBiometricManager.canAuthenticate(Authenticators.BIOMETRIC_WEAK); 97 if (result == BiometricManager.BIOMETRIC_SUCCESS) { 98 showToastAndLog("Please ensure that all biometrics are removed before starting" 99 + " this test"); 100 return; 101 } 102 103 result = mBiometricManager.canAuthenticate(requestedStrength); 104 if (result == BiometricManager.BIOMETRIC_SUCCESS) { 105 showToastAndLog("Please ensure that all biometrics are removed before starting" 106 + " this test"); 107 } else if (result == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE) { 108 // Multi-sensor cases are more thoroughly tested in regular CTS (not CTS-V), this 109 // should be fine for the purposes of CTS-V. 110 showToastAndLog("This device does not have a sensor meeting the requested strength," 111 + " you may pass this test"); 112 enrollButton.setEnabled(false); 113 getPassButton().setEnabled(true); 114 } else if (result == BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED) { 115 startBiometricEnroll(REQUEST_ENROLL_WHEN_NONE_ENROLLED, requestedStrength); 116 } else { 117 showToastAndLog("Unexpected result: " + result + ". Please ensure you have removed" 118 + "all biometric enrollments."); 119 } 120 } 121 startBiometricEnroll(int requestCode, int requestedStrength)122 private void startBiometricEnroll(int requestCode, int requestedStrength) { 123 mCurrentlyEnrolling = true; 124 final Intent enrollIntent = new Intent(Settings.ACTION_BIOMETRIC_ENROLL); 125 enrollIntent.putExtra(Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, 126 requestedStrength); 127 128 startActivityForResult(enrollIntent, requestCode); 129 } 130 } 131