/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.biometrics; import android.app.PendingIntent; import android.content.Intent; import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import androidx.annotation.NonNull; import androidx.fragment.app.FragmentActivity; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.password.ChooseLockSettingsHelper; import java.util.function.Function; /** * Helper for {@link BiometricEnrollActivity} when multiple sensors exist on a device. */ public class MultiBiometricEnrollHelper { private static final String TAG = "MultiBiometricEnrollHelper"; private static final int REQUEST_FACE_ENROLL = 3000; private static final int REQUEST_FINGERPRINT_ENROLL = 3001; public static final String EXTRA_ENROLL_AFTER_FACE = "enroll_after_face"; public static final String EXTRA_ENROLL_AFTER_FINGERPRINT = "enroll_after_finger"; public static final String EXTRA_SKIP_PENDING_ENROLL = "skip_pending_enroll"; @NonNull private final FragmentActivity mActivity; private final long mGkPwHandle; private final int mUserId; private final boolean mRequestEnrollFace; private final boolean mRequestEnrollFingerprint; private final FingerprintManager mFingerprintManager; private final FaceManager mFaceManager; private final Intent mFingerprintEnrollIntroductionIntent; private final Intent mFaceEnrollIntroductionIntent; private Function mGatekeeperHatSupplier; @VisibleForTesting MultiBiometricEnrollHelper(@NonNull FragmentActivity activity, int userId, boolean enrollFace, boolean enrollFingerprint, long gkPwHandle, FingerprintManager fingerprintManager, FaceManager faceManager, Intent fingerprintEnrollIntroductionIntent, Intent faceEnrollIntroductionIntent, Function gatekeeperHatSupplier) { mActivity = activity; mUserId = userId; mGkPwHandle = gkPwHandle; mRequestEnrollFace = enrollFace; mRequestEnrollFingerprint = enrollFingerprint; mFingerprintManager = fingerprintManager; mFaceManager = faceManager; mFingerprintEnrollIntroductionIntent = fingerprintEnrollIntroductionIntent; mFaceEnrollIntroductionIntent = faceEnrollIntroductionIntent; mGatekeeperHatSupplier = gatekeeperHatSupplier; } MultiBiometricEnrollHelper(@NonNull FragmentActivity activity, int userId, boolean enrollFace, boolean enrollFingerprint, long gkPwHandle) { this(activity, userId, enrollFace, enrollFingerprint, gkPwHandle, activity.getSystemService(FingerprintManager.class), activity.getSystemService(FaceManager.class), BiometricUtils.getFingerprintIntroIntent(activity, activity.getIntent()), BiometricUtils.getFaceIntroIntent(activity, activity.getIntent()), (challenge) -> BiometricUtils.requestGatekeeperHat(activity, gkPwHandle, userId, challenge)); } void startNextStep() { if (mRequestEnrollFingerprint) { launchFingerprintEnroll(); } else if (mRequestEnrollFace) { launchFaceEnroll(); } else { mActivity.setResult(BiometricEnrollIntroduction.RESULT_SKIP); mActivity.finish(); } } private void launchFaceEnroll() { mFaceManager.generateChallenge(mUserId, (sensorId, userId, challenge) -> { final byte[] hardwareAuthToken = mGatekeeperHatSupplier.apply(challenge); mFaceEnrollIntroductionIntent.putExtra( BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId); mFaceEnrollIntroductionIntent.putExtra( BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge); BiometricUtils.launchEnrollForResult(mActivity, mFaceEnrollIntroductionIntent, REQUEST_FACE_ENROLL, hardwareAuthToken, mGkPwHandle, mUserId); }); } private void launchFingerprintEnroll() { mFingerprintManager.generateChallenge(mUserId, ((sensorId, userId, challenge) -> { final byte[] hardwareAuthToken = mGatekeeperHatSupplier.apply(challenge); mFingerprintEnrollIntroductionIntent.putExtra( BiometricEnrollBase.EXTRA_KEY_SENSOR_ID, sensorId); mFingerprintEnrollIntroductionIntent.putExtra( BiometricEnrollBase.EXTRA_KEY_CHALLENGE, challenge); if (mRequestEnrollFace) { // Give FingerprintEnroll a pendingIntent pointing to face enrollment, so that it // can be started when user skips or finishes fingerprint enrollment. // FLAG_UPDATE_CURRENT ensures it is launched with the most recent values. mFaceEnrollIntroductionIntent.putExtra(Intent.EXTRA_USER_ID, mUserId); mFaceEnrollIntroductionIntent.putExtra( ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle); final PendingIntent faceAfterFp = PendingIntent.getActivity(mActivity, 0 /* requestCode */, mFaceEnrollIntroductionIntent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); mFingerprintEnrollIntroductionIntent.putExtra(EXTRA_ENROLL_AFTER_FINGERPRINT, faceAfterFp); } BiometricUtils.launchEnrollForResult(mActivity, mFingerprintEnrollIntroductionIntent, REQUEST_FINGERPRINT_ENROLL, hardwareAuthToken, mGkPwHandle, mUserId); })); } }