1 /*
2  * Copyright (C) 2018 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 android.app.admin.DevicePolicyManager;
20 import android.app.settings.SettingsEnums;
21 import android.content.Intent;
22 import android.content.pm.PackageManager;
23 import android.hardware.biometrics.BiometricManager;
24 import android.hardware.biometrics.BiometricManager.Authenticators;
25 import android.os.Bundle;
26 import android.os.UserHandle;
27 import android.provider.Settings;
28 import android.util.Log;
29 
30 import com.android.settings.SetupWizardUtils;
31 import com.android.settings.biometrics.face.FaceEnrollIntroduction;
32 import com.android.settings.biometrics.fingerprint.FingerprintEnrollFindSensor;
33 import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
34 import com.android.settings.biometrics.fingerprint.SetupFingerprintEnrollIntroduction;
35 import com.android.settings.core.InstrumentedActivity;
36 import com.android.settings.password.ChooseLockGeneric;
37 import com.android.settings.password.ChooseLockSettingsHelper;
38 
39 import com.google.android.setupcompat.util.WizardManagerHelper;
40 
41 /**
42  * Trampoline activity launched by the {@code android.settings.BIOMETRIC_ENROLL} action which
43  * shows the user an appropriate enrollment flow depending on the device's biometric hardware.
44  * This activity must only allow enrollment of biometrics that can be used by
45  * {@link android.hardware.biometrics.BiometricPrompt}.
46  */
47 public class BiometricEnrollActivity extends InstrumentedActivity {
48 
49     private static final String TAG = "BiometricEnrollActivity";
50 
51     public static final String EXTRA_SKIP_INTRO = "skip_intro";
52 
53     public static final class InternalActivity extends BiometricEnrollActivity {}
54 
55     @Override
onCreate(Bundle savedInstanceState)56     public void onCreate(Bundle savedInstanceState) {
57         super.onCreate(savedInstanceState);
58 
59         // Default behavior is to enroll BIOMETRIC_WEAK or above. See ACTION_BIOMETRIC_ENROLL.
60         final int authenticators = getIntent().getIntExtra(
61                 Settings.EXTRA_BIOMETRIC_AUTHENTICATORS_ALLOWED, Authenticators.BIOMETRIC_WEAK);
62 
63         Log.d(TAG, "Authenticators: " + authenticators);
64 
65         final BiometricManager bm = getSystemService(BiometricManager.class);
66         final PackageManager pm = getApplicationContext().getPackageManager();
67         Intent intent = null;
68 
69         final int result = bm.canAuthenticate(authenticators);
70 
71         if (!WizardManagerHelper.isAnySetupWizard(getIntent())) {
72             if (result == BiometricManager.BIOMETRIC_SUCCESS
73                     || result == BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE) {
74                 Log.e(TAG, "Unexpected result: " + result);
75                 finish();
76                 return;
77             }
78         }
79 
80         if (authenticators == BiometricManager.Authenticators.DEVICE_CREDENTIAL) {
81             // If only device credential was specified, ask the user to only set that up.
82             intent = new Intent(this, ChooseLockGeneric.class);
83             intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
84                     DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
85         } else if (pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
86             // This logic may have to be modified on devices with multiple biometrics.
87             // ChooseLockGeneric can request to start fingerprint enroll bypassing the intro screen.
88             if (getIntent().getBooleanExtra(EXTRA_SKIP_INTRO, false)
89                     && this instanceof InternalActivity) {
90                 intent = getFingerprintFindSensorIntent();
91             } else {
92                 intent = getFingerprintIntroIntent();
93             }
94         } else if (pm.hasSystemFeature(PackageManager.FEATURE_FACE)) {
95             intent = getFaceIntroIntent();
96         }
97 
98         if (intent != null) {
99             intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
100 
101             if (this instanceof InternalActivity) {
102                 // Propagate challenge and user Id from ChooseLockGeneric.
103                 final byte[] token = getIntent()
104                         .getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
105                 final int userId = getIntent()
106                         .getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
107 
108                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
109                 intent.putExtra(Intent.EXTRA_USER_ID, userId);
110             }
111 
112             startActivity(intent);
113             finish();
114         } else {
115             Log.e(TAG, "Intent was null, finishing");
116             finish();
117         }
118     }
119 
getFingerprintFindSensorIntent()120     private Intent getFingerprintFindSensorIntent() {
121         Intent intent = new Intent(this, FingerprintEnrollFindSensor.class);
122         SetupWizardUtils.copySetupExtras(getIntent(), intent);
123         return intent;
124     }
125 
getFingerprintIntroIntent()126     private Intent getFingerprintIntroIntent() {
127         if (WizardManagerHelper.isAnySetupWizard(getIntent())) {
128             Intent intent = new Intent(this, SetupFingerprintEnrollIntroduction.class);
129             WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
130             return intent;
131         } else {
132             return new Intent(this, FingerprintEnrollIntroduction.class);
133         }
134     }
135 
getFaceIntroIntent()136     private Intent getFaceIntroIntent() {
137         Intent intent = new Intent(this, FaceEnrollIntroduction.class);
138         WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent);
139         return intent;
140     }
141 
142     @Override
getMetricsCategory()143     public int getMetricsCategory() {
144         return SettingsEnums.BIOMETRIC_ENROLL_ACTIVITY;
145     }
146 }
147