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 com.android.server.accessibility; 18 19 import android.accessibilityservice.FingerprintGestureController; 20 import android.content.res.Resources; 21 import android.hardware.fingerprint.IFingerprintClientActiveCallback; 22 import android.hardware.fingerprint.IFingerprintService; 23 import android.os.Binder; 24 import android.os.Handler; 25 import android.os.Message; 26 import android.os.RemoteException; 27 import android.util.Slog; 28 import android.view.KeyEvent; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 33 /** 34 * Encapsulate fingerprint gesture logic 35 */ 36 @SuppressWarnings("MissingPermissionAnnotation") 37 public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallback.Stub 38 implements Handler.Callback{ 39 private static final int MSG_REGISTER = 1; 40 private static final int MSG_UNREGISTER = 2; 41 private static final String LOG_TAG = "FingerprintGestureDispatcher"; 42 43 private final List<FingerprintGestureClient> mCapturingClients = new ArrayList<>(0); 44 private final Object mLock; 45 private final IFingerprintService mFingerprintService; 46 private final Handler mHandler; 47 private final boolean mHardwareSupportsGestures; 48 49 // This field is ground truth for whether or not we are registered. Only write to it in handler. 50 private boolean mRegisteredReadOnlyExceptInHandler; 51 52 /** 53 * @param fingerprintService The system's fingerprint service 54 * @param lock A lock to use when managing internal state 55 */ FingerprintGestureDispatcher(IFingerprintService fingerprintService, Resources resources, Object lock)56 public FingerprintGestureDispatcher(IFingerprintService fingerprintService, 57 Resources resources, Object lock) { 58 mFingerprintService = fingerprintService; 59 mHardwareSupportsGestures = resources.getBoolean( 60 com.android.internal.R.bool.config_fingerprintSupportsGestures); 61 mLock = lock; 62 mHandler = new Handler(this); 63 } 64 65 /** 66 * @param fingerprintService The system's fingerprint service 67 * @param lock A lock to use when managing internal state 68 * @param handler A handler to use internally. Used for testing. 69 */ FingerprintGestureDispatcher(IFingerprintService fingerprintService, Resources resources, Object lock, Handler handler)70 public FingerprintGestureDispatcher(IFingerprintService fingerprintService, 71 Resources resources, Object lock, Handler handler) { 72 mFingerprintService = fingerprintService; 73 mHardwareSupportsGestures = resources.getBoolean( 74 com.android.internal.R.bool.config_fingerprintSupportsGestures); 75 mLock = lock; 76 mHandler = handler; 77 } 78 79 /** 80 * Update the list of clients that are interested in fingerprint gestures. 81 * 82 * @param clientList The list of potential clients. 83 */ updateClientList(List<? extends FingerprintGestureClient> clientList)84 public void updateClientList(List<? extends FingerprintGestureClient> clientList) { 85 if (!mHardwareSupportsGestures) return; 86 87 synchronized (mLock) { 88 mCapturingClients.clear(); 89 for (int i = 0; i < clientList.size(); i++) { 90 FingerprintGestureClient client = clientList.get(i); 91 if (client.isCapturingFingerprintGestures()) { 92 mCapturingClients.add(client); 93 } 94 } 95 if (mCapturingClients.isEmpty()) { 96 if (mRegisteredReadOnlyExceptInHandler) { 97 mHandler.obtainMessage(MSG_UNREGISTER).sendToTarget(); 98 } 99 } else { 100 if(!mRegisteredReadOnlyExceptInHandler) { 101 mHandler.obtainMessage(MSG_REGISTER).sendToTarget(); 102 } 103 } 104 } 105 } 106 107 @Override onClientActiveChanged(boolean nonGestureFingerprintClientActive)108 public void onClientActiveChanged(boolean nonGestureFingerprintClientActive) { 109 if (!mHardwareSupportsGestures) return; 110 111 synchronized (mLock) { 112 for (int i = 0; i < mCapturingClients.size(); i++) { 113 mCapturingClients.get(i).onFingerprintGestureDetectionActiveChanged( 114 !nonGestureFingerprintClientActive); 115 } 116 } 117 } 118 isFingerprintGestureDetectionAvailable()119 public boolean isFingerprintGestureDetectionAvailable() { 120 if (!mHardwareSupportsGestures) return false; 121 122 final long identity = Binder.clearCallingIdentity(); 123 try { 124 return !mFingerprintService.isClientActive(); 125 } catch (RemoteException re) { 126 return false; 127 } finally { 128 Binder.restoreCallingIdentity(identity); 129 } 130 } 131 132 /** 133 * Called when the fingerprint sensor detects a gesture 134 * 135 * @param fingerprintKeyCode 136 * @return {@code true} if the gesture is consumed. {@code false} otherwise. 137 */ onFingerprintGesture(int fingerprintKeyCode)138 public boolean onFingerprintGesture(int fingerprintKeyCode) { 139 int idForFingerprintGestureManager; 140 141 final List<FingerprintGestureClient> clientList; 142 synchronized (mLock) { 143 if (mCapturingClients.isEmpty()) { 144 return false; 145 } 146 switch (fingerprintKeyCode) { 147 case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP: 148 idForFingerprintGestureManager = 149 FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_UP; 150 break; 151 case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN: 152 idForFingerprintGestureManager = 153 FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_DOWN; 154 break; 155 case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_RIGHT: 156 idForFingerprintGestureManager = 157 FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_RIGHT; 158 break; 159 case KeyEvent.KEYCODE_SYSTEM_NAVIGATION_LEFT: 160 idForFingerprintGestureManager = 161 FingerprintGestureController.FINGERPRINT_GESTURE_SWIPE_LEFT; 162 break; 163 default: 164 return false; 165 } 166 clientList = new ArrayList<>(mCapturingClients); 167 } 168 for (int i = 0; i < clientList.size(); i++) { 169 clientList.get(i).onFingerprintGesture(idForFingerprintGestureManager); 170 } 171 return true; 172 } 173 174 @Override handleMessage(Message message)175 public boolean handleMessage(Message message) { 176 if (message.what == MSG_REGISTER) { 177 final long identity = Binder.clearCallingIdentity(); 178 try { 179 mFingerprintService.addClientActiveCallback(this); 180 mRegisteredReadOnlyExceptInHandler = true; 181 } catch (RemoteException re) { 182 Slog.e(LOG_TAG, "Failed to register for fingerprint activity callbacks"); 183 } finally { 184 Binder.restoreCallingIdentity(identity); 185 } 186 return false; 187 } else if (message.what == MSG_UNREGISTER) { 188 final long identity = Binder.clearCallingIdentity(); 189 try { 190 mFingerprintService.removeClientActiveCallback(this); 191 } catch (RemoteException re) { 192 Slog.e(LOG_TAG, "Failed to unregister for fingerprint activity callbacks"); 193 } finally { 194 Binder.restoreCallingIdentity(identity); 195 } 196 mRegisteredReadOnlyExceptInHandler = false; 197 } else { 198 Slog.e(LOG_TAG, "Unknown message: " + message.what); 199 return false; 200 } 201 return true; 202 } 203 204 // Interface for potential clients. 205 public interface FingerprintGestureClient { 206 /** 207 * @return {@code true} if the client is capturing fingerprint gestures 208 */ isCapturingFingerprintGestures()209 boolean isCapturingFingerprintGestures(); 210 211 /** 212 * Callback when gesture detection becomes active or inactive. 213 * 214 * @param active {@code true} when detection is active 215 */ onFingerprintGestureDetectionActiveChanged(boolean active)216 void onFingerprintGestureDetectionActiveChanged(boolean active); 217 218 /** 219 * Callback when gesture is detected 220 * 221 * @param gesture The identifier for the gesture. For example, 222 * {@link FingerprintGestureController#FINGERPRINT_GESTURE_SWIPE_LEFT} 223 */ onFingerprintGesture(int gesture)224 void onFingerprintGesture(int gesture); 225 } 226 } 227