186 lines
7.4 KiB
Java
186 lines
7.4 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2017 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.accessibilityservice;
|
||
|
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.os.Handler;
|
||
|
import android.os.RemoteException;
|
||
|
import android.util.ArrayMap;
|
||
|
import android.util.Log;
|
||
|
import com.android.internal.annotations.VisibleForTesting;
|
||
|
|
||
|
/**
|
||
|
* An {@link AccessibilityService} can capture gestures performed on a device's fingerprint
|
||
|
* sensor, as long as the device has a sensor capable of detecting gestures.
|
||
|
* <p>
|
||
|
* This capability must be declared by the service as
|
||
|
* {@link AccessibilityServiceInfo#CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES}. It also requires
|
||
|
* the permission {@link android.Manifest.permission#USE_FINGERPRINT}.
|
||
|
* <p>
|
||
|
* Because capturing fingerprint gestures may have side effects, services with the capability only
|
||
|
* capture gestures when {@link AccessibilityServiceInfo#FLAG_REQUEST_FINGERPRINT_GESTURES} is set.
|
||
|
* <p>
|
||
|
* <strong>Note: </strong>The fingerprint sensor is used for authentication in critical use cases,
|
||
|
* so services must carefully design their user's experience when performing gestures on the sensor.
|
||
|
* When the sensor is in use by an app, for example, when authenticating or enrolling a user,
|
||
|
* the sensor will not detect gestures. Services need to ensure that users understand when the
|
||
|
* sensor is in-use for authentication to prevent users from authenticating unintentionally when
|
||
|
* trying to interact with the service. They can use
|
||
|
* {@link FingerprintGestureCallback#onGestureDetectionAvailabilityChanged(boolean)} to learn when
|
||
|
* gesture detection becomes unavailable.
|
||
|
* <p>
|
||
|
* Multiple accessibility services may listen for fingerprint gestures simultaneously, so services
|
||
|
* should provide a way for the user to disable the use of this feature so multiple services don't
|
||
|
* conflict with each other.
|
||
|
* <p>
|
||
|
* {@see android.hardware.fingerprint.FingerprintManager#isHardwareDetected}
|
||
|
*/
|
||
|
public final class FingerprintGestureController {
|
||
|
/** Identifier for a swipe right on the fingerprint sensor */
|
||
|
public static final int FINGERPRINT_GESTURE_SWIPE_RIGHT = 0x00000001;
|
||
|
|
||
|
/** Identifier for a swipe left on the fingerprint sensor */
|
||
|
public static final int FINGERPRINT_GESTURE_SWIPE_LEFT = 0x00000002;
|
||
|
|
||
|
/** Identifier for a swipe up on the fingerprint sensor */
|
||
|
public static final int FINGERPRINT_GESTURE_SWIPE_UP = 0x00000004;
|
||
|
|
||
|
/** Identifier for a swipe down on the fingerprint sensor */
|
||
|
public static final int FINGERPRINT_GESTURE_SWIPE_DOWN = 0x00000008;
|
||
|
|
||
|
private static final String LOG_TAG = "FingerprintGestureController";
|
||
|
private final Object mLock = new Object();
|
||
|
private final IAccessibilityServiceConnection mAccessibilityServiceConnection;
|
||
|
|
||
|
private final ArrayMap<FingerprintGestureCallback, Handler> mCallbackHandlerMap =
|
||
|
new ArrayMap<>(1);
|
||
|
|
||
|
/**
|
||
|
* @param connection The connection to use for system interactions
|
||
|
* @hide
|
||
|
*/
|
||
|
@VisibleForTesting
|
||
|
public FingerprintGestureController(IAccessibilityServiceConnection connection) {
|
||
|
mAccessibilityServiceConnection = connection;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Gets if the fingerprint sensor's gesture detection is available.
|
||
|
*
|
||
|
* @return {@code true} if the sensor's gesture detection is available. {@code false} if it is
|
||
|
* not currently detecting gestures (for example, if it is enrolling a finger).
|
||
|
*/
|
||
|
public boolean isGestureDetectionAvailable() {
|
||
|
try {
|
||
|
return mAccessibilityServiceConnection.isFingerprintGestureDetectionAvailable();
|
||
|
} catch (RemoteException re) {
|
||
|
Log.w(LOG_TAG, "Failed to check if fingerprint gestures are active", re);
|
||
|
re.rethrowFromSystemServer();
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Register a callback to be informed of fingerprint sensor gesture events.
|
||
|
*
|
||
|
* @param callback The listener to be added.
|
||
|
* @param handler The handler to use for the callback. If {@code null}, callbacks will happen
|
||
|
* on the service's main thread.
|
||
|
*/
|
||
|
public void registerFingerprintGestureCallback(
|
||
|
@NonNull FingerprintGestureCallback callback, @Nullable Handler handler) {
|
||
|
synchronized (mLock) {
|
||
|
mCallbackHandlerMap.put(callback, handler);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Unregister a listener added with {@link #registerFingerprintGestureCallback}.
|
||
|
*
|
||
|
* @param callback The callback to remove. Removing a callback that was never added has no
|
||
|
* effect.
|
||
|
*/
|
||
|
public void unregisterFingerprintGestureCallback(FingerprintGestureCallback callback) {
|
||
|
synchronized (mLock) {
|
||
|
mCallbackHandlerMap.remove(callback);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when gesture detection becomes active or inactive
|
||
|
* @hide
|
||
|
*/
|
||
|
public void onGestureDetectionActiveChanged(boolean active) {
|
||
|
final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
|
||
|
synchronized (mLock) {
|
||
|
handlerMap = new ArrayMap<>(mCallbackHandlerMap);
|
||
|
}
|
||
|
int numListeners = handlerMap.size();
|
||
|
for (int i = 0; i < numListeners; i++) {
|
||
|
FingerprintGestureCallback callback = handlerMap.keyAt(i);
|
||
|
Handler handler = handlerMap.valueAt(i);
|
||
|
if (handler != null) {
|
||
|
handler.post(() -> callback.onGestureDetectionAvailabilityChanged(active));
|
||
|
} else {
|
||
|
callback.onGestureDetectionAvailabilityChanged(active);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Called when gesture is detected.
|
||
|
* @hide
|
||
|
*/
|
||
|
public void onGesture(int gesture) {
|
||
|
final ArrayMap<FingerprintGestureCallback, Handler> handlerMap;
|
||
|
synchronized (mLock) {
|
||
|
handlerMap = new ArrayMap<>(mCallbackHandlerMap);
|
||
|
}
|
||
|
int numListeners = handlerMap.size();
|
||
|
for (int i = 0; i < numListeners; i++) {
|
||
|
FingerprintGestureCallback callback = handlerMap.keyAt(i);
|
||
|
Handler handler = handlerMap.valueAt(i);
|
||
|
if (handler != null) {
|
||
|
handler.post(() -> callback.onGestureDetected(gesture));
|
||
|
} else {
|
||
|
callback.onGestureDetected(gesture);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Class that is called back when fingerprint gestures are being used for accessibility.
|
||
|
*/
|
||
|
public abstract static class FingerprintGestureCallback {
|
||
|
/**
|
||
|
* Called when the fingerprint sensor's gesture detection becomes available or unavailable.
|
||
|
*
|
||
|
* @param available Whether or not the sensor's gesture detection is now available.
|
||
|
*/
|
||
|
public void onGestureDetectionAvailabilityChanged(boolean available) {}
|
||
|
|
||
|
/**
|
||
|
* Called when the fingerprint sensor detects gestures.
|
||
|
*
|
||
|
* @param gesture The id of the gesture that was detected. For example,
|
||
|
* {@link #FINGERPRINT_GESTURE_SWIPE_RIGHT}.
|
||
|
*/
|
||
|
public void onGestureDetected(int gesture) {}
|
||
|
}
|
||
|
}
|