• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.server.biometrics;
18 
19 import android.app.Activity;
20 import android.hardware.biometrics.BiometricPrompt;
21 import android.os.Bundle;
22 import android.server.wm.TestJournalProvider;
23 import android.util.Log;
24 
25 import androidx.annotation.NonNull;
26 
27 import java.util.ArrayList;
28 
29 public class BiometricCallbackHelper extends BiometricPrompt.AuthenticationCallback {
30 
31     private static final String TAG = "BiometricCallbackHelper";
32     public static final String KEY = "key_auth_callback";
33 
34     public static class State {
35         private static final String KEY_ERRORS_RECEIVED = "key_errors_received";
36         private static final String KEY_ACQUIRED_RECEIVED = "key_acquired_received";
37         private static final String KEY_NUM_ACCEPTED = "key_num_accepted";
38         private static final String KEY_NUM_REJECTED = "key_num_rejected";
39         private static final String KEY_NEGATIVE_BUTTON_PRESSED = "key_negative_button_pressed";
40 
41         public final ArrayList<Integer> mErrorsReceived;
42         public final ArrayList<Integer> mAcquiredReceived;
43         public int mNumAuthAccepted;
44         public int mNumAuthRejected;
45         public boolean mNegativeButtonPressed;
46 
State()47         public State() {
48             mErrorsReceived = new ArrayList<>();
49             mAcquiredReceived = new ArrayList<>();
50         }
51 
toBundle()52         public Bundle toBundle() {
53             final Bundle bundle = new Bundle();
54             bundle.putIntegerArrayList(KEY_ERRORS_RECEIVED, mErrorsReceived);
55             bundle.putIntegerArrayList(KEY_ACQUIRED_RECEIVED, mAcquiredReceived);
56             bundle.putInt(KEY_NUM_ACCEPTED, mNumAuthAccepted);
57             bundle.putInt(KEY_NUM_REJECTED, mNumAuthRejected);
58             bundle.putBoolean(KEY_NEGATIVE_BUTTON_PRESSED, mNegativeButtonPressed);
59             return bundle;
60         }
61 
State(ArrayList<Integer> errorsReceived, ArrayList<Integer> acquiredReceived, int numAuthAccepted, int numAuthRejected, boolean negativeButtonPressed)62         private State(ArrayList<Integer> errorsReceived, ArrayList<Integer> acquiredReceived,
63                 int numAuthAccepted, int numAuthRejected, boolean negativeButtonPressed) {
64             mErrorsReceived = errorsReceived;
65             mAcquiredReceived = acquiredReceived;
66             mNumAuthAccepted = numAuthAccepted;
67             mNumAuthRejected = numAuthRejected;
68             mNegativeButtonPressed = negativeButtonPressed;
69         }
70 
fromBundle(@onNull Bundle bundle)71         public static BiometricCallbackHelper.State fromBundle(@NonNull Bundle bundle) {
72             return new BiometricCallbackHelper.State(
73                     bundle.getIntegerArrayList(KEY_ERRORS_RECEIVED),
74                     bundle.getIntegerArrayList(KEY_ACQUIRED_RECEIVED),
75                     bundle.getInt(KEY_NUM_ACCEPTED),
76                     bundle.getInt(KEY_NUM_REJECTED),
77                     bundle.getBoolean(KEY_NEGATIVE_BUTTON_PRESSED));
78         }
79 
80         @Override
toString()81         public String toString() {
82             final StringBuilder sb = new StringBuilder();
83             sb.append("Accept: ").append(mNumAuthAccepted)
84                     .append(", Reject: ").append(mNumAuthRejected)
85                     .append(", Acquired Count: " ).append(mAcquiredReceived.size())
86                     .append(", Errors Count: ").append(mErrorsReceived.size())
87                     .append(", Negative pressed: ").append(mNegativeButtonPressed);
88             return sb.toString();
89         }
90     }
91 
92     private final Activity mActivity;
93     private final State mState;
94 
95     @Override
onAuthenticationError(int errorCode, CharSequence errString)96     public void onAuthenticationError(int errorCode, CharSequence errString) {
97         Log.d(TAG, "onAuthenticationError: " + errorCode + ", " + errString);
98         mState.mErrorsReceived.add(errorCode);
99         updateJournal();
100     }
101 
102     @Override
onAuthenticationHelp(int helpCode, CharSequence helpString)103     public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
104         Log.d(TAG, "onAuthenticationHelp: " + helpCode + ", " + helpString);
105         mState.mAcquiredReceived.add(helpCode);
106         updateJournal();
107     }
108 
109     @Override
onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result)110     public void onAuthenticationSucceeded(BiometricPrompt.AuthenticationResult result) {
111         Log.d(TAG, "onAuthenticationSucceeded");
112         mState.mNumAuthAccepted++;
113         updateJournal();
114     }
115 
116     @Override
onAuthenticationFailed()117     public void onAuthenticationFailed() {
118         Log.d(TAG, "onAuthenticationFailed");
119         mState.mNumAuthRejected++;
120         updateJournal();
121     }
122 
onNegativeButtonPressed()123     void onNegativeButtonPressed() {
124         Log.d(TAG, "onNegativeButtonPressed");
125         mState.mNegativeButtonPressed = true;
126         updateJournal();
127     }
128 
BiometricCallbackHelper(@onNull Activity activity)129     public BiometricCallbackHelper(@NonNull Activity activity) {
130         mActivity = activity;
131         mState = new BiometricCallbackHelper.State();
132 
133         // Update with empty state. It's faster than waiting/retrying for null on CTS-side.
134         updateJournal();
135     }
136 
updateJournal()137     private void updateJournal() {
138         TestJournalProvider.putExtras(mActivity,
139                 bundle -> bundle.putBundle(KEY, mState.toBundle()));
140     }
141 }
142