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.server.biometrics.sensors.fingerprint;
18 
19 import static android.hardware.fingerprint.FingerprintStateListener.STATE_AUTH_OTHER;
20 import static android.hardware.fingerprint.FingerprintStateListener.STATE_BP_AUTH;
21 import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING;
22 import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
23 import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH;
24 
25 import android.annotation.NonNull;
26 import android.hardware.fingerprint.FingerprintStateListener;
27 import android.hardware.fingerprint.IFingerprintStateListener;
28 import android.os.RemoteException;
29 import android.util.Slog;
30 
31 import com.android.server.biometrics.Utils;
32 import com.android.server.biometrics.sensors.AuthenticationClient;
33 import com.android.server.biometrics.sensors.BaseClientMonitor;
34 import com.android.server.biometrics.sensors.EnrollClient;
35 import com.android.server.biometrics.sensors.EnrollmentModifier;
36 
37 import java.util.concurrent.CopyOnWriteArrayList;
38 
39 /**
40  * A callback for receiving notifications about changes in fingerprint state.
41  */
42 public class FingerprintStateCallback implements BaseClientMonitor.Callback {
43 
44     @NonNull private final CopyOnWriteArrayList<IFingerprintStateListener>
45             mFingerprintStateListeners = new CopyOnWriteArrayList<>();
46 
47     private @FingerprintStateListener.State int mFingerprintState;
48 
FingerprintStateCallback()49     public FingerprintStateCallback() {
50         mFingerprintState = STATE_IDLE;
51     }
52 
getFingerprintState()53     public int getFingerprintState() {
54         return mFingerprintState;
55     }
56 
57     @Override
onClientStarted(@onNull BaseClientMonitor client)58     public void onClientStarted(@NonNull BaseClientMonitor client) {
59         final int previousFingerprintState = mFingerprintState;
60 
61         if (client instanceof AuthenticationClient) {
62             final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client;
63             if (authClient.isKeyguard()) {
64                 mFingerprintState = STATE_KEYGUARD_AUTH;
65             } else if (authClient.isBiometricPrompt()) {
66                 mFingerprintState = STATE_BP_AUTH;
67             } else {
68                 mFingerprintState = STATE_AUTH_OTHER;
69             }
70         } else if (client instanceof EnrollClient) {
71             mFingerprintState = STATE_ENROLLING;
72         } else {
73             Slog.w(FingerprintService.TAG,
74                     "Other authentication client: " + Utils.getClientName(client));
75             mFingerprintState = STATE_IDLE;
76         }
77 
78         Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState
79                 + " to " + mFingerprintState + ", client " + client);
80         notifyFingerprintStateListeners(mFingerprintState);
81     }
82 
83     @Override
onClientFinished(@onNull BaseClientMonitor client, boolean success)84     public void onClientFinished(@NonNull BaseClientMonitor client, boolean success) {
85         mFingerprintState = STATE_IDLE;
86         Slog.d(FingerprintService.TAG,
87                 "Client finished, fps state updated to " + mFingerprintState + ", client "
88                         + client);
89 
90         if (client instanceof EnrollmentModifier) {
91             EnrollmentModifier enrollmentModifier = (EnrollmentModifier) client;
92             final boolean enrollmentStateChanged = enrollmentModifier.hasEnrollmentStateChanged();
93             Slog.d(FingerprintService.TAG, "Enrollment state changed: " + enrollmentStateChanged);
94             if (enrollmentStateChanged) {
95                 notifyAllFingerprintEnrollmentStateChanged(client.getTargetUserId(),
96                         client.getSensorId(),
97                         enrollmentModifier.hasEnrollments());
98             }
99         }
100 
101         notifyFingerprintStateListeners(mFingerprintState);
102     }
103 
notifyFingerprintStateListeners(@ingerprintStateListener.State int newState)104     private void notifyFingerprintStateListeners(@FingerprintStateListener.State int newState) {
105         for (IFingerprintStateListener listener : mFingerprintStateListeners) {
106             try {
107                 listener.onStateChanged(newState);
108             } catch (RemoteException e) {
109                 Slog.e(FingerprintService.TAG, "Remote exception in fingerprint state change", e);
110             }
111         }
112     }
113 
114     /**
115      * This should be invoked when:
116      *  1) Enrolled --> None-enrolled
117      *  2) None-enrolled --> enrolled
118      *  3) HAL becomes ready
119      *  4) Listener is registered
120      */
notifyAllFingerprintEnrollmentStateChanged(int userId, int sensorId, boolean hasEnrollments)121     void notifyAllFingerprintEnrollmentStateChanged(int userId, int sensorId,
122             boolean hasEnrollments) {
123         for (IFingerprintStateListener listener : mFingerprintStateListeners) {
124             notifyFingerprintEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments);
125         }
126     }
127 
128     /**
129      * Notifies the listener of enrollment state changes.
130      */
notifyFingerprintEnrollmentStateChanged(@onNull IFingerprintStateListener listener, int userId, int sensorId, boolean hasEnrollments)131     void notifyFingerprintEnrollmentStateChanged(@NonNull IFingerprintStateListener listener,
132             int userId, int sensorId, boolean hasEnrollments) {
133         try {
134             listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments);
135         } catch (RemoteException e) {
136             Slog.e(FingerprintService.TAG, "Remote exception", e);
137         }
138     }
139 
140     /**
141      * Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward
142      * updates in fingerprint sensor state to the SideFpNsEventHandler
143      *
144      * @param listener
145      */
registerFingerprintStateListener(@onNull IFingerprintStateListener listener)146     public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
147         mFingerprintStateListeners.add(listener);
148     }
149 }
150