1 /*
2  * Copyright (C) 2017 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.accessibilityservice;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.os.Handler;
22 import android.os.RemoteException;
23 import android.util.ArrayMap;
24 import android.util.Log;
25 import com.android.internal.annotations.VisibleForTesting;
26 
27 /**
28  * An {@link AccessibilityService} can capture gestures performed on a device's fingerprint
29  * sensor, as long as the device has a sensor capable of detecting gestures.
30  * <p>
31  * This capability must be declared by the service as
32  * {@link AccessibilityServiceInfo#CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES}. It also requires
33  * the permission {@link android.Manifest.permission#USE_FINGERPRINT}.
34  * <p>
35  * Because capturing fingerprint gestures may have side effects, services with the capability only
36  * capture gestures when {@link AccessibilityServiceInfo#FLAG_REQUEST_FINGERPRINT_GESTURES} is set.
37  * <p>
38  * <strong>Note: </strong>The fingerprint sensor is used for authentication in critical use cases,
39  * so services must carefully design their user's experience when performing gestures on the sensor.
40  * When the sensor is in use by an app, for example, when authenticating or enrolling a user,
41  * the sensor will not detect gestures. Services need to ensure that users understand when the
42  * sensor is in-use for authentication to prevent users from authenticating unintentionally when
43  * trying to interact with the service. They can use
44  * {@link FingerprintGestureCallback#onGestureDetectionAvailabilityChanged(boolean)} to learn when
45  * gesture detection becomes unavailable.
46  * <p>
47  * Multiple accessibility services may listen for fingerprint gestures simultaneously, so services
48  * should provide a way for the user to disable the use of this feature so multiple services don't
49  * conflict with each other.
50  * <p>
51  * {@see android.hardware.fingerprint.FingerprintManager#isHardwareDetected}
52  */
53 public final class FingerprintGestureController {
54     /** Identifier for a swipe right on the fingerprint sensor */
55     public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 0x00000001;
56 
57     /** Identifier for a swipe left on the fingerprint sensor */
58     public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 0x00000002;
59 
60     /** Identifier for a swipe up on the fingerprint sensor */
61     public static final int FINGERPRINT_GESTURE_SWIPE_UP = 0x00000004;
62 
63     /** Identifier for a swipe down on the fingerprint sensor */
64     public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 0x00000008;
65 
66     private static final String LOG_TAG = "FingerprintGestureController";
67     private final Object mLock = new Object();
68     private final IAccessibilityServiceConnection mAccessibilityServiceConnection;
69 
70     private final ArrayMap<FingerprintGestureCallback, Handler> mCallbackHandlerMap =
71             new ArrayMap<>(1);
72 
73     /**
74      * @param connection The connection to use for system interactions
75      * @hide
76      */
77     @VisibleForTesting
FingerprintGestureController(IAccessibilityServiceConnection connection)78     public FingerprintGestureController(IAccessibilityServiceConnection connection) {
79         mAccessibilityServiceConnection = connection;
80     }
81 
82     /**
83      * Gets if the fingerprint sensor's gesture detection is available.
84      *
85      * @return {@code true} if the sensor's gesture detection is available. {@code false} if it is
86      * not currently detecting gestures (for example, if it is enrolling a finger).
87      */
isGestureDetectionAvailable()88     public boolean isGestureDetectionAvailable() {
89         try {
90             return mAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable();
91         } catch (RemoteException re) {
92             Log.w(LOG_TAG, "Failed to check if fingerprint gestures are active", re);
93             re.rethrowFromSystemServer();
94             return false;
95         }
96     }
97 
98     /**
99      * Register a callback to be informed of fingerprint sensor gesture events.
100      *
101      * @param callback The listener to be added.
102      * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
103      * on the service's main thread.
104      */
registerFingerprintGestureCallback( @onNull FingerprintGestureCallback callback, @Nullable Handler handler)105     public void registerFingerprintGestureCallback(
106             @NonNull FingerprintGestureCallback callback, @Nullable Handler handler) {
107         synchronized (mLock) {
108             mCallbackHandlerMap.put(callback, handler);
109         }
110     }
111 
112     /**
113      * Unregister a listener added with {@link #registerFingerprintGestureCallback}.
114      *
115      * @param callback The callback to remove. Removing a callback that was never added has no
116      * effect.
117      */
unregisterFingerprintGestureCallback(FingerprintGestureCallback callback)118     public void unregisterFingerprintGestureCallback(FingerprintGestureCallback callback) {
119         synchronized (mLock) {
120             mCallbackHandlerMap.remove(callback);
121         }
122     }
123 
124     /**
125      * Called when gesture detection becomes active or inactive
126      * @hide
127      */
onGestureDetectionActiveChanged(boolean active)128     public void onGestureDetectionActiveChanged(boolean active) {
129         final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
130         synchronized (mLock) {
131             handlerMap = new ArrayMap<>(mCallbackHandlerMap);
132         }
133         int numListeners = handlerMap.size();
134         for (int i = 0; i < numListeners; i++) {
135             FingerprintGestureCallback callback = handlerMap.keyAt(i);
136             Handler handler = handlerMap.valueAt(i);
137             if (handler != null) {
138                 handler.post(() -> callback.onGestureDetectionAvailabilityChanged(active));
139             } else {
140                 callback.onGestureDetectionAvailabilityChanged(active);
141             }
142         }
143     }
144 
145     /**
146      * Called when gesture is detected.
147      * @hide
148      */
onGesture(int gesture)149     public void onGesture(int gesture) {
150         final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
151         synchronized (mLock) {
152             handlerMap = new ArrayMap<>(mCallbackHandlerMap);
153         }
154         int numListeners = handlerMap.size();
155         for (int i = 0; i < numListeners; i++) {
156             FingerprintGestureCallback callback = handlerMap.keyAt(i);
157             Handler handler = handlerMap.valueAt(i);
158             if (handler != null) {
159                 handler.post(() -> callback.onGestureDetected(gesture));
160             } else {
161                 callback.onGestureDetected(gesture);
162             }
163         }
164     }
165 
166     /**
167      * Class that is called back when fingerprint gestures are being used for accessibility.
168      */
169     public abstract static class FingerprintGestureCallback {
170         /**
171          * Called when the fingerprint sensor's gesture detection becomes available or unavailable.
172          *
173          * @param available Whether or not the sensor's gesture detection is now available.
174          */
onGestureDetectionAvailabilityChanged(boolean available)175         public void onGestureDetectionAvailabilityChanged(boolean available) {}
176 
177         /**
178          * Called when the fingerprint sensor detects gestures.
179          *
180          * @param gesture The id of the gesture that was detected. For example,
181          * {@link #FINGERPRINT_GESTURE_SWIPE_RIGHT}.
182          */
onGestureDetected(int gesture)183         public void onGestureDetected(int gesture) {}
184     }
185 }
186