Loading packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt +59 −7 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.systemui.biometrics import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.content.Context import android.graphics.PixelFormat import android.graphics.PorterDuff Loading @@ -33,6 +35,8 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.Surface import android.view.View import android.view.ViewPropertyAnimator import android.view.WindowInsets import android.view.WindowManager import androidx.annotation.RawRes import com.airbnb.lottie.LottieAnimationView Loading @@ -42,6 +46,7 @@ import com.android.internal.annotations.VisibleForTesting import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.DelayableExecutor import javax.inject.Inject Loading @@ -56,9 +61,10 @@ class SidefpsController @Inject constructor( private val layoutInflater: LayoutInflater, fingerprintManager: FingerprintManager?, private val windowManager: WindowManager, @Main mainExecutor: DelayableExecutor, overviewProxyService: OverviewProxyService, displayManager: DisplayManager, @Main handler: Handler @Main mainExecutor: DelayableExecutor, @Main private val handler: Handler ) { @VisibleForTesting val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager Loading @@ -74,15 +80,33 @@ class SidefpsController @Inject constructor( BiometricDisplayListener.SensorType.SideFingerprint(sensorProps) ) { onOrientationChanged() } @VisibleForTesting val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener { override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { overlayView?.let { view -> handler.postDelayed({ updateOverlayVisibility(view) }, 500) } } } private val animationDuration = context.resources.getInteger(android.R.integer.config_mediumAnimTime).toLong() private var overlayHideAnimator: ViewPropertyAnimator? = null private var overlayView: View? = null set(value) { field?.let { oldView -> windowManager.removeView(oldView) orientationListener.disable() } overlayHideAnimator?.cancel() overlayHideAnimator = null field = value field?.let { newView -> windowManager.addView(newView, overlayViewParams) updateOverlayVisibility(newView) orientationListener.enable() } } Loading @@ -90,11 +114,8 @@ class SidefpsController @Inject constructor( private val overlayViewParams = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, PixelFormat.TRANSLUCENT ).apply { title = TAG Loading @@ -121,6 +142,7 @@ class SidefpsController @Inject constructor( override fun hide(sensorId: Int) = mainExecutor.execute { overlayView = null } }) overviewProxyService.addCallback(overviewProxyListener) } private fun onOrientationChanged() { Loading Loading @@ -176,6 +198,33 @@ class SidefpsController @Inject constructor( overlayViewParams.x = x overlayViewParams.y = y } private fun updateOverlayVisibility(view: View) { if (view != overlayView) { return } // hide after a few seconds if the sensor is oriented down and there are // large overlapping system bars if ((context.display?.rotation == Surface.ROTATION_270) && windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar()) { overlayHideAnimator = view.animate() .alpha(0f) .setStartDelay(3_000) .setDuration(animationDuration) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { view.visibility = View.GONE overlayHideAnimator = null } }) } else { overlayHideAnimator?.cancel() overlayHideAnimator = null view.alpha = 1f view.visibility = View.VISIBLE } } } @BiometricOverlayConstants.ShowReason Loading @@ -200,6 +249,9 @@ private fun Display.asSideFpsAnimationRotation(): Float = when (rotation) { private fun Display.isPortrait(): Boolean = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 private fun WindowInsets.hasBigNavigationBar(): Boolean = getInsets(WindowInsets.Type.navigationBars()).bottom >= 70 private fun LottieAnimationView.addOverlayDynamicColor(context: Context) { fun update() { val c = context.getColor(R.color.biometric_dialog_accent) Loading packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +2 −9 Original line number Diff line number Diff line Loading @@ -583,7 +583,7 @@ public class UdfpsController implements DozeReceiver { mCoreLayoutParams = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, getCoreLayoutParamFlags(), Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, PixelFormat.TRANSLUCENT); mCoreLayoutParams.setTitle(TAG); mCoreLayoutParams.setFitInsetsTypes(0); Loading Loading @@ -616,13 +616,6 @@ public class UdfpsController implements DozeReceiver { } } private int getCoreLayoutParamFlags() { return WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } @Nullable private FingerprintSensorPropertiesInternal findFirstUdfps() { for (FingerprintSensorPropertiesInternal props : Loading Loading @@ -685,7 +678,7 @@ public class UdfpsController implements DozeReceiver { final int paddingX = animation != null ? animation.getPaddingX() : 0; final int paddingY = animation != null ? animation.getPaddingY() : 0; mCoreLayoutParams.flags = getCoreLayoutParamFlags(); mCoreLayoutParams.flags = Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS; if (animation != null && animation.listenForTouchesOutsideView()) { mCoreLayoutParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; } Loading packages/SystemUI/src/com/android/systemui/biometrics/Utils.java +8 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.hardware.biometrics.SensorPropertiesInternal; import android.os.UserManager; import android.util.DisplayMetrics; import android.view.ViewGroup; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; Loading @@ -46,6 +47,13 @@ public class Utils { public static final int CREDENTIAL_PATTERN = 2; public static final int CREDENTIAL_PASSWORD = 3; /** Base set of layout flags for fingerprint overlay widgets. */ public static final int FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; @Retention(RetentionPolicy.SOURCE) @IntDef({CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD}) @interface CredentialType {} Loading @@ -55,11 +63,6 @@ public class Utils { / DisplayMetrics.DENSITY_DEFAULT); } static float pixelsToDp(Context context, float pixels) { return pixels / ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT); } static void notifyAccessibilityContentChanged(AccessibilityManager am, ViewGroup view) { if (!am.isEnabled()) { return; Loading packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt +105 −25 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.biometrics import android.animation.Animator import android.graphics.Insets import android.graphics.Rect import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN Loading @@ -33,7 +35,9 @@ import android.view.Display import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS import android.view.DisplayInfo import android.view.LayoutInflater import android.view.Surface import android.view.View import android.view.ViewPropertyAnimator import android.view.WindowInsets import android.view.WindowManager import android.view.WindowMetrics Loading @@ -41,6 +45,7 @@ import androidx.test.filters.SmallTest import com.airbnb.lottie.LottieAnimationView import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock import org.junit.Before Loading @@ -53,6 +58,8 @@ import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.anyFloat import org.mockito.Mockito.anyLong import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset Loading Loading @@ -81,6 +88,8 @@ class SidefpsControllerTest : SysuiTestCase() { @Mock lateinit var displayManager: DisplayManager @Mock lateinit var overviewProxyService: OverviewProxyService @Mock lateinit var handler: Handler @Captor lateinit var overlayCaptor: ArgumentCaptor<View> Loading @@ -91,9 +100,23 @@ class SidefpsControllerTest : SysuiTestCase() { @Before fun setup() { context.addMockSystemService(DisplayManager::class.java, displayManager) context.addMockSystemService(WindowManager::class.java, windowManager) `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView) `when`(sidefpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation))) .thenReturn(mock(LottieAnimationView::class.java)) with(mock(ViewPropertyAnimator::class.java)) { `when`(sidefpsView.animate()).thenReturn(this) `when`(alpha(anyFloat())).thenReturn(this) `when`(setStartDelay(anyLong())).thenReturn(this) `when`(setDuration(anyLong())).thenReturn(this) `when`(setListener(any())).thenAnswer { (it.arguments[0] as Animator.AnimatorListener) .onAnimationEnd(mock(Animator::class.java)) this } } `when`(fingerprintManager.sensorPropertiesInternal).thenReturn( listOf( FingerprintSensorPropertiesInternal( Loading @@ -106,30 +129,33 @@ class SidefpsControllerTest : SysuiTestCase() { ) ) ) `when`(windowManager.defaultDisplay).thenReturn( Display( DisplayManagerGlobal.getInstance(), DISPLAY_ID, DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS ) ) `when`(windowManager.maximumWindowMetrics).thenReturn( WindowMetrics(Rect(0, 0, 800, 800), WindowInsets.CONSUMED) ) } private fun testWithDisplay(initInfo: DisplayInfo.() -> Unit = {}, block: () -> Unit) { val displayInfo = DisplayInfo() displayInfo.initInfo() val dmGlobal = mock(DisplayManagerGlobal::class.java) val display = Display(dmGlobal, DISPLAY_ID, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS) `when`(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo) `when`(windowManager.defaultDisplay).thenReturn(display) sideFpsController = SidefpsController( mContext, layoutInflater, fingerprintManager, windowManager, executor, displayManager, handler context.createDisplayContext(display), layoutInflater, fingerprintManager, windowManager, overviewProxyService, displayManager, executor, handler ) overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply { verify(fingerprintManager).setSidefpsController(capture()) }.value block() } @Test fun testSubscribesToOrientationChangesWhenShowingOverlay() { fun testSubscribesToOrientationChangesWhenShowingOverlay() = testWithDisplay { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() Loading @@ -141,7 +167,7 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test fun testShowsAndHides() { fun testShowsAndHides() = testWithDisplay { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() Loading @@ -156,7 +182,7 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test fun testShowsOnce() { fun testShowsOnce() = testWithDisplay { repeat(5) { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() Loading @@ -167,7 +193,7 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test fun testHidesOnce() { fun testHidesOnce() = testWithDisplay { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() Loading @@ -181,10 +207,64 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test fun testIgnoredForKeyguard() { overlayController.show(SENSOR_ID, REASON_AUTH_KEYGUARD) fun testIgnoredForKeyguard() = testWithDisplay { testIgnoredFor(REASON_AUTH_KEYGUARD) } private fun testIgnoredFor(reason: Int) { overlayController.show(SENSOR_ID, reason) executor.runAllReady() verify(windowManager, never()).addView(any(), any()) } @Test fun showsWithTaskbar() = testWithDisplay({ rotation = Surface.ROTATION_0 }) { hidesWithTaskbar(visible = true) } @Test fun showsWithTaskbar90() = testWithDisplay({ rotation = Surface.ROTATION_90 }) { hidesWithTaskbar(visible = true) } @Test fun showsWithTaskbar180() = testWithDisplay({ rotation = Surface.ROTATION_180 }) { hidesWithTaskbar(visible = true) } @Test fun showsWithTaskbarCollapsedDown() = testWithDisplay({ rotation = Surface.ROTATION_270 }) { `when`(windowManager.currentWindowMetrics).thenReturn( WindowMetrics(Rect(0, 0, 800, 800), insetsForSmallNavbar()) ) hidesWithTaskbar(visible = true) } @Test fun hidesWithTaskbarDown() = testWithDisplay({ rotation = Surface.ROTATION_270 }) { `when`(windowManager.currentWindowMetrics).thenReturn( WindowMetrics(Rect(0, 0, 800, 800), insetsForLargeNavbar()) ) hidesWithTaskbar(visible = false) } private fun hidesWithTaskbar(visible: Boolean) { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() sideFpsController.overviewProxyListener.onTaskbarStatusUpdated(true, false) executor.runAllReady() verify(windowManager).addView(any(), any()) verify(windowManager, never()).removeView(any()) verify(sidefpsView).visibility = if (visible) View.VISIBLE else View.GONE } } private fun insetsForSmallNavbar() = insetsWithBottom(60) private fun insetsForLargeNavbar() = insetsWithBottom(100) private fun insetsWithBottom(bottom: Int) = WindowInsets.Builder() .setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, bottom)) .build() No newline at end of file Loading
packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.kt +59 −7 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.systemui.biometrics import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.content.Context import android.graphics.PixelFormat import android.graphics.PorterDuff Loading @@ -33,6 +35,8 @@ import android.view.Gravity import android.view.LayoutInflater import android.view.Surface import android.view.View import android.view.ViewPropertyAnimator import android.view.WindowInsets import android.view.WindowManager import androidx.annotation.RawRes import com.airbnb.lottie.LottieAnimationView Loading @@ -42,6 +46,7 @@ import com.android.internal.annotations.VisibleForTesting import com.android.systemui.R import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.DelayableExecutor import javax.inject.Inject Loading @@ -56,9 +61,10 @@ class SidefpsController @Inject constructor( private val layoutInflater: LayoutInflater, fingerprintManager: FingerprintManager?, private val windowManager: WindowManager, @Main mainExecutor: DelayableExecutor, overviewProxyService: OverviewProxyService, displayManager: DisplayManager, @Main handler: Handler @Main mainExecutor: DelayableExecutor, @Main private val handler: Handler ) { @VisibleForTesting val sensorProps: FingerprintSensorPropertiesInternal = fingerprintManager Loading @@ -74,15 +80,33 @@ class SidefpsController @Inject constructor( BiometricDisplayListener.SensorType.SideFingerprint(sensorProps) ) { onOrientationChanged() } @VisibleForTesting val overviewProxyListener = object : OverviewProxyService.OverviewProxyListener { override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) { overlayView?.let { view -> handler.postDelayed({ updateOverlayVisibility(view) }, 500) } } } private val animationDuration = context.resources.getInteger(android.R.integer.config_mediumAnimTime).toLong() private var overlayHideAnimator: ViewPropertyAnimator? = null private var overlayView: View? = null set(value) { field?.let { oldView -> windowManager.removeView(oldView) orientationListener.disable() } overlayHideAnimator?.cancel() overlayHideAnimator = null field = value field?.let { newView -> windowManager.addView(newView, overlayViewParams) updateOverlayVisibility(newView) orientationListener.enable() } } Loading @@ -90,11 +114,8 @@ class SidefpsController @Inject constructor( private val overlayViewParams = WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, PixelFormat.TRANSLUCENT ).apply { title = TAG Loading @@ -121,6 +142,7 @@ class SidefpsController @Inject constructor( override fun hide(sensorId: Int) = mainExecutor.execute { overlayView = null } }) overviewProxyService.addCallback(overviewProxyListener) } private fun onOrientationChanged() { Loading Loading @@ -176,6 +198,33 @@ class SidefpsController @Inject constructor( overlayViewParams.x = x overlayViewParams.y = y } private fun updateOverlayVisibility(view: View) { if (view != overlayView) { return } // hide after a few seconds if the sensor is oriented down and there are // large overlapping system bars if ((context.display?.rotation == Surface.ROTATION_270) && windowManager.currentWindowMetrics.windowInsets.hasBigNavigationBar()) { overlayHideAnimator = view.animate() .alpha(0f) .setStartDelay(3_000) .setDuration(animationDuration) .setListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { view.visibility = View.GONE overlayHideAnimator = null } }) } else { overlayHideAnimator?.cancel() overlayHideAnimator = null view.alpha = 1f view.visibility = View.VISIBLE } } } @BiometricOverlayConstants.ShowReason Loading @@ -200,6 +249,9 @@ private fun Display.asSideFpsAnimationRotation(): Float = when (rotation) { private fun Display.isPortrait(): Boolean = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180 private fun WindowInsets.hasBigNavigationBar(): Boolean = getInsets(WindowInsets.Type.navigationBars()).bottom >= 70 private fun LottieAnimationView.addOverlayDynamicColor(context: Context) { fun update() { val c = context.getColor(R.color.biometric_dialog_accent) Loading
packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +2 −9 Original line number Diff line number Diff line Loading @@ -583,7 +583,7 @@ public class UdfpsController implements DozeReceiver { mCoreLayoutParams = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, getCoreLayoutParamFlags(), Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, PixelFormat.TRANSLUCENT); mCoreLayoutParams.setTitle(TAG); mCoreLayoutParams.setFitInsetsTypes(0); Loading Loading @@ -616,13 +616,6 @@ public class UdfpsController implements DozeReceiver { } } private int getCoreLayoutParamFlags() { return WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; } @Nullable private FingerprintSensorPropertiesInternal findFirstUdfps() { for (FingerprintSensorPropertiesInternal props : Loading Loading @@ -685,7 +678,7 @@ public class UdfpsController implements DozeReceiver { final int paddingX = animation != null ? animation.getPaddingX() : 0; final int paddingY = animation != null ? animation.getPaddingY() : 0; mCoreLayoutParams.flags = getCoreLayoutParamFlags(); mCoreLayoutParams.flags = Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS; if (animation != null && animation.listenForTouchesOutsideView()) { mCoreLayoutParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; } Loading
packages/SystemUI/src/com/android/systemui/biometrics/Utils.java +8 −5 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.hardware.biometrics.SensorPropertiesInternal; import android.os.UserManager; import android.util.DisplayMetrics; import android.view.ViewGroup; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; Loading @@ -46,6 +47,13 @@ public class Utils { public static final int CREDENTIAL_PATTERN = 2; public static final int CREDENTIAL_PASSWORD = 3; /** Base set of layout flags for fingerprint overlay widgets. */ public static final int FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; @Retention(RetentionPolicy.SOURCE) @IntDef({CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD}) @interface CredentialType {} Loading @@ -55,11 +63,6 @@ public class Utils { / DisplayMetrics.DENSITY_DEFAULT); } static float pixelsToDp(Context context, float pixels) { return pixels / ((float) context.getResources().getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT); } static void notifyAccessibilityContentChanged(AccessibilityManager am, ViewGroup view) { if (!am.isEnabled()) { return; Loading
packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt +105 −25 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.systemui.biometrics import android.animation.Animator import android.graphics.Insets import android.graphics.Rect import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN Loading @@ -33,7 +35,9 @@ import android.view.Display import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS import android.view.DisplayInfo import android.view.LayoutInflater import android.view.Surface import android.view.View import android.view.ViewPropertyAnimator import android.view.WindowInsets import android.view.WindowManager import android.view.WindowMetrics Loading @@ -41,6 +45,7 @@ import androidx.test.filters.SmallTest import com.airbnb.lottie.LottieAnimationView import com.android.systemui.R import com.android.systemui.SysuiTestCase import com.android.systemui.recents.OverviewProxyService import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.time.FakeSystemClock import org.junit.Before Loading @@ -53,6 +58,8 @@ import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.anyFloat import org.mockito.Mockito.anyLong import org.mockito.Mockito.mock import org.mockito.Mockito.never import org.mockito.Mockito.reset Loading Loading @@ -81,6 +88,8 @@ class SidefpsControllerTest : SysuiTestCase() { @Mock lateinit var displayManager: DisplayManager @Mock lateinit var overviewProxyService: OverviewProxyService @Mock lateinit var handler: Handler @Captor lateinit var overlayCaptor: ArgumentCaptor<View> Loading @@ -91,9 +100,23 @@ class SidefpsControllerTest : SysuiTestCase() { @Before fun setup() { context.addMockSystemService(DisplayManager::class.java, displayManager) context.addMockSystemService(WindowManager::class.java, windowManager) `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView) `when`(sidefpsView.findViewById<LottieAnimationView>(eq(R.id.sidefps_animation))) .thenReturn(mock(LottieAnimationView::class.java)) with(mock(ViewPropertyAnimator::class.java)) { `when`(sidefpsView.animate()).thenReturn(this) `when`(alpha(anyFloat())).thenReturn(this) `when`(setStartDelay(anyLong())).thenReturn(this) `when`(setDuration(anyLong())).thenReturn(this) `when`(setListener(any())).thenAnswer { (it.arguments[0] as Animator.AnimatorListener) .onAnimationEnd(mock(Animator::class.java)) this } } `when`(fingerprintManager.sensorPropertiesInternal).thenReturn( listOf( FingerprintSensorPropertiesInternal( Loading @@ -106,30 +129,33 @@ class SidefpsControllerTest : SysuiTestCase() { ) ) ) `when`(windowManager.defaultDisplay).thenReturn( Display( DisplayManagerGlobal.getInstance(), DISPLAY_ID, DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS ) ) `when`(windowManager.maximumWindowMetrics).thenReturn( WindowMetrics(Rect(0, 0, 800, 800), WindowInsets.CONSUMED) ) } private fun testWithDisplay(initInfo: DisplayInfo.() -> Unit = {}, block: () -> Unit) { val displayInfo = DisplayInfo() displayInfo.initInfo() val dmGlobal = mock(DisplayManagerGlobal::class.java) val display = Display(dmGlobal, DISPLAY_ID, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS) `when`(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo) `when`(windowManager.defaultDisplay).thenReturn(display) sideFpsController = SidefpsController( mContext, layoutInflater, fingerprintManager, windowManager, executor, displayManager, handler context.createDisplayContext(display), layoutInflater, fingerprintManager, windowManager, overviewProxyService, displayManager, executor, handler ) overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply { verify(fingerprintManager).setSidefpsController(capture()) }.value block() } @Test fun testSubscribesToOrientationChangesWhenShowingOverlay() { fun testSubscribesToOrientationChangesWhenShowingOverlay() = testWithDisplay { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() Loading @@ -141,7 +167,7 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test fun testShowsAndHides() { fun testShowsAndHides() = testWithDisplay { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() Loading @@ -156,7 +182,7 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test fun testShowsOnce() { fun testShowsOnce() = testWithDisplay { repeat(5) { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() Loading @@ -167,7 +193,7 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test fun testHidesOnce() { fun testHidesOnce() = testWithDisplay { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() Loading @@ -181,10 +207,64 @@ class SidefpsControllerTest : SysuiTestCase() { } @Test fun testIgnoredForKeyguard() { overlayController.show(SENSOR_ID, REASON_AUTH_KEYGUARD) fun testIgnoredForKeyguard() = testWithDisplay { testIgnoredFor(REASON_AUTH_KEYGUARD) } private fun testIgnoredFor(reason: Int) { overlayController.show(SENSOR_ID, reason) executor.runAllReady() verify(windowManager, never()).addView(any(), any()) } @Test fun showsWithTaskbar() = testWithDisplay({ rotation = Surface.ROTATION_0 }) { hidesWithTaskbar(visible = true) } @Test fun showsWithTaskbar90() = testWithDisplay({ rotation = Surface.ROTATION_90 }) { hidesWithTaskbar(visible = true) } @Test fun showsWithTaskbar180() = testWithDisplay({ rotation = Surface.ROTATION_180 }) { hidesWithTaskbar(visible = true) } @Test fun showsWithTaskbarCollapsedDown() = testWithDisplay({ rotation = Surface.ROTATION_270 }) { `when`(windowManager.currentWindowMetrics).thenReturn( WindowMetrics(Rect(0, 0, 800, 800), insetsForSmallNavbar()) ) hidesWithTaskbar(visible = true) } @Test fun hidesWithTaskbarDown() = testWithDisplay({ rotation = Surface.ROTATION_270 }) { `when`(windowManager.currentWindowMetrics).thenReturn( WindowMetrics(Rect(0, 0, 800, 800), insetsForLargeNavbar()) ) hidesWithTaskbar(visible = false) } private fun hidesWithTaskbar(visible: Boolean) { overlayController.show(SENSOR_ID, REASON_UNKNOWN) executor.runAllReady() sideFpsController.overviewProxyListener.onTaskbarStatusUpdated(true, false) executor.runAllReady() verify(windowManager).addView(any(), any()) verify(windowManager, never()).removeView(any()) verify(sidefpsView).visibility = if (visible) View.VISIBLE else View.GONE } } private fun insetsForSmallNavbar() = insetsWithBottom(60) private fun insetsForLargeNavbar() = insetsWithBottom(100) private fun insetsWithBottom(bottom: Int) = WindowInsets.Builder() .setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, bottom)) .build() No newline at end of file