summaryrefslogtreecommitdiff
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
authorBeverly <beverlyt@google.com>2021-04-26 18:13:13 -0400
committerBeverly <beverlyt@google.com>2021-04-27 13:58:44 -0400
commitf6346f451397a8a65eff906a1d2728c76584c85b (patch)
treea62abba2ff835c8325a48871d69d0a51948f47ac /packages/SystemUI/src
parentd2c28835dd834c552b3b5200a5a093fbcf72c098 (diff)
Support touchExplorationEnabled on udfps
- When touchExplorationEnabled, touch events become hover events. This updates UdfpsController to handle hover events so the user can still authenticate when a11y options are enabled - Update UdfpsView contentDescription - Update LockIconViewController labels to support a11y Test: manual Bug: 185912108 Change-Id: Ic9590607105459506f8ce5d4d73f779853f1ed31
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java41
2 files changed, 102 insertions, 10 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 66ea2ad001fd..9b0ae6b6b4c5 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -29,9 +29,12 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import com.android.settingslib.Utils;
import com.android.systemui.Dumpable;
@@ -63,6 +66,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@NonNull private final KeyguardStateController mKeyguardStateController;
@NonNull private final FalsingManager mFalsingManager;
@NonNull private final AuthController mAuthController;
+ @NonNull private final AccessibilityManager mAccessibilityManager;
private boolean mHasUdfpsOrFaceAuthFeatures;
private boolean mUdfpsEnrolled;
@@ -93,19 +97,17 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
@NonNull KeyguardStateController keyguardStateController,
@NonNull FalsingManager falsingManager,
@NonNull AuthController authController,
- @NonNull DumpManager dumpManager
+ @NonNull DumpManager dumpManager,
+ @NonNull AccessibilityManager accessibilityManager
) {
super(view);
- if (mView != null) {
- mView.setOnClickListener(v -> onAffordanceClick());
- mView.setOnLongClickListener(v -> onAffordanceClick());
- }
mStatusBarStateController = statusBarStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mAuthController = authController;
mKeyguardViewController = keyguardViewController;
mKeyguardStateController = keyguardStateController;
mFalsingManager = falsingManager;
+ mAccessibilityManager = accessibilityManager;
final Context context = view.getContext();
mButton = context.getResources().getDrawable(
@@ -122,6 +124,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
@Override
+ protected void onInit() {
+ mView.setAccessibilityDelegate(mAccessibilityDelegate);
+ }
+
+ @Override
protected void onViewAttached() {
// we check this here instead of onInit since the FingeprintManager + FaceManager may not
// have started up yet onInit
@@ -163,6 +170,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mKeyguardStateController.addCallback(mKeyguardStateCallback);
+ mAccessibilityManager.addTouchExplorationStateChangeListener(
+ mTouchExplorationStateChangeListener);
updateVisibility();
}
@@ -172,6 +181,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mKeyguardStateController.removeCallback(mKeyguardStateCallback);
+ mAccessibilityManager.removeTouchExplorationStateChangeListener(
+ mTouchExplorationStateChangeListener);
}
public float getTop() {
@@ -210,20 +221,56 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mShowLockIcon = !mUdfpsEnrolled && !mCanDismissLockScreen && isLockScreen()
&& mFaceAuthEnrolled;
+ updateClickListener();
if (mShowButton) {
mView.setImageDrawable(mButton);
mView.setVisibility(View.VISIBLE);
+ mView.setContentDescription(getResources().getString(
+ R.string.accessibility_udfps_disabled_button));
} else if (mShowUnlockIcon) {
mView.setImageDrawable(mUnlockIcon);
mView.setVisibility(View.VISIBLE);
+ mView.setContentDescription(getResources().getString(
+ R.string.accessibility_unlock_button));
} else if (mShowLockIcon) {
mView.setImageDrawable(mLockIcon);
mView.setVisibility(View.VISIBLE);
+ mView.setContentDescription(getResources().getString(
+ R.string.accessibility_lock_icon));
} else {
mView.setVisibility(View.INVISIBLE);
+ mView.setContentDescription(null);
}
}
+ private final View.AccessibilityDelegate mAccessibilityDelegate =
+ new View.AccessibilityDelegate() {
+ private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityAuthenticateHint =
+ new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfoCompat.ACTION_CLICK,
+ getResources().getString(R.string.accessibility_authenticate_hint));
+ private final AccessibilityNodeInfo.AccessibilityAction mAccessibilityEnterHint =
+ new AccessibilityNodeInfo.AccessibilityAction(
+ AccessibilityNodeInfoCompat.ACTION_CLICK,
+ getResources().getString(R.string.accessibility_enter_hint));
+ public void onInitializeAccessibilityNodeInfo(View v, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(v, info);
+ removeAllActions(info);
+ if (mShowButton || mShowLockIcon) {
+ info.addAction(mAccessibilityAuthenticateHint);
+ } else if (mShowUnlockIcon) {
+ info.addAction(mAccessibilityEnterHint);
+ }
+ }
+
+ private void removeAllActions(AccessibilityNodeInfo info) {
+ info.removeAction(mAccessibilityAuthenticateHint);
+ info.removeAction(mAccessibilityEnterHint);
+ info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+ mView.setLongClickable(false);
+ }
+ };
+
private boolean isLockScreen() {
return !mIsDozing
&& !mIsBouncerShowing
@@ -231,6 +278,17 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
&& mStatusBarState == StatusBarState.KEYGUARD;
}
+ private void updateClickListener() {
+ if (mView != null) {
+ mView.setOnClickListener(v -> onAffordanceClick());
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ mView.setOnLongClickListener(null);
+ } else {
+ mView.setOnLongClickListener(v -> onAffordanceClick());
+ }
+ }
+ }
+
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(" mShowBouncerButton: " + mShowButton);
@@ -298,4 +356,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
updateVisibility();
}
};
+
+ private final AccessibilityManager.TouchExplorationStateChangeListener
+ mTouchExplorationStateChangeListener = enabled -> updateClickListener();
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 7ebfb7266c11..ee5fb313fff3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -28,7 +28,6 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.RectF;
@@ -55,6 +54,7 @@ import android.view.Surface;
import android.view.VelocityTracker;
import android.view.View;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -108,6 +108,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@NonNull private final Handler mMainHandler;
@NonNull private final FalsingManager mFalsingManager;
@NonNull private final PowerManager mPowerManager;
+ @NonNull private final AccessibilityManager mAccessibilityManager;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -276,6 +277,13 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) ->
onTouch(view, event, true);
+ @SuppressLint("ClickableViewAccessibility")
+ private final UdfpsView.OnHoverListener mOnHoverListener = (view, event) ->
+ onTouch(view, event, true);
+
+ private final AccessibilityManager.TouchExplorationStateChangeListener
+ mTouchExplorationStateChangeListener = enabled -> updateTouchListener();
+
/**
* @param x coordinate
* @param y coordinate
@@ -300,6 +308,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
udfpsView.onTouchOutsideView();
break;
case MotionEvent.ACTION_DOWN:
+ case MotionEvent.ACTION_HOVER_ENTER:
// To simplify the lifecycle of the velocity tracker, make sure it's never null
// after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
if (mVelocityTracker == null) {
@@ -322,6 +331,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
break;
case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_HOVER_MOVE:
final int idx = mActivePointerId == -1
? event.getPointerId(0)
: event.findPointerIndex(mActivePointerId);
@@ -388,6 +398,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_HOVER_EXIT:
mActivePointerId = -1;
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
@@ -409,10 +420,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@Inject
public UdfpsController(@NonNull Context context,
- @Main Resources resources,
@NonNull LayoutInflater inflater,
@Nullable FingerprintManager fingerprintManager,
- WindowManager windowManager,
+ @NonNull WindowManager windowManager,
@NonNull StatusBarStateController statusBarStateController,
@Main DelayableExecutor fgExecutor,
@NonNull StatusBar statusBar,
@@ -421,7 +431,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
@NonNull KeyguardViewMediator keyguardViewMediator,
@NonNull FalsingManager falsingManager,
- @NonNull PowerManager powerManager) {
+ @NonNull PowerManager powerManager,
+ @NonNull AccessibilityManager accessibilityManager) {
mContext = context;
// TODO (b/185124905): inject main handler and vibrator once done prototyping
mMainHandler = new Handler(Looper.getMainLooper());
@@ -440,6 +451,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
mKeyguardViewMediator = keyguardViewMediator;
mFalsingManager = falsingManager;
mPowerManager = powerManager;
+ mAccessibilityManager = accessibilityManager;
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -577,7 +589,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
mView.setAnimationViewController(animation);
mWindowManager.addView(mView, computeLayoutParams(animation));
- mView.setOnTouchListener(mOnTouchListener);
+ mAccessibilityManager.addTouchExplorationStateChangeListener(
+ mTouchExplorationStateChangeListener);
+ updateTouchListener();
} catch (RuntimeException e) {
Log.e(TAG, "showUdfpsOverlay | failed to add window", e);
}
@@ -650,7 +664,10 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
onFingerUp();
mWindowManager.removeView(mView);
mView.setOnTouchListener(null);
+ mView.setOnHoverListener(null);
mView.setAnimationViewController(null);
+ mAccessibilityManager.removeTouchExplorationStateChangeListener(
+ mTouchExplorationStateChangeListener);
mView = null;
} else {
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
@@ -758,4 +775,18 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
return defaultEffect;
}
}
+
+ private void updateTouchListener() {
+ if (mView == null) {
+ return;
+ }
+
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ mView.setOnHoverListener(mOnHoverListener);
+ mView.setOnTouchListener(null);
+ } else {
+ mView.setOnHoverListener(null);
+ mView.setOnTouchListener(mOnTouchListener);
+ }
+ }
}