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