Loading packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +10 −9 Original line number Original line Diff line number Diff line Loading @@ -58,7 +58,8 @@ import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Gefingerpoken; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; import com.android.systemui.R; import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.biometrics.SideFpsController; import com.android.systemui.biometrics.SideFpsUiRequestSource; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags; Loading Loading @@ -100,7 +101,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final GlobalSettings mGlobalSettings; private final GlobalSettings mGlobalSettings; private final FeatureFlags mFeatureFlags; private final FeatureFlags mFeatureFlags; private final SessionTracker mSessionTracker; private final SessionTracker mSessionTracker; private final Optional<SidefpsController> mSidefpsController; private final Optional<SideFpsController> mSideFpsController; private final FalsingA11yDelegate mFalsingA11yDelegate; private final FalsingA11yDelegate mFalsingA11yDelegate; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; Loading Loading @@ -290,7 +291,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard FeatureFlags featureFlags, FeatureFlags featureFlags, GlobalSettings globalSettings, GlobalSettings globalSettings, SessionTracker sessionTracker, SessionTracker sessionTracker, Optional<SidefpsController> sidefpsController, Optional<SideFpsController> sideFpsController, FalsingA11yDelegate falsingA11yDelegate) { FalsingA11yDelegate falsingA11yDelegate) { super(view); super(view); mLockPatternUtils = lockPatternUtils; mLockPatternUtils = lockPatternUtils; Loading @@ -311,7 +312,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mFeatureFlags = featureFlags; mFeatureFlags = featureFlags; mGlobalSettings = globalSettings; mGlobalSettings = globalSettings; mSessionTracker = sessionTracker; mSessionTracker = sessionTracker; mSidefpsController = sidefpsController; mSideFpsController = sideFpsController; mFalsingA11yDelegate = falsingA11yDelegate; mFalsingA11yDelegate = falsingA11yDelegate; } } Loading Loading @@ -351,7 +352,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } } private void updateSideFpsVisibility() { private void updateSideFpsVisibility() { if (!mSidefpsController.isPresent()) { if (!mSideFpsController.isPresent()) { return; return; } } final boolean sfpsEnabled = getResources().getBoolean( final boolean sfpsEnabled = getResources().getBoolean( Loading @@ -369,9 +370,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard + "needsStrongAuth=" + needsStrongAuth); + "needsStrongAuth=" + needsStrongAuth); } } if (toShow) { if (toShow) { mSidefpsController.get().show(); mSideFpsController.get().show(SideFpsUiRequestSource.PRIMARY_BOUNCER); } else { } else { mSidefpsController.get().hide(); mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); } } } } Loading Loading @@ -745,7 +746,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final FeatureFlags mFeatureFlags; private final FeatureFlags mFeatureFlags; private final UserSwitcherController mUserSwitcherController; private final UserSwitcherController mUserSwitcherController; private final SessionTracker mSessionTracker; private final SessionTracker mSessionTracker; private final Optional<SidefpsController> mSidefpsController; private final Optional<SideFpsController> mSidefpsController; private final FalsingA11yDelegate mFalsingA11yDelegate; private final FalsingA11yDelegate mFalsingA11yDelegate; @Inject @Inject Loading @@ -766,7 +767,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard FeatureFlags featureFlags, FeatureFlags featureFlags, GlobalSettings globalSettings, GlobalSettings globalSettings, SessionTracker sessionTracker, SessionTracker sessionTracker, Optional<SidefpsController> sidefpsController, Optional<SideFpsController> sidefpsController, FalsingA11yDelegate falsingA11yDelegate) { FalsingA11yDelegate falsingA11yDelegate) { mView = view; mView = view; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; Loading packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java +5 −5 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,7 @@ package com.android.keyguard.dagger; package com.android.keyguard.dagger; import static com.android.systemui.biometrics.SidefpsControllerKt.hasSideFpsSensor; import static com.android.systemui.biometrics.SideFpsControllerKt.hasSideFpsSensor; import android.annotation.Nullable; import android.annotation.Nullable; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager; Loading @@ -27,7 +27,7 @@ import com.android.keyguard.KeyguardHostView; import com.android.keyguard.KeyguardSecurityContainer; import com.android.keyguard.KeyguardSecurityContainer; import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.systemui.R; import com.android.systemui.R; import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.biometrics.SideFpsController; import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.KeyguardBouncer; Loading Loading @@ -70,12 +70,12 @@ public interface KeyguardBouncerModule { return containerView.findViewById(R.id.view_flipper); return containerView.findViewById(R.id.view_flipper); } } /** Provides {@link SidefpsController} if the device has the side fingerprint sensor. */ /** Provides {@link SideFpsController} if the device has the side fingerprint sensor. */ @Provides @Provides @KeyguardBouncerScope @KeyguardBouncerScope static Optional<SidefpsController> providesOptionalSidefpsController( static Optional<SideFpsController> providesOptionalSidefpsController( @Nullable FingerprintManager fingerprintManager, @Nullable FingerprintManager fingerprintManager, Provider<SidefpsController> sidefpsControllerProvider) { Provider<SideFpsController> sidefpsControllerProvider) { if (!hasSideFpsSensor(fingerprintManager)) { if (!hasSideFpsSensor(fingerprintManager)) { return Optional.empty(); return Optional.empty(); } } Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +5 −5 Original line number Original line Diff line number Diff line Loading @@ -119,7 +119,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; @Nullable private final FaceManager mFaceManager; private final Provider<UdfpsController> mUdfpsControllerFactory; private final Provider<UdfpsController> mUdfpsControllerFactory; private final Provider<SidefpsController> mSidefpsControllerFactory; private final Provider<SideFpsController> mSidefpsControllerFactory; private final Display mDisplay; private final Display mDisplay; private float mScaleFactor = 1f; private float mScaleFactor = 1f; Loading @@ -141,7 +141,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull private final DisplayManager mDisplayManager; @NonNull private final DisplayManager mDisplayManager; @Nullable private UdfpsController mUdfpsController; @Nullable private UdfpsController mUdfpsController; @Nullable private IUdfpsHbmListener mUdfpsHbmListener; @Nullable private IUdfpsHbmListener mUdfpsHbmListener; @Nullable private SidefpsController mSidefpsController; @Nullable private SideFpsController mSideFpsController; @Nullable private IBiometricContextListener mBiometricContextListener; @Nullable private IBiometricContextListener mBiometricContextListener; @VisibleForTesting IBiometricSysuiReceiver mReceiver; @VisibleForTesting IBiometricSysuiReceiver mReceiver; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; Loading Loading @@ -316,7 +316,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; if (mSidefpsProps != null) { if (mSidefpsProps != null) { mSidefpsController = mSidefpsControllerFactory.get(); mSideFpsController = mSidefpsControllerFactory.get(); } } updateSensorLocations(); updateSensorLocations(); Loading Loading @@ -677,7 +677,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @Nullable FingerprintManager fingerprintManager, @Nullable FingerprintManager fingerprintManager, @Nullable FaceManager faceManager, @Nullable FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory, Provider<UdfpsController> udfpsControllerFactory, Provider<SidefpsController> sidefpsControllerFactory, Provider<SideFpsController> sidefpsControllerFactory, @NonNull DisplayManager displayManager, @NonNull DisplayManager displayManager, @NonNull WakefulnessLifecycle wakefulnessLifecycle, @NonNull WakefulnessLifecycle wakefulnessLifecycle, @NonNull UserManager userManager, @NonNull UserManager userManager, Loading Loading @@ -1054,7 +1054,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, * Whether the passed userId has enrolled SFPS. * Whether the passed userId has enrolled SFPS. */ */ public boolean isSfpsEnrolled(int userId) { public boolean isSfpsEnrolled(int userId) { if (mSidefpsController == null) { if (mSideFpsController == null) { return false; return false; } } Loading packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt→packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt +164 −104 Original line number Original line Diff line number Diff line Loading @@ -51,20 +51,25 @@ import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieProperty import com.airbnb.lottie.LottieProperty import com.airbnb.lottie.model.KeyPath import com.airbnb.lottie.model.KeyPath import com.android.internal.annotations.VisibleForTesting import com.android.internal.annotations.VisibleForTesting import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.recents.OverviewProxyService import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor import java.io.PrintWriter import javax.inject.Inject import javax.inject.Inject private const val TAG = "SidefpsController" private const val TAG = "SideFpsController" /** /** * Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events. * Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events. */ */ @SysUISingleton @SysUISingleton class SidefpsController @Inject constructor( class SideFpsController @Inject constructor( private val context: Context, private val context: Context, private val layoutInflater: LayoutInflater, private val layoutInflater: LayoutInflater, fingerprintManager: FingerprintManager?, fingerprintManager: FingerprintManager?, Loading @@ -73,15 +78,19 @@ class SidefpsController @Inject constructor( overviewProxyService: OverviewProxyService, overviewProxyService: OverviewProxyService, displayManager: DisplayManager, displayManager: DisplayManager, @Main private val mainExecutor: DelayableExecutor, @Main private val mainExecutor: DelayableExecutor, @Main private val handler: Handler @Main private val handler: Handler, ) { dumpManager: DumpManager ) : Dumpable { val requests: HashSet<SideFpsUiRequestSource> = HashSet() @VisibleForTesting @VisibleForTesting val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager val sensorProps: FingerprintSensorPropertiesInternal = ?.sideFpsSensorProperties fingerprintManager?.sideFpsSensorProperties ?: throw IllegalStateException("no side fingerprint sensor") ?: throw IllegalStateException("no side fingerprint sensor") @VisibleForTesting @VisibleForTesting val orientationListener = BiometricDisplayListener( val orientationListener = BiometricDisplayListener( context, context, displayManager, displayManager, handler, handler, Loading @@ -89,7 +98,8 @@ class SidefpsController @Inject constructor( ) { onOrientationChanged() } ) { onOrientationChanged() } @VisibleForTesting @VisibleForTesting val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener { val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener { override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { overlayView?.let { view -> overlayView?.let { view -> handler.postDelayed({ updateOverlayVisibility(view) }, 500) handler.postDelayed({ updateOverlayVisibility(view) }, 500) Loading Loading @@ -121,17 +131,20 @@ class SidefpsController @Inject constructor( @VisibleForTesting @VisibleForTesting internal var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT internal var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT private val overlayViewParams = WindowManager.LayoutParams( private val overlayViewParams = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, PixelFormat.TRANSLUCENT PixelFormat.TRANSLUCENT ).apply { ) .apply { title = TAG title = TAG fitInsetsTypes = 0 // overrides default, avoiding status bars during layout fitInsetsTypes = 0 // overrides default, avoiding status bars during layout gravity = Gravity.TOP or Gravity.LEFT gravity = Gravity.TOP or Gravity.LEFT layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION } } Loading @@ -141,15 +154,23 @@ class SidefpsController @Inject constructor( override fun show( override fun show( sensorId: Int, sensorId: Int, @BiometricOverlayConstants.ShowReason reason: Int @BiometricOverlayConstants.ShowReason reason: Int ) = if (reason.isReasonToShow(activityTaskManager)) show() else hide() ) = if (reason.isReasonToAutoShow(activityTaskManager)) { show(SideFpsUiRequestSource.AUTO_SHOW) } else { hide(SideFpsUiRequestSource.AUTO_SHOW) } override fun hide(sensorId: Int) = hide() override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW) }) } ) overviewProxyService.addCallback(overviewProxyListener) overviewProxyService.addCallback(overviewProxyListener) dumpManager.registerDumpable(this) } } /** Shows the side fps overlay if not already shown. */ /** Shows the side fps overlay if not already shown. */ fun show() { fun show(request: SideFpsUiRequestSource) { requests.add(request) mainExecutor.execute { mainExecutor.execute { if (overlayView == null) { if (overlayView == null) { createOverlayForDisplay() createOverlayForDisplay() Loading @@ -160,8 +181,20 @@ class SidefpsController @Inject constructor( } } /** Hides the fps overlay if shown. */ /** Hides the fps overlay if shown. */ fun hide() { fun hide(request: SideFpsUiRequestSource) { mainExecutor.execute { overlayView = null } requests.remove(request) mainExecutor.execute { if (requests.isEmpty()) { overlayView = null } } } override fun dump(pw: PrintWriter, args: Array<out String>) { pw.println("requests:") for (requestSource in requests) { pw.println(" $requestSource.name") } } } private fun onOrientationChanged() { private fun onOrientationChanged() { Loading @@ -174,7 +207,8 @@ class SidefpsController @Inject constructor( val view = layoutInflater.inflate(R.layout.sidefps_view, null, false) val view = layoutInflater.inflate(R.layout.sidefps_view, null, false) overlayView = view overlayView = view val display = context.display!! val display = context.display!! val offsets = sensorProps.getLocation(display.uniqueId).let { location -> val offsets = sensorProps.getLocation(display.uniqueId).let { location -> if (location == null) { if (location == null) { Log.w(TAG, "No location specified for display: ${display.uniqueId}") Log.w(TAG, "No location specified for display: ${display.uniqueId}") } } Loading @@ -195,21 +229,25 @@ class SidefpsController @Inject constructor( /** /** * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from * speaking @string/accessibility_fingerprint_label twice when sensor location indicator * speaking @string/accessibility_fingerprint_label twice when sensor location indicator is * is in focus * in focus */ */ view.setAccessibilityDelegate(object : AccessibilityDelegate() { view.setAccessibilityDelegate( object : AccessibilityDelegate() { override fun dispatchPopulateAccessibilityEvent( override fun dispatchPopulateAccessibilityEvent( host: View, host: View, event: AccessibilityEvent event: AccessibilityEvent ): Boolean { ): Boolean { return if (event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { return if ( event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED ) { true true } else { } else { super.dispatchPopulateAccessibilityEvent(host, event) super.dispatchPopulateAccessibilityEvent(host, event) } } } } }) } ) } } @VisibleForTesting @VisibleForTesting Loading @@ -220,7 +258,8 @@ class SidefpsController @Inject constructor( val displayHeight = if (isNaturalOrientation) size.height() else size.width() val displayHeight = if (isNaturalOrientation) size.height() else size.width() val boundsWidth = if (isNaturalOrientation) bounds.width() else bounds.height() val boundsWidth = if (isNaturalOrientation) bounds.width() else bounds.height() val boundsHeight = if (isNaturalOrientation) bounds.height() else bounds.width() val boundsHeight = if (isNaturalOrientation) bounds.height() else bounds.width() val sensorBounds = if (overlayOffsets.isYAligned()) { val sensorBounds = if (overlayOffsets.isYAligned()) { Rect( Rect( displayWidth - boundsWidth, displayWidth - boundsWidth, overlayOffsets.sensorLocationY, overlayOffsets.sensorLocationY, Loading Loading @@ -254,19 +293,25 @@ class SidefpsController @Inject constructor( // hide after a few seconds if the sensor is oriented down and there are // hide after a few seconds if the sensor is oriented down and there are // large overlapping system bars // large overlapping system bars val rotation = context.display?.rotation val rotation = context.display?.rotation if (windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar() && if ( windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar() && ((rotation == Surface.ROTATION_270 && overlayOffsets.isYAligned()) || ((rotation == Surface.ROTATION_270 && overlayOffsets.isYAligned()) || (rotation == Surface.ROTATION_180 && !overlayOffsets.isYAligned()))) { (rotation == Surface.ROTATION_180 && !overlayOffsets.isYAligned())) overlayHideAnimator = view.animate() ) { overlayHideAnimator = view .animate() .alpha(0f) .alpha(0f) .setStartDelay(3_000) .setStartDelay(3_000) .setDuration(animationDuration) .setDuration(animationDuration) .setListener(object : AnimatorListenerAdapter() { .setListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) { view.visibility = View.GONE view.visibility = View.GONE overlayHideAnimator = null overlayHideAnimator = null } } }) } ) } else { } else { overlayHideAnimator?.cancel() overlayHideAnimator?.cancel() overlayHideAnimator = null overlayHideAnimator = null Loading @@ -283,9 +328,11 @@ private val FingerprintManager?.sideFpsSensorProperties: FingerprintSensorProper fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null @BiometricOverlayConstants.ShowReason @BiometricOverlayConstants.ShowReason private fun Int.isReasonToShow(activityTaskManager: ActivityTaskManager): Boolean = when (this) { private fun Int.isReasonToAutoShow(activityTaskManager: ActivityTaskManager): Boolean = when (this) { REASON_AUTH_KEYGUARD -> false REASON_AUTH_KEYGUARD -> false REASON_AUTH_SETTINGS -> when (activityTaskManager.topClass()) { REASON_AUTH_SETTINGS -> when (activityTaskManager.topClass()) { // TODO(b/186176653): exclude fingerprint overlays from this list view // TODO(b/186176653): exclude fingerprint overlays from this list view "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false else -> true else -> true Loading @@ -297,13 +344,15 @@ private fun ActivityTaskManager.topClass(): String = getTasks(1).firstOrNull()?.topActivity?.className ?: "" getTasks(1).firstOrNull()?.topActivity?.className ?: "" @RawRes @RawRes private fun Display.asSideFpsAnimation(yAligned: Boolean): Int = when (rotation) { private fun Display.asSideFpsAnimation(yAligned: Boolean): Int = when (rotation) { Surface.ROTATION_0 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape Surface.ROTATION_0 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape Surface.ROTATION_180 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape Surface.ROTATION_180 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape else -> if (yAligned) R.raw.sfps_pulse_landscape else R.raw.sfps_pulse else -> if (yAligned) R.raw.sfps_pulse_landscape else R.raw.sfps_pulse } } private fun Display.asSideFpsAnimationRotation(yAligned: Boolean): Float = when (rotation) { private fun Display.asSideFpsAnimationRotation(yAligned: Boolean): Float = when (rotation) { Surface.ROTATION_90 -> if (yAligned) 0f else 180f Surface.ROTATION_90 -> if (yAligned) 0f else 180f Surface.ROTATION_180 -> 180f Surface.ROTATION_180 -> 180f Surface.ROTATION_270 -> if (yAligned) 180f else 0f Surface.ROTATION_270 -> if (yAligned) 180f else 0f Loading @@ -322,10 +371,9 @@ private fun LottieAnimationView.addOverlayDynamicColor(context: Context) { fun update() { fun update() { val c = context.getColor(R.color.biometric_dialog_accent) val c = context.getColor(R.color.biometric_dialog_accent) for (key in listOf(".blue600", ".blue400")) { for (key in listOf(".blue600", ".blue400")) { addValueCallback( addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) { KeyPath(key, "**"), PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP) LottieProperty.COLOR_FILTER } ) { PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP) } } } } } Loading @@ -335,3 +383,15 @@ private fun LottieAnimationView.addOverlayDynamicColor(context: Context) { addLottieOnCompositionLoadedListener { update() } addLottieOnCompositionLoadedListener { update() } } } } } /** * The source of a request to show the side fps visual indicator. This is distinct from * [BiometricOverlayConstants] which corrresponds with the reason fingerprint authentication is * requested. */ enum class SideFpsUiRequestSource { /** see [isReasonToAutoShow] */ AUTO_SHOW, /** Pin, pattern or password bouncer */ PRIMARY_BOUNCER, } packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +34 −33 Original line number Original line Diff line number Diff line Loading @@ -54,7 +54,8 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.biometrics.SideFpsController; import com.android.systemui.biometrics.SideFpsUiRequestSource; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags; Loading Loading @@ -141,7 +142,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Mock @Mock private KeyguardViewController mKeyguardViewController; private KeyguardViewController mKeyguardViewController; @Mock @Mock private SidefpsController mSidefpsController; private SideFpsController mSideFpsController; @Mock @Mock private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock; private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock; @Mock @Mock Loading Loading @@ -189,7 +190,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mKeyguardStateController, mKeyguardSecurityViewFlipperController, mKeyguardStateController, mKeyguardSecurityViewFlipperController, mConfigurationController, mFalsingCollector, mFalsingManager, mConfigurationController, mFalsingCollector, mFalsingManager, mUserSwitcherController, mFeatureFlags, mGlobalSettings, mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker, Optional.of(mSidefpsController), mFalsingA11yDelegate).create( mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate).create( mSecurityCallback); mSecurityCallback); } } Loading Loading @@ -345,48 +346,48 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Test @Test public void onBouncerVisibilityChanged_allConditionsGood_sideFpsHintShown() { public void onBouncerVisibilityChanged_allConditionsGood_sideFpsHintShown() { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController).show(); verify(mSideFpsController).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).hide(); verify(mSideFpsController, never()).hide(any()); } } @Test @Test public void onBouncerVisibilityChanged_fpsSensorNotRunning_sideFpsHintHidden() { public void onBouncerVisibilityChanged_fpsSensorNotRunning_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); setFingerprintDetectionRunning(false); setFingerprintDetectionRunning(false); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test public void onBouncerVisibilityChanged_withoutSidedSecurity_sideFpsHintHidden() { public void onBouncerVisibilityChanged_withoutSidedSecurity_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); setSideFpsHintEnabledFromResources(false); setSideFpsHintEnabledFromResources(false); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test public void onBouncerVisibilityChanged_needsStrongAuth_sideFpsHintHidden() { public void onBouncerVisibilityChanged_needsStrongAuth_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); setNeedsStrongAuth(true); setNeedsStrongAuth(true); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading @@ -394,13 +395,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController, atLeastOnce()).show(); verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading @@ -408,13 +409,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController, atLeastOnce()).show(); verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onStartingToHide(); mKeyguardSecurityContainerController.onStartingToHide(); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading @@ -422,13 +423,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController, atLeastOnce()).show(); verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onPause(); mKeyguardSecurityContainerController.onPause(); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading @@ -436,12 +437,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onResume(0); mKeyguardSecurityContainerController.onResume(0); verify(mSidefpsController).show(); verify(mSideFpsController).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).hide(); verify(mSideFpsController, never()).hide(any()); } } @Test @Test Loading @@ -450,12 +451,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); setSideFpsHintEnabledFromResources(false); setSideFpsHintEnabledFromResources(false); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onResume(0); mKeyguardSecurityContainerController.onResume(0); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading Loading
packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java +10 −9 Original line number Original line Diff line number Diff line Loading @@ -58,7 +58,8 @@ import com.android.keyguard.dagger.KeyguardBouncerScope; import com.android.settingslib.utils.ThreadUtils; import com.android.settingslib.utils.ThreadUtils; import com.android.systemui.Gefingerpoken; import com.android.systemui.Gefingerpoken; import com.android.systemui.R; import com.android.systemui.R; import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.biometrics.SideFpsController; import com.android.systemui.biometrics.SideFpsUiRequestSource; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags; Loading Loading @@ -100,7 +101,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final GlobalSettings mGlobalSettings; private final GlobalSettings mGlobalSettings; private final FeatureFlags mFeatureFlags; private final FeatureFlags mFeatureFlags; private final SessionTracker mSessionTracker; private final SessionTracker mSessionTracker; private final Optional<SidefpsController> mSidefpsController; private final Optional<SideFpsController> mSideFpsController; private final FalsingA11yDelegate mFalsingA11yDelegate; private final FalsingA11yDelegate mFalsingA11yDelegate; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; Loading Loading @@ -290,7 +291,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard FeatureFlags featureFlags, FeatureFlags featureFlags, GlobalSettings globalSettings, GlobalSettings globalSettings, SessionTracker sessionTracker, SessionTracker sessionTracker, Optional<SidefpsController> sidefpsController, Optional<SideFpsController> sideFpsController, FalsingA11yDelegate falsingA11yDelegate) { FalsingA11yDelegate falsingA11yDelegate) { super(view); super(view); mLockPatternUtils = lockPatternUtils; mLockPatternUtils = lockPatternUtils; Loading @@ -311,7 +312,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard mFeatureFlags = featureFlags; mFeatureFlags = featureFlags; mGlobalSettings = globalSettings; mGlobalSettings = globalSettings; mSessionTracker = sessionTracker; mSessionTracker = sessionTracker; mSidefpsController = sidefpsController; mSideFpsController = sideFpsController; mFalsingA11yDelegate = falsingA11yDelegate; mFalsingA11yDelegate = falsingA11yDelegate; } } Loading Loading @@ -351,7 +352,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard } } private void updateSideFpsVisibility() { private void updateSideFpsVisibility() { if (!mSidefpsController.isPresent()) { if (!mSideFpsController.isPresent()) { return; return; } } final boolean sfpsEnabled = getResources().getBoolean( final boolean sfpsEnabled = getResources().getBoolean( Loading @@ -369,9 +370,9 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard + "needsStrongAuth=" + needsStrongAuth); + "needsStrongAuth=" + needsStrongAuth); } } if (toShow) { if (toShow) { mSidefpsController.get().show(); mSideFpsController.get().show(SideFpsUiRequestSource.PRIMARY_BOUNCER); } else { } else { mSidefpsController.get().hide(); mSideFpsController.get().hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); } } } } Loading Loading @@ -745,7 +746,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard private final FeatureFlags mFeatureFlags; private final FeatureFlags mFeatureFlags; private final UserSwitcherController mUserSwitcherController; private final UserSwitcherController mUserSwitcherController; private final SessionTracker mSessionTracker; private final SessionTracker mSessionTracker; private final Optional<SidefpsController> mSidefpsController; private final Optional<SideFpsController> mSidefpsController; private final FalsingA11yDelegate mFalsingA11yDelegate; private final FalsingA11yDelegate mFalsingA11yDelegate; @Inject @Inject Loading @@ -766,7 +767,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard FeatureFlags featureFlags, FeatureFlags featureFlags, GlobalSettings globalSettings, GlobalSettings globalSettings, SessionTracker sessionTracker, SessionTracker sessionTracker, Optional<SidefpsController> sidefpsController, Optional<SideFpsController> sidefpsController, FalsingA11yDelegate falsingA11yDelegate) { FalsingA11yDelegate falsingA11yDelegate) { mView = view; mView = view; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; mAdminSecondaryLockScreenControllerFactory = adminSecondaryLockScreenControllerFactory; Loading
packages/SystemUI/src/com/android/keyguard/dagger/KeyguardBouncerModule.java +5 −5 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,7 @@ package com.android.keyguard.dagger; package com.android.keyguard.dagger; import static com.android.systemui.biometrics.SidefpsControllerKt.hasSideFpsSensor; import static com.android.systemui.biometrics.SideFpsControllerKt.hasSideFpsSensor; import android.annotation.Nullable; import android.annotation.Nullable; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager; Loading @@ -27,7 +27,7 @@ import com.android.keyguard.KeyguardHostView; import com.android.keyguard.KeyguardSecurityContainer; import com.android.keyguard.KeyguardSecurityContainer; import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.keyguard.KeyguardSecurityViewFlipper; import com.android.systemui.R; import com.android.systemui.R; import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.biometrics.SideFpsController; import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.dagger.qualifiers.RootView; import com.android.systemui.statusbar.phone.KeyguardBouncer; import com.android.systemui.statusbar.phone.KeyguardBouncer; Loading Loading @@ -70,12 +70,12 @@ public interface KeyguardBouncerModule { return containerView.findViewById(R.id.view_flipper); return containerView.findViewById(R.id.view_flipper); } } /** Provides {@link SidefpsController} if the device has the side fingerprint sensor. */ /** Provides {@link SideFpsController} if the device has the side fingerprint sensor. */ @Provides @Provides @KeyguardBouncerScope @KeyguardBouncerScope static Optional<SidefpsController> providesOptionalSidefpsController( static Optional<SideFpsController> providesOptionalSidefpsController( @Nullable FingerprintManager fingerprintManager, @Nullable FingerprintManager fingerprintManager, Provider<SidefpsController> sidefpsControllerProvider) { Provider<SideFpsController> sidefpsControllerProvider) { if (!hasSideFpsSensor(fingerprintManager)) { if (!hasSideFpsSensor(fingerprintManager)) { return Optional.empty(); return Optional.empty(); } } Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +5 −5 Original line number Original line Diff line number Diff line Loading @@ -119,7 +119,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FingerprintManager mFingerprintManager; @Nullable private final FaceManager mFaceManager; @Nullable private final FaceManager mFaceManager; private final Provider<UdfpsController> mUdfpsControllerFactory; private final Provider<UdfpsController> mUdfpsControllerFactory; private final Provider<SidefpsController> mSidefpsControllerFactory; private final Provider<SideFpsController> mSidefpsControllerFactory; private final Display mDisplay; private final Display mDisplay; private float mScaleFactor = 1f; private float mScaleFactor = 1f; Loading @@ -141,7 +141,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @NonNull private final DisplayManager mDisplayManager; @NonNull private final DisplayManager mDisplayManager; @Nullable private UdfpsController mUdfpsController; @Nullable private UdfpsController mUdfpsController; @Nullable private IUdfpsHbmListener mUdfpsHbmListener; @Nullable private IUdfpsHbmListener mUdfpsHbmListener; @Nullable private SidefpsController mSidefpsController; @Nullable private SideFpsController mSideFpsController; @Nullable private IBiometricContextListener mBiometricContextListener; @Nullable private IBiometricContextListener mBiometricContextListener; @VisibleForTesting IBiometricSysuiReceiver mReceiver; @VisibleForTesting IBiometricSysuiReceiver mReceiver; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener; Loading Loading @@ -316,7 +316,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; mSidefpsProps = !sidefpsProps.isEmpty() ? sidefpsProps : null; if (mSidefpsProps != null) { if (mSidefpsProps != null) { mSidefpsController = mSidefpsControllerFactory.get(); mSideFpsController = mSidefpsControllerFactory.get(); } } updateSensorLocations(); updateSensorLocations(); Loading Loading @@ -677,7 +677,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, @Nullable FingerprintManager fingerprintManager, @Nullable FingerprintManager fingerprintManager, @Nullable FaceManager faceManager, @Nullable FaceManager faceManager, Provider<UdfpsController> udfpsControllerFactory, Provider<UdfpsController> udfpsControllerFactory, Provider<SidefpsController> sidefpsControllerFactory, Provider<SideFpsController> sidefpsControllerFactory, @NonNull DisplayManager displayManager, @NonNull DisplayManager displayManager, @NonNull WakefulnessLifecycle wakefulnessLifecycle, @NonNull WakefulnessLifecycle wakefulnessLifecycle, @NonNull UserManager userManager, @NonNull UserManager userManager, Loading Loading @@ -1054,7 +1054,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks, * Whether the passed userId has enrolled SFPS. * Whether the passed userId has enrolled SFPS. */ */ public boolean isSfpsEnrolled(int userId) { public boolean isSfpsEnrolled(int userId) { if (mSidefpsController == null) { if (mSideFpsController == null) { return false; return false; } } Loading
packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt→packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt +164 −104 Original line number Original line Diff line number Diff line Loading @@ -51,20 +51,25 @@ import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieProperty import com.airbnb.lottie.LottieProperty import com.airbnb.lottie.model.KeyPath import com.airbnb.lottie.model.KeyPath import com.android.internal.annotations.VisibleForTesting import com.android.internal.annotations.VisibleForTesting import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager import com.android.systemui.recents.OverviewProxyService import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.DelayableExecutor import java.io.PrintWriter import javax.inject.Inject import javax.inject.Inject private const val TAG = "SidefpsController" private const val TAG = "SideFpsController" /** /** * Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events. * Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events. */ */ @SysUISingleton @SysUISingleton class SidefpsController @Inject constructor( class SideFpsController @Inject constructor( private val context: Context, private val context: Context, private val layoutInflater: LayoutInflater, private val layoutInflater: LayoutInflater, fingerprintManager: FingerprintManager?, fingerprintManager: FingerprintManager?, Loading @@ -73,15 +78,19 @@ class SidefpsController @Inject constructor( overviewProxyService: OverviewProxyService, overviewProxyService: OverviewProxyService, displayManager: DisplayManager, displayManager: DisplayManager, @Main private val mainExecutor: DelayableExecutor, @Main private val mainExecutor: DelayableExecutor, @Main private val handler: Handler @Main private val handler: Handler, ) { dumpManager: DumpManager ) : Dumpable { val requests: HashSet<SideFpsUiRequestSource> = HashSet() @VisibleForTesting @VisibleForTesting val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager val sensorProps: FingerprintSensorPropertiesInternal = ?.sideFpsSensorProperties fingerprintManager?.sideFpsSensorProperties ?: throw IllegalStateException("no side fingerprint sensor") ?: throw IllegalStateException("no side fingerprint sensor") @VisibleForTesting @VisibleForTesting val orientationListener = BiometricDisplayListener( val orientationListener = BiometricDisplayListener( context, context, displayManager, displayManager, handler, handler, Loading @@ -89,7 +98,8 @@ class SidefpsController @Inject constructor( ) { onOrientationChanged() } ) { onOrientationChanged() } @VisibleForTesting @VisibleForTesting val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener { val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener { override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { overlayView?.let { view -> overlayView?.let { view -> handler.postDelayed({ updateOverlayVisibility(view) }, 500) handler.postDelayed({ updateOverlayVisibility(view) }, 500) Loading Loading @@ -121,17 +131,20 @@ class SidefpsController @Inject constructor( @VisibleForTesting @VisibleForTesting internal var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT internal var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT private val overlayViewParams = WindowManager.LayoutParams( private val overlayViewParams = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, PixelFormat.TRANSLUCENT PixelFormat.TRANSLUCENT ).apply { ) .apply { title = TAG title = TAG fitInsetsTypes = 0 // overrides default, avoiding status bars during layout fitInsetsTypes = 0 // overrides default, avoiding status bars during layout gravity = Gravity.TOP or Gravity.LEFT gravity = Gravity.TOP or Gravity.LEFT layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION privateFlags = PRIVATE_FLAG_TRUSTED_OVERLAY or PRIVATE_FLAG_NO_MOVE_ANIMATION } } Loading @@ -141,15 +154,23 @@ class SidefpsController @Inject constructor( override fun show( override fun show( sensorId: Int, sensorId: Int, @BiometricOverlayConstants.ShowReason reason: Int @BiometricOverlayConstants.ShowReason reason: Int ) = if (reason.isReasonToShow(activityTaskManager)) show() else hide() ) = if (reason.isReasonToAutoShow(activityTaskManager)) { show(SideFpsUiRequestSource.AUTO_SHOW) } else { hide(SideFpsUiRequestSource.AUTO_SHOW) } override fun hide(sensorId: Int) = hide() override fun hide(sensorId: Int) = hide(SideFpsUiRequestSource.AUTO_SHOW) }) } ) overviewProxyService.addCallback(overviewProxyListener) overviewProxyService.addCallback(overviewProxyListener) dumpManager.registerDumpable(this) } } /** Shows the side fps overlay if not already shown. */ /** Shows the side fps overlay if not already shown. */ fun show() { fun show(request: SideFpsUiRequestSource) { requests.add(request) mainExecutor.execute { mainExecutor.execute { if (overlayView == null) { if (overlayView == null) { createOverlayForDisplay() createOverlayForDisplay() Loading @@ -160,8 +181,20 @@ class SidefpsController @Inject constructor( } } /** Hides the fps overlay if shown. */ /** Hides the fps overlay if shown. */ fun hide() { fun hide(request: SideFpsUiRequestSource) { mainExecutor.execute { overlayView = null } requests.remove(request) mainExecutor.execute { if (requests.isEmpty()) { overlayView = null } } } override fun dump(pw: PrintWriter, args: Array<out String>) { pw.println("requests:") for (requestSource in requests) { pw.println(" $requestSource.name") } } } private fun onOrientationChanged() { private fun onOrientationChanged() { Loading @@ -174,7 +207,8 @@ class SidefpsController @Inject constructor( val view = layoutInflater.inflate(R.layout.sidefps_view, null, false) val view = layoutInflater.inflate(R.layout.sidefps_view, null, false) overlayView = view overlayView = view val display = context.display!! val display = context.display!! val offsets = sensorProps.getLocation(display.uniqueId).let { location -> val offsets = sensorProps.getLocation(display.uniqueId).let { location -> if (location == null) { if (location == null) { Log.w(TAG, "No location specified for display: ${display.uniqueId}") Log.w(TAG, "No location specified for display: ${display.uniqueId}") } } Loading @@ -195,21 +229,25 @@ class SidefpsController @Inject constructor( /** /** * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from * Intercepts TYPE_WINDOW_STATE_CHANGED accessibility event, preventing Talkback from * speaking @string/accessibility_fingerprint_label twice when sensor location indicator * speaking @string/accessibility_fingerprint_label twice when sensor location indicator is * is in focus * in focus */ */ view.setAccessibilityDelegate(object : AccessibilityDelegate() { view.setAccessibilityDelegate( object : AccessibilityDelegate() { override fun dispatchPopulateAccessibilityEvent( override fun dispatchPopulateAccessibilityEvent( host: View, host: View, event: AccessibilityEvent event: AccessibilityEvent ): Boolean { ): Boolean { return if (event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { return if ( event.getEventType() === AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED ) { true true } else { } else { super.dispatchPopulateAccessibilityEvent(host, event) super.dispatchPopulateAccessibilityEvent(host, event) } } } } }) } ) } } @VisibleForTesting @VisibleForTesting Loading @@ -220,7 +258,8 @@ class SidefpsController @Inject constructor( val displayHeight = if (isNaturalOrientation) size.height() else size.width() val displayHeight = if (isNaturalOrientation) size.height() else size.width() val boundsWidth = if (isNaturalOrientation) bounds.width() else bounds.height() val boundsWidth = if (isNaturalOrientation) bounds.width() else bounds.height() val boundsHeight = if (isNaturalOrientation) bounds.height() else bounds.width() val boundsHeight = if (isNaturalOrientation) bounds.height() else bounds.width() val sensorBounds = if (overlayOffsets.isYAligned()) { val sensorBounds = if (overlayOffsets.isYAligned()) { Rect( Rect( displayWidth - boundsWidth, displayWidth - boundsWidth, overlayOffsets.sensorLocationY, overlayOffsets.sensorLocationY, Loading Loading @@ -254,19 +293,25 @@ class SidefpsController @Inject constructor( // hide after a few seconds if the sensor is oriented down and there are // hide after a few seconds if the sensor is oriented down and there are // large overlapping system bars // large overlapping system bars val rotation = context.display?.rotation val rotation = context.display?.rotation if (windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar() && if ( windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar() && ((rotation == Surface.ROTATION_270 && overlayOffsets.isYAligned()) || ((rotation == Surface.ROTATION_270 && overlayOffsets.isYAligned()) || (rotation == Surface.ROTATION_180 && !overlayOffsets.isYAligned()))) { (rotation == Surface.ROTATION_180 && !overlayOffsets.isYAligned())) overlayHideAnimator = view.animate() ) { overlayHideAnimator = view .animate() .alpha(0f) .alpha(0f) .setStartDelay(3_000) .setStartDelay(3_000) .setDuration(animationDuration) .setDuration(animationDuration) .setListener(object : AnimatorListenerAdapter() { .setListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { override fun onAnimationEnd(animation: Animator) { view.visibility = View.GONE view.visibility = View.GONE overlayHideAnimator = null overlayHideAnimator = null } } }) } ) } else { } else { overlayHideAnimator?.cancel() overlayHideAnimator?.cancel() overlayHideAnimator = null overlayHideAnimator = null Loading @@ -283,9 +328,11 @@ private val FingerprintManager?.sideFpsSensorProperties: FingerprintSensorProper fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null fun FingerprintManager?.hasSideFpsSensor(): Boolean = this?.sideFpsSensorProperties != null @BiometricOverlayConstants.ShowReason @BiometricOverlayConstants.ShowReason private fun Int.isReasonToShow(activityTaskManager: ActivityTaskManager): Boolean = when (this) { private fun Int.isReasonToAutoShow(activityTaskManager: ActivityTaskManager): Boolean = when (this) { REASON_AUTH_KEYGUARD -> false REASON_AUTH_KEYGUARD -> false REASON_AUTH_SETTINGS -> when (activityTaskManager.topClass()) { REASON_AUTH_SETTINGS -> when (activityTaskManager.topClass()) { // TODO(b/186176653): exclude fingerprint overlays from this list view // TODO(b/186176653): exclude fingerprint overlays from this list view "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false "com.android.settings.biometrics.fingerprint.FingerprintSettings" -> false else -> true else -> true Loading @@ -297,13 +344,15 @@ private fun ActivityTaskManager.topClass(): String = getTasks(1).firstOrNull()?.topActivity?.className ?: "" getTasks(1).firstOrNull()?.topActivity?.className ?: "" @RawRes @RawRes private fun Display.asSideFpsAnimation(yAligned: Boolean): Int = when (rotation) { private fun Display.asSideFpsAnimation(yAligned: Boolean): Int = when (rotation) { Surface.ROTATION_0 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape Surface.ROTATION_0 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape Surface.ROTATION_180 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape Surface.ROTATION_180 -> if (yAligned) R.raw.sfps_pulse else R.raw.sfps_pulse_landscape else -> if (yAligned) R.raw.sfps_pulse_landscape else R.raw.sfps_pulse else -> if (yAligned) R.raw.sfps_pulse_landscape else R.raw.sfps_pulse } } private fun Display.asSideFpsAnimationRotation(yAligned: Boolean): Float = when (rotation) { private fun Display.asSideFpsAnimationRotation(yAligned: Boolean): Float = when (rotation) { Surface.ROTATION_90 -> if (yAligned) 0f else 180f Surface.ROTATION_90 -> if (yAligned) 0f else 180f Surface.ROTATION_180 -> 180f Surface.ROTATION_180 -> 180f Surface.ROTATION_270 -> if (yAligned) 180f else 0f Surface.ROTATION_270 -> if (yAligned) 180f else 0f Loading @@ -322,10 +371,9 @@ private fun LottieAnimationView.addOverlayDynamicColor(context: Context) { fun update() { fun update() { val c = context.getColor(R.color.biometric_dialog_accent) val c = context.getColor(R.color.biometric_dialog_accent) for (key in listOf(".blue600", ".blue400")) { for (key in listOf(".blue600", ".blue400")) { addValueCallback( addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) { KeyPath(key, "**"), PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP) LottieProperty.COLOR_FILTER } ) { PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP) } } } } } Loading @@ -335,3 +383,15 @@ private fun LottieAnimationView.addOverlayDynamicColor(context: Context) { addLottieOnCompositionLoadedListener { update() } addLottieOnCompositionLoadedListener { update() } } } } } /** * The source of a request to show the side fps visual indicator. This is distinct from * [BiometricOverlayConstants] which corrresponds with the reason fingerprint authentication is * requested. */ enum class SideFpsUiRequestSource { /** see [isReasonToAutoShow] */ AUTO_SHOW, /** Pin, pattern or password bouncer */ PRIMARY_BOUNCER, }
packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java +34 −33 Original line number Original line Diff line number Diff line Loading @@ -54,7 +54,8 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.keyguard.KeyguardSecurityModel.SecurityMode; import com.android.systemui.R; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.SidefpsController; import com.android.systemui.biometrics.SideFpsController; import com.android.systemui.biometrics.SideFpsUiRequestSource; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingA11yDelegate; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.FeatureFlags; Loading Loading @@ -141,7 +142,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Mock @Mock private KeyguardViewController mKeyguardViewController; private KeyguardViewController mKeyguardViewController; @Mock @Mock private SidefpsController mSidefpsController; private SideFpsController mSideFpsController; @Mock @Mock private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock; private KeyguardPasswordViewController mKeyguardPasswordViewControllerMock; @Mock @Mock Loading Loading @@ -189,7 +190,7 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { mKeyguardStateController, mKeyguardSecurityViewFlipperController, mKeyguardStateController, mKeyguardSecurityViewFlipperController, mConfigurationController, mFalsingCollector, mFalsingManager, mConfigurationController, mFalsingCollector, mFalsingManager, mUserSwitcherController, mFeatureFlags, mGlobalSettings, mUserSwitcherController, mFeatureFlags, mGlobalSettings, mSessionTracker, Optional.of(mSidefpsController), mFalsingA11yDelegate).create( mSessionTracker, Optional.of(mSideFpsController), mFalsingA11yDelegate).create( mSecurityCallback); mSecurityCallback); } } Loading Loading @@ -345,48 +346,48 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { @Test @Test public void onBouncerVisibilityChanged_allConditionsGood_sideFpsHintShown() { public void onBouncerVisibilityChanged_allConditionsGood_sideFpsHintShown() { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController).show(); verify(mSideFpsController).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).hide(); verify(mSideFpsController, never()).hide(any()); } } @Test @Test public void onBouncerVisibilityChanged_fpsSensorNotRunning_sideFpsHintHidden() { public void onBouncerVisibilityChanged_fpsSensorNotRunning_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); setFingerprintDetectionRunning(false); setFingerprintDetectionRunning(false); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test public void onBouncerVisibilityChanged_withoutSidedSecurity_sideFpsHintHidden() { public void onBouncerVisibilityChanged_withoutSidedSecurity_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); setSideFpsHintEnabledFromResources(false); setSideFpsHintEnabledFromResources(false); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test public void onBouncerVisibilityChanged_needsStrongAuth_sideFpsHintHidden() { public void onBouncerVisibilityChanged_needsStrongAuth_sideFpsHintHidden() { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); setNeedsStrongAuth(true); setNeedsStrongAuth(true); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading @@ -394,13 +395,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController, atLeastOnce()).show(); verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.INVISIBLE); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading @@ -408,13 +409,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController, atLeastOnce()).show(); verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onStartingToHide(); mKeyguardSecurityContainerController.onStartingToHide(); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading @@ -422,13 +423,13 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); verify(mSidefpsController, atLeastOnce()).show(); verify(mSideFpsController, atLeastOnce()).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onPause(); mKeyguardSecurityContainerController.onPause(); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading @@ -436,12 +437,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupGetSecurityView(); setupGetSecurityView(); setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onResume(0); mKeyguardSecurityContainerController.onResume(0); verify(mSidefpsController).show(); verify(mSideFpsController).show(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).hide(); verify(mSideFpsController, never()).hide(any()); } } @Test @Test Loading @@ -450,12 +451,12 @@ public class KeyguardSecurityContainerControllerTest extends SysuiTestCase { setupConditionsToEnableSideFpsHint(); setupConditionsToEnableSideFpsHint(); setSideFpsHintEnabledFromResources(false); setSideFpsHintEnabledFromResources(false); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE); reset(mSidefpsController); reset(mSideFpsController); mKeyguardSecurityContainerController.onResume(0); mKeyguardSecurityContainerController.onResume(0); verify(mSidefpsController).hide(); verify(mSideFpsController).hide(SideFpsUiRequestSource.PRIMARY_BOUNCER); verify(mSidefpsController, never()).show(); verify(mSideFpsController, never()).show(any()); } } @Test @Test Loading