Loading packages/SystemUI/res/layout/udfps_view.xml +2 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,8 @@ android:id="@+id/udfps_view" android:layout_width="match_parent" android:layout_height="match_parent" systemui:sensorTouchAreaCoefficient="0.5"> systemui:sensorTouchAreaCoefficient="0.5" android:contentDescription="@string/accessibility_fingerprint_label"> <ViewStub android:id="@+id/animation_view" Loading packages/SystemUI/res/values/strings.xml +13 −0 Original line number Diff line number Diff line Loading @@ -338,6 +338,8 @@ <string name="accessibility_voice_assist_button">Voice Assist</string> <!-- Content description of the unlock button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_unlock_button">Unlock</string> <!-- Content description of the lock icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_lock_icon">Device locked</string> <!-- Content description hint of the unlock button when fingerprint is on (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string> <!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] --> Loading Loading @@ -2958,4 +2960,15 @@ <!-- Secondary label for alarm tile when there is no next alarm information [CHAR LIMIT=20] --> <string name="qs_alarm_tile_no_alarm">No alarm set</string> <!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] --> <string name="accessibility_fingerprint_label">Fingerprint sensor</string> <!-- Accessibility label for disabled udfps sensor [CHAR LIMIT=NONE] --> <string name="accessibility_udfps_disabled_button">Fingerprint sensor disabled</string> <!-- Accessibility action for tapping on an affordance that will bring up the user's pin/pattern/password bouncer (ie: "Double tap to authenticate") [CHAR LIMIT=NONE] --> <string name="accessibility_authenticate_hint">authenticate</string> <!-- Accessibility action for tapping on an affordance on an unlocked lock screen (ie: "Double tap to enter device") [CHAR LIMIT=NONE] --> <string name="accessibility_enter_hint">enter device</string> </resources> packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +66 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading @@ -121,6 +123,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme dumpManager.registerDumpable("LockIconViewController", this); } @Override protected void onInit() { mView.setAccessibilityDelegate(mAccessibilityDelegate); } @Override protected void onViewAttached() { // we check this here instead of onInit since the FingeprintManager + FaceManager may not Loading Loading @@ -163,6 +170,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); mStatusBarStateController.addCallback(mStatusBarStateListener); mKeyguardStateController.addCallback(mKeyguardStateCallback); mAccessibilityManager.addTouchExplorationStateChangeListener( mTouchExplorationStateChangeListener); updateVisibility(); } Loading @@ -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() { Loading Loading @@ -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 Loading @@ -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); Loading Loading @@ -298,4 +356,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme updateVisibility(); } }; private final AccessibilityManager.TouchExplorationStateChangeListener mTouchExplorationStateChangeListener = enabled -> updateClickListener(); } packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +36 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 Loading @@ -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) { Loading @@ -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); Loading Loading @@ -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(); Loading @@ -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, Loading @@ -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()); Loading @@ -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 Loading Loading @@ -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); } Loading Loading @@ -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"); Loading Loading @@ -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); } } } packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +5 −12 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.res.Resources; import android.content.res.TypedArray; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; Loading @@ -40,6 +39,7 @@ import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; Loading Loading @@ -85,8 +85,6 @@ public class UdfpsControllerTest extends SysuiTestCase { // Dependencies @Mock private Resources mResources; @Mock private LayoutInflater mLayoutInflater; @Mock private FingerprintManager mFingerprintManager; Loading @@ -110,6 +108,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private FalsingManager mFalsingManager; @Mock private PowerManager mPowerManager; @Mock private AccessibilityManager mAccessibilityManager; private FakeExecutor mFgExecutor; Loading Loading @@ -151,7 +151,6 @@ public class UdfpsControllerTest extends SysuiTestCase { mFgExecutor = new FakeExecutor(new FakeSystemClock()); mUdfpsController = new UdfpsController( mContext, mResources, mLayoutInflater, mFingerprintManager, mWindowManager, Loading @@ -163,7 +162,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor, mKeyguardViewMediator, mFalsingManager, mPowerManager); mPowerManager, mAccessibilityManager); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); Loading @@ -174,16 +174,9 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mBrightnessValues.length()).thenReturn(2); when(mBrightnessValues.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f); when(mBrightnessValues.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f); when(mResources.obtainTypedArray(com.android.internal.R.array.config_screenBrightnessNits)) .thenReturn(mBrightnessValues); when(mBrightnessBacklight.length()).thenReturn(2); when(mBrightnessBacklight.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f); when(mBrightnessBacklight.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f); when(mResources.obtainTypedArray( com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)) .thenReturn(mBrightnessBacklight); when(mResources.getIntArray(com.android.internal.R.array.config_screenBrightnessBacklight)) .thenReturn(new int[]{1, 2}); } @Test Loading Loading
packages/SystemUI/res/layout/udfps_view.xml +2 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,8 @@ android:id="@+id/udfps_view" android:layout_width="match_parent" android:layout_height="match_parent" systemui:sensorTouchAreaCoefficient="0.5"> systemui:sensorTouchAreaCoefficient="0.5" android:contentDescription="@string/accessibility_fingerprint_label"> <ViewStub android:id="@+id/animation_view" Loading
packages/SystemUI/res/values/strings.xml +13 −0 Original line number Diff line number Diff line Loading @@ -338,6 +338,8 @@ <string name="accessibility_voice_assist_button">Voice Assist</string> <!-- Content description of the unlock button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_unlock_button">Unlock</string> <!-- Content description of the lock icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_lock_icon">Device locked</string> <!-- Content description hint of the unlock button when fingerprint is on (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_waiting_for_fingerprint">Waiting for fingerprint</string> <!-- Accessibility action of the unlock button when fingerpint is on (not shown on the screen). [CHAR LIMIT=NONE] --> Loading Loading @@ -2958,4 +2960,15 @@ <!-- Secondary label for alarm tile when there is no next alarm information [CHAR LIMIT=20] --> <string name="qs_alarm_tile_no_alarm">No alarm set</string> <!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] --> <string name="accessibility_fingerprint_label">Fingerprint sensor</string> <!-- Accessibility label for disabled udfps sensor [CHAR LIMIT=NONE] --> <string name="accessibility_udfps_disabled_button">Fingerprint sensor disabled</string> <!-- Accessibility action for tapping on an affordance that will bring up the user's pin/pattern/password bouncer (ie: "Double tap to authenticate") [CHAR LIMIT=NONE] --> <string name="accessibility_authenticate_hint">authenticate</string> <!-- Accessibility action for tapping on an affordance on an unlocked lock screen (ie: "Double tap to enter device") [CHAR LIMIT=NONE] --> <string name="accessibility_enter_hint">enter device</string> </resources>
packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +66 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading @@ -121,6 +123,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme dumpManager.registerDumpable("LockIconViewController", this); } @Override protected void onInit() { mView.setAccessibilityDelegate(mAccessibilityDelegate); } @Override protected void onViewAttached() { // we check this here instead of onInit since the FingeprintManager + FaceManager may not Loading Loading @@ -163,6 +170,8 @@ public class LockIconViewController extends ViewController<LockIconView> impleme mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback); mStatusBarStateController.addCallback(mStatusBarStateListener); mKeyguardStateController.addCallback(mKeyguardStateCallback); mAccessibilityManager.addTouchExplorationStateChangeListener( mTouchExplorationStateChangeListener); updateVisibility(); } Loading @@ -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() { Loading Loading @@ -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 Loading @@ -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); Loading Loading @@ -298,4 +356,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme updateVisibility(); } }; private final AccessibilityManager.TouchExplorationStateChangeListener mTouchExplorationStateChangeListener = enabled -> updateClickListener(); }
packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +36 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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 Loading @@ -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) { Loading @@ -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); Loading Loading @@ -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(); Loading @@ -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, Loading @@ -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()); Loading @@ -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 Loading Loading @@ -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); } Loading Loading @@ -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"); Loading Loading @@ -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); } } }
packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +5 −12 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.res.Resources; import android.content.res.TypedArray; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; Loading @@ -40,6 +39,7 @@ import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import androidx.test.filters.SmallTest; Loading Loading @@ -85,8 +85,6 @@ public class UdfpsControllerTest extends SysuiTestCase { // Dependencies @Mock private Resources mResources; @Mock private LayoutInflater mLayoutInflater; @Mock private FingerprintManager mFingerprintManager; Loading @@ -110,6 +108,8 @@ public class UdfpsControllerTest extends SysuiTestCase { private FalsingManager mFalsingManager; @Mock private PowerManager mPowerManager; @Mock private AccessibilityManager mAccessibilityManager; private FakeExecutor mFgExecutor; Loading Loading @@ -151,7 +151,6 @@ public class UdfpsControllerTest extends SysuiTestCase { mFgExecutor = new FakeExecutor(new FakeSystemClock()); mUdfpsController = new UdfpsController( mContext, mResources, mLayoutInflater, mFingerprintManager, mWindowManager, Loading @@ -163,7 +162,8 @@ public class UdfpsControllerTest extends SysuiTestCase { mKeyguardUpdateMonitor, mKeyguardViewMediator, mFalsingManager, mPowerManager); mPowerManager, mAccessibilityManager); verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture()); mOverlayController = mOverlayCaptor.getValue(); Loading @@ -174,16 +174,9 @@ public class UdfpsControllerTest extends SysuiTestCase { when(mBrightnessValues.length()).thenReturn(2); when(mBrightnessValues.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f); when(mBrightnessValues.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f); when(mResources.obtainTypedArray(com.android.internal.R.array.config_screenBrightnessNits)) .thenReturn(mBrightnessValues); when(mBrightnessBacklight.length()).thenReturn(2); when(mBrightnessBacklight.getFloat(0, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(1f); when(mBrightnessBacklight.getFloat(1, PowerManager.BRIGHTNESS_OFF_FLOAT)).thenReturn(2f); when(mResources.obtainTypedArray( com.android.internal.R.array.config_autoBrightnessDisplayValuesNits)) .thenReturn(mBrightnessBacklight); when(mResources.getIntArray(com.android.internal.R.array.config_screenBrightnessBacklight)) .thenReturn(new int[]{1, 2}); } @Test Loading