• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.password;
18 
19 import android.app.settings.SettingsEnums;
20 import android.hardware.biometrics.BiometricPrompt;
21 import android.hardware.biometrics.BiometricPrompt.AuthenticationCallback;
22 import android.hardware.biometrics.BiometricPrompt.AuthenticationResult;
23 import android.hardware.biometrics.PromptInfo;
24 import android.os.Bundle;
25 import android.os.CancellationSignal;
26 
27 import androidx.annotation.NonNull;
28 
29 import com.android.settings.core.InstrumentedFragment;
30 
31 import java.util.concurrent.Executor;
32 
33 /**
34  * A fragment that wraps the BiometricPrompt and manages its lifecycle.
35  */
36 public class BiometricFragment extends InstrumentedFragment {
37 
38     private static final String TAG = "ConfirmDeviceCredential/BiometricFragment";
39 
40     private static final String KEY_PROMPT_INFO = "prompt_info";
41 
42     // Re-set by the application. Should be done upon orientation changes, etc
43     private Executor mClientExecutor;
44     private AuthenticationCallback mClientCallback;
45 
46     // Re-settable by the application.
47     private int mUserId;
48 
49     // Created/Initialized once and retained
50     private BiometricPrompt mBiometricPrompt;
51     private CancellationSignal mCancellationSignal;
52 
53     private AuthenticationCallback mAuthenticationCallback =
54             new AuthenticationCallback() {
55         @Override
56         public void onAuthenticationError(int error, @NonNull CharSequence message) {
57             mClientExecutor.execute(() -> {
58                 mClientCallback.onAuthenticationError(error, message);
59             });
60             cleanup();
61         }
62 
63         @Override
64         public void onAuthenticationSucceeded(AuthenticationResult result) {
65             mClientExecutor.execute(() -> {
66                 mClientCallback.onAuthenticationSucceeded(result);
67             });
68             cleanup();
69         }
70 
71         @Override
72         public void onAuthenticationFailed() {
73             mClientExecutor.execute(() -> {
74                 mClientCallback.onAuthenticationFailed();
75             });
76         }
77 
78         @Override
79         public void onSystemEvent(int event) {
80             mClientExecutor.execute(() -> {
81                 mClientCallback.onSystemEvent(event);
82             });
83         }
84     };
85 
86     /**
87      * @param promptInfo
88      * @return
89      */
newInstance(PromptInfo promptInfo)90     public static BiometricFragment newInstance(PromptInfo promptInfo) {
91         BiometricFragment biometricFragment = new BiometricFragment();
92         final Bundle bundle = new Bundle();
93         bundle.putParcelable(KEY_PROMPT_INFO, promptInfo);
94         biometricFragment.setArguments(bundle);
95         return biometricFragment;
96     }
97 
setCallbacks(Executor executor, AuthenticationCallback callback)98     public void setCallbacks(Executor executor, AuthenticationCallback callback) {
99         mClientExecutor = executor;
100         mClientCallback = callback;
101     }
102 
setUser(int userId)103     public void setUser(int userId) {
104         mUserId = userId;
105     }
106 
cancel()107     public void cancel() {
108         if (mCancellationSignal != null) {
109             mCancellationSignal.cancel();
110         }
111         cleanup();
112     }
113 
cleanup()114     private void cleanup() {
115         if (getActivity() != null) {
116             getActivity().getSupportFragmentManager().beginTransaction().remove(this)
117                     .commitAllowingStateLoss();
118         }
119     }
120 
121     @Override
onCreate(Bundle savedInstanceState)122     public void onCreate(Bundle savedInstanceState) {
123         super.onCreate(savedInstanceState);
124         setRetainInstance(true);
125 
126         final Bundle bundle = getArguments();
127         final PromptInfo promptInfo = bundle.getParcelable(KEY_PROMPT_INFO);
128 
129         mBiometricPrompt = new BiometricPrompt.Builder(getContext())
130                 .setTitle(promptInfo.getTitle())
131                 .setUseDefaultTitle() // use default title if title is null/empty
132                 .setDeviceCredentialAllowed(true)
133                 .setSubtitle(promptInfo.getSubtitle())
134                 .setDescription(promptInfo.getDescription())
135                 .setTextForDeviceCredential(
136                         promptInfo.getDeviceCredentialTitle(),
137                         promptInfo.getDeviceCredentialSubtitle(),
138                         promptInfo.getDeviceCredentialDescription())
139                 .setConfirmationRequired(promptInfo.isConfirmationRequested())
140                 .setDisallowBiometricsIfPolicyExists(
141                         promptInfo.isDisallowBiometricsIfPolicyExists())
142                 .setReceiveSystemEvents(true)
143                 .build();
144     }
145 
146     @Override
onResume()147     public void onResume() {
148         super.onResume();
149 
150         if (mCancellationSignal == null) {
151             mCancellationSignal = new CancellationSignal();
152             mBiometricPrompt.authenticateUser(mCancellationSignal, mClientExecutor,
153                     mAuthenticationCallback, mUserId);
154         }
155     }
156 
157     @Override
getMetricsCategory()158     public int getMetricsCategory() {
159         return SettingsEnums.BIOMETRIC_FRAGMENT;
160     }
161 }
162