• 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.BiometricAuthenticator.TYPE_FACE;
20 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
21 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
22 
23 import static com.android.settings.biometrics.BiometricEnrollBase.EXTRA_KEY_MODALITY;
24 import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_DENIED;
25 import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_CONSENT_GRANTED;
26 
27 import android.app.Activity;
28 import android.content.Context;
29 import android.content.Intent;
30 import android.os.Bundle;
31 
32 import androidx.annotation.NonNull;
33 import androidx.annotation.Nullable;
34 
35 import com.android.settings.biometrics.face.FaceEnrollParentalConsent;
36 import com.android.settings.biometrics.fingerprint.FingerprintEnrollParentalConsent;
37 import com.android.settings.password.ChooseLockSettingsHelper;
38 
39 import com.google.android.setupcompat.util.WizardManagerHelper;
40 
41 /**
42  * Helper for {@link BiometricEnrollActivity} to ask for parental consent prior to actual user
43  * enrollment.
44  */
45 public class ParentalConsentHelper {
46 
47     private static final String KEY_FACE_CONSENT = "face";
48     private static final String KEY_FINGERPRINT_CONSENT = "fingerprint";
49     private static final String KEY_IRIS_CONSENT = "iris";
50 
51     private final boolean mRequireFace;
52     private final boolean mRequireFingerprint;
53 
54     private long mGkPwHandle;
55     @Nullable
56     private Boolean mConsentFace;
57     @Nullable
58     private Boolean mConsentFingerprint;
59 
60     /**
61      * Helper for aggregating user consent.
62      *
63      * @param requireFace if face consent should be shown
64      * @param requireFingerprint if fingerprint consent should be shown
65      * @param gkPwHandle for launched intents
66      */
ParentalConsentHelper(boolean requireFace, boolean requireFingerprint, @Nullable Long gkPwHandle)67     public ParentalConsentHelper(boolean requireFace, boolean requireFingerprint,
68             @Nullable Long gkPwHandle) {
69         mRequireFace = requireFace;
70         mRequireFingerprint = requireFingerprint;
71         mGkPwHandle = gkPwHandle != null ? gkPwHandle : 0L;
72     }
73 
74     /**
75      * Updated the handle used for launching activities
76      *
77      * @param data result intent for credential verification
78      */
updateGatekeeperHandle(Intent data)79     public void updateGatekeeperHandle(Intent data) {
80         mGkPwHandle = BiometricUtils.getGatekeeperPasswordHandle(data);
81     }
82 
83     /**
84      * Launch the next consent screen.
85      *
86      * @param activity root activity
87      * @param requestCode request code to launch new activity
88      * @param resultCode result code of the last consent launch
89      * @param data result data from the last consent launch
90      * @return true if a consent activity was launched or false when complete
91      */
launchNext(@onNull Activity activity, int requestCode, int resultCode, @Nullable Intent data)92     public boolean launchNext(@NonNull Activity activity, int requestCode, int resultCode,
93             @Nullable Intent data) {
94         if (data != null) {
95             switch (data.getIntExtra(EXTRA_KEY_MODALITY, TYPE_NONE)) {
96                 case TYPE_FACE:
97                     mConsentFace = isConsent(resultCode, mConsentFace);
98                     break;
99                 case TYPE_FINGERPRINT:
100                     mConsentFingerprint = isConsent(resultCode, mConsentFingerprint);
101                     break;
102             }
103         }
104         return launchNext(activity, requestCode);
105     }
106 
107     @Nullable
isConsent(int resultCode, @Nullable Boolean defaultValue)108     private static Boolean isConsent(int resultCode, @Nullable Boolean defaultValue) {
109         switch (resultCode) {
110             case RESULT_CONSENT_GRANTED:
111                 return true;
112             case RESULT_CONSENT_DENIED:
113                 return false;
114         }
115         return defaultValue;
116     }
117 
118     /** @see #launchNext(Activity, int, int, Intent)  */
launchNext(@onNull Activity activity, int requestCode)119     public boolean launchNext(@NonNull Activity activity, int requestCode) {
120         final Intent intent = getNextConsentIntent(activity);
121         if (intent != null) {
122             WizardManagerHelper.copyWizardManagerExtras(activity.getIntent(), intent);
123             if (mGkPwHandle != 0) {
124                 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, mGkPwHandle);
125             }
126             activity.startActivityForResult(intent, requestCode);
127             return true;
128         }
129         return false;
130     }
131 
132     @Nullable
getNextConsentIntent(@onNull Context context)133     private Intent getNextConsentIntent(@NonNull Context context) {
134         if (mRequireFace && mConsentFace == null) {
135             return new Intent(context, FaceEnrollParentalConsent.class);
136         }
137         if (mRequireFingerprint && mConsentFingerprint == null) {
138             return new Intent(context, FingerprintEnrollParentalConsent.class);
139         }
140         return null;
141     }
142 
143     /**
144      * Get the result of all consent requests.
145      *
146      * This should be called when {@link #launchNext(Activity, int, int, Intent)} returns false
147      * to indicate that all responses have been recorded.
148      *
149      * @return The aggregate consent status.
150      */
151     @NonNull
getConsentResult()152     public Bundle getConsentResult() {
153         final Bundle result = new Bundle();
154         result.putBoolean(KEY_FACE_CONSENT, mConsentFace != null ? mConsentFace : false);
155         result.putBoolean(KEY_FINGERPRINT_CONSENT,
156                 mConsentFingerprint != null ? mConsentFingerprint : false);
157         result.putBoolean(KEY_IRIS_CONSENT, false);
158         return result;
159     }
160 
161     /** @return If the result bundle contains consent for face authentication. */
hasFaceConsent(@onNull Bundle bundle)162     public static boolean hasFaceConsent(@NonNull Bundle bundle) {
163         return bundle.getBoolean(KEY_FACE_CONSENT, false);
164     }
165 
166     /** @return If the result bundle contains consent for fingerprint authentication. */
hasFingerprintConsent(@onNull Bundle bundle)167     public static boolean hasFingerprintConsent(@NonNull Bundle bundle) {
168         return bundle.getBoolean(KEY_FINGERPRINT_CONSENT, false);
169     }
170 }
171