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.policy;
18 
19 import static android.hardware.fingerprint.FingerprintStateListener.STATE_ENROLLING;
20 import static android.hardware.fingerprint.FingerprintStateListener.STATE_IDLE;
21 
22 import android.annotation.NonNull;
23 import android.app.AlertDialog;
24 import android.app.Dialog;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.content.pm.PackageManager;
28 import android.hardware.fingerprint.FingerprintManager;
29 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
30 import android.hardware.fingerprint.FingerprintStateListener;
31 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
32 import android.os.Handler;
33 import android.os.PowerManager;
34 import android.view.WindowManager;
35 
36 import com.android.internal.R;
37 
38 import java.util.List;
39 import java.util.concurrent.atomic.AtomicBoolean;
40 
41 /**
42  * Defines behavior for handling interactions between power button events and
43  * fingerprint-related operations, for devices where the fingerprint sensor (side fps)
44  * lives on the power button.
45  */
46 public class SideFpsEventHandler {
47     @NonNull private final Context mContext;
48     @NonNull private final Handler mHandler;
49     @NonNull private final PowerManager mPowerManager;
50     @NonNull private final AtomicBoolean mIsSideFps;
51     @NonNull private final AtomicBoolean mSideFpsEventHandlerReady;
52 
53     private @FingerprintStateListener.State int mFingerprintState;
54 
SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager)55     SideFpsEventHandler(Context context, Handler handler, PowerManager powerManager) {
56         mContext = context;
57         mHandler = handler;
58         mPowerManager = powerManager;
59         mFingerprintState = STATE_IDLE;
60         mIsSideFps = new AtomicBoolean(false);
61         mSideFpsEventHandlerReady = new AtomicBoolean(false);
62     }
63 
64     /**
65      * Called from {@link PhoneWindowManager} after power button is pressed. Checks fingerprint
66      * sensor state and if mFingerprintState = STATE_ENROLLING, displays a dialog confirming intent
67      * to turn screen off. If confirmed, the device goes to sleep, and if canceled, the dialog is
68      * dismissed.
69      * @param eventTime powerPress event time
70      * @return true if powerPress was consumed, false otherwise
71      */
onSinglePressDetected(long eventTime)72     public boolean onSinglePressDetected(long eventTime) {
73         if (!mSideFpsEventHandlerReady.get() || !mIsSideFps.get()
74                 || mFingerprintState != STATE_ENROLLING) {
75             return false;
76         }
77         mHandler.post(() -> {
78             Dialog confirmScreenOffDialog = new AlertDialog.Builder(mContext)
79                     .setTitle(R.string.fp_enrollment_powerbutton_intent_title)
80                     .setMessage(R.string.fp_enrollment_powerbutton_intent_message)
81                     .setPositiveButton(
82                             R.string.fp_enrollment_powerbutton_intent_positive_button,
83                             new DialogInterface.OnClickListener() {
84                                 @Override
85                                 public void onClick(DialogInterface dialog, int which) {
86                                     dialog.dismiss();
87                                     mPowerManager.goToSleep(
88                                             eventTime,
89                                             PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON,
90                                             0 /* flags */
91                                     );
92                                 }
93                             })
94                     .setNegativeButton(
95                             R.string.fp_enrollment_powerbutton_intent_negative_button,
96                             new DialogInterface.OnClickListener() {
97                                 @Override
98                                 public void onClick(DialogInterface dialog, int which) {
99                                     dialog.dismiss();
100                                 }
101                             })
102                     .setCancelable(false)
103                     .create();
104             confirmScreenOffDialog.getWindow().setType(
105                     WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL);
106             confirmScreenOffDialog.show();
107         });
108         return true;
109     }
110 
111     /**
112      * Awaits notification from PhoneWindowManager that fingerprint service is ready
113      * to send updates about power button fps sensor state. Then configures a
114      * FingerprintStateListener to receive and record updates to fps state, and
115      * registers the FingerprintStateListener in FingerprintManager.
116      */
onFingerprintSensorReady()117     public void onFingerprintSensorReady() {
118         final PackageManager pm = mContext.getPackageManager();
119         if (!pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) return;
120         FingerprintManager fingerprintManager =
121                 mContext.getSystemService(FingerprintManager.class);
122         fingerprintManager.addAuthenticatorsRegisteredCallback(
123                 new IFingerprintAuthenticatorsRegisteredCallback.Stub() {
124                     @Override
125                     public void onAllAuthenticatorsRegistered(
126                             List<FingerprintSensorPropertiesInternal> sensors) {
127                         mIsSideFps.set(fingerprintManager.isPowerbuttonFps());
128                         FingerprintStateListener fingerprintStateListener =
129                                 new FingerprintStateListener() {
130                             @Override
131                             public void onStateChanged(
132                                     @FingerprintStateListener.State int newState) {
133                                 mFingerprintState = newState;
134                             }
135                         };
136                         fingerprintManager.registerFingerprintStateListener(
137                                 fingerprintStateListener);
138                         mSideFpsEventHandlerReady.set(true);
139                     }
140                 });
141     }
142 }
143