Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13ad3a2c authored by Grace Cheng's avatar Grace Cheng Committed by Android (Google) Code Review
Browse files

Merge "Fix location of side-fps indicator" into tm-dev

parents 5cc20aa2 2bd253a0
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.CoreStartable;
import com.android.systemui.assist.ui.DisplayUtils;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
@@ -600,8 +599,14 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
        mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
    }

    private int getDisplayWidth() {
        DisplayInfo displayInfo = new DisplayInfo();
        mContext.getDisplay().getDisplayInfo(displayInfo);
        return displayInfo.getNaturalWidth();
    }

    private void updateFingerprintLocation() {
        int xLocation = DisplayUtils.getWidth(mContext) / 2;
        int xLocation = getDisplayWidth() / 2;
        try {
            xLocation = mContext.getResources().getDimensionPixelSize(
                    com.android.systemui.R.dimen
+40 −48
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
import android.hardware.fingerprint.ISidefpsController
import android.os.Handler
import android.util.Log
import android.util.RotationUtils
import android.view.View.AccessibilityDelegate
import android.view.accessibility.AccessibilityEvent
import android.view.Display
@@ -116,7 +117,8 @@ class SidefpsController @Inject constructor(
                orientationListener.enable()
            }
        }
    private var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT
    @VisibleForTesting
    internal var overlayOffsets: SensorLocationInternal = SensorLocationInternal.DEFAULT

    private val overlayViewParams = WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
@@ -141,7 +143,7 @@ class SidefpsController @Inject constructor(

            private fun doShow() = mainExecutor.execute {
                if (overlayView == null) {
                    overlayView = createOverlayForDisplay()
                    createOverlayForDisplay()
                } else {
                    Log.v(TAG, "overlay already shown")
                }
@@ -154,14 +156,14 @@ class SidefpsController @Inject constructor(

    private fun onOrientationChanged() {
        if (overlayView != null) {
            overlayView = createOverlayForDisplay()
            createOverlayForDisplay()
        }
    }

    private fun createOverlayForDisplay(): View {
    private fun createOverlayForDisplay() {
        val view = layoutInflater.inflate(R.layout.sidefps_view, null, false)
        overlayView = view
        val display = context.display!!

        val offsets = sensorProps.getLocation(display.uniqueId).let { location ->
            if (location == null) {
                Log.w(TAG, "No location specified for display: ${display.uniqueId}")
@@ -172,13 +174,11 @@ class SidefpsController @Inject constructor(

        val lottie = view.findViewById(R.id.sidefps_animation) as LottieAnimationView
        view.rotation = display.asSideFpsAnimationRotation(offsets.isYAligned())

        updateOverlayParams(display, lottie.composition?.bounds ?: Rect())
        lottie.setAnimation(display.asSideFpsAnimation(offsets.isYAligned()))
        lottie.addLottieOnCompositionLoadedListener {
            if (overlayView == view) {
            // Check that view is not stale, and that overlayView has not been hidden/removed
            if (overlayView != null && overlayView == view) {
                updateOverlayParams(display, it.bounds)
                windowManager.updateViewLayout(overlayView, overlayViewParams)
            }
        }
        lottie.addOverlayDynamicColor(context)
@@ -200,55 +200,47 @@ class SidefpsController @Inject constructor(
                }
            }
        })
        return view
    }

    private fun updateOverlayParams(display: Display, bounds: Rect) {
        val isPortrait = display.isPortrait()
    @VisibleForTesting
    internal fun updateOverlayParams(display: Display, bounds: Rect) {
        val isNaturalOrientation = display.isNaturalOrientation()
        val size = windowManager.maximumWindowMetrics.bounds
        val displayWidth = if (isPortrait) size.width() else size.height()
        val displayHeight = if (isPortrait) size.height() else size.width()

        // ignore sensorRadius since it's assumed that the sensor is on the side and centered at
        // either sensorLocationX or sensorLocationY (both should not be set)
        val (x, y) = if (overlayOffsets.isYAligned()) {
            when (display.rotation) {
                Surface.ROTATION_90 ->
                    Pair(overlayOffsets.sensorLocationY, 0)
                Surface.ROTATION_270 ->
                    Pair(
                        displayHeight - overlayOffsets.sensorLocationY - bounds.width(),
                        displayWidth + bounds.height()
        val displayWidth = if (isNaturalOrientation) size.width() else size.height()
        val displayHeight = if (isNaturalOrientation) size.height() else size.width()
        val boundsWidth = if (isNaturalOrientation) bounds.width() else bounds.height()
        val boundsHeight = if (isNaturalOrientation) bounds.height() else bounds.width()
        val sensorBounds = if (overlayOffsets.isYAligned()) {
            Rect(
                displayWidth - boundsWidth,
                overlayOffsets.sensorLocationY,
                displayWidth,
                overlayOffsets.sensorLocationY + boundsHeight
            )
                Surface.ROTATION_180 ->
                    Pair(0, displayHeight - overlayOffsets.sensorLocationY - bounds.height())
                else ->
                    Pair(displayWidth, overlayOffsets.sensorLocationY)
            }
        } else {
            when (display.rotation) {
                Surface.ROTATION_90 ->
                    Pair(0, displayWidth - overlayOffsets.sensorLocationX - bounds.height())
                Surface.ROTATION_270 ->
                    Pair(displayWidth, overlayOffsets.sensorLocationX - bounds.height())
                Surface.ROTATION_180 ->
                    Pair(
                        displayWidth - overlayOffsets.sensorLocationX - bounds.width(),
                        displayHeight
            Rect(
                overlayOffsets.sensorLocationX,
                0,
                overlayOffsets.sensorLocationX + boundsWidth,
                boundsHeight
            )
                else ->
                    Pair(overlayOffsets.sensorLocationX, 0)
        }
        }
        overlayViewParams.x = x
        overlayViewParams.y = y

        RotationUtils.rotateBounds(
            sensorBounds,
            Rect(0, 0, displayWidth, displayHeight),
            display.rotation
        )

        overlayViewParams.x = sensorBounds.left
        overlayViewParams.y = sensorBounds.top
        windowManager.updateViewLayout(overlayView, overlayViewParams)
    }

    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
        val rotation = context.display?.rotation
@@ -304,7 +296,7 @@ private fun Display.asSideFpsAnimationRotation(yAligned: Boolean): Float = when

private fun SensorLocationInternal.isYAligned(): Boolean = sensorLocationY != 0

private fun Display.isPortrait(): Boolean =
private fun Display.isNaturalOrientation(): Boolean =
    rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180

private fun WindowInsets.hasBigNavigationBar(): Boolean =
+91 −33
Original line number Diff line number Diff line
@@ -77,12 +77,6 @@ import org.mockito.junit.MockitoJUnit
private const val DISPLAY_ID = 2
private const val SENSOR_ID = 1

private const val DISPLAY_SIZE_X = 800
private const val DISPLAY_SIZE_Y = 900

private val X_LOCATION = SensorLocationInternal("", 540, 0, 20)
private val Y_LOCATION = SensorLocationInternal("", 0, 1500, 22)

@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
@@ -116,6 +110,17 @@ class SidefpsControllerTest : SysuiTestCase() {
    private lateinit var overlayController: ISidefpsController
    private lateinit var sideFpsController: SidefpsController

    enum class DeviceConfig { X_ALIGNED, Y_ALIGNED_UNFOLDED, Y_ALIGNED_FOLDED }

    private lateinit var deviceConfig: DeviceConfig
    private lateinit var indicatorBounds: Rect
    private lateinit var displayBounds: Rect
    private lateinit var sensorLocation: SensorLocationInternal
    private var displayWidth: Int = 0
    private var displayHeight: Int = 0
    private var boundsWidth: Int = 0
    private var boundsHeight: Int = 0

    @Before
    fun setup() {
        context.addMockSystemService(DisplayManager::class.java, displayManager)
@@ -135,17 +140,43 @@ class SidefpsControllerTest : SysuiTestCase() {
                this
            }
        }
        `when`(windowManager.maximumWindowMetrics).thenReturn(
            WindowMetrics(Rect(0, 0, DISPLAY_SIZE_X, DISPLAY_SIZE_Y), WindowInsets.CONSUMED)
        )
    }

    private fun testWithDisplay(
        deviceConfig: DeviceConfig = DeviceConfig.X_ALIGNED,
        initInfo: DisplayInfo.() -> Unit = {},
        locations: List<SensorLocationInternal> = listOf(X_LOCATION),
        windowInsets: WindowInsets = insetsForSmallNavbar(),
        block: () -> Unit
    ) {
        this.deviceConfig = deviceConfig

        when (deviceConfig) {
            DeviceConfig.X_ALIGNED -> {
                displayWidth = 2560
                displayHeight = 1600
                sensorLocation = SensorLocationInternal("", 2325, 0, 0)
                boundsWidth = 160
                boundsHeight = 84
            }
            DeviceConfig.Y_ALIGNED_UNFOLDED -> {
                displayWidth = 2208
                displayHeight = 1840
                sensorLocation = SensorLocationInternal("", 0, 510, 0)
                boundsWidth = 110
                boundsHeight = 210
            }
            DeviceConfig.Y_ALIGNED_FOLDED -> {
                displayWidth = 1080
                displayHeight = 2100
                sensorLocation = SensorLocationInternal("", 0, 590, 0)
                boundsWidth = 110
                boundsHeight = 210
            }
        }
        indicatorBounds = Rect(0, 0, boundsWidth, boundsHeight)
        displayBounds = Rect(0, 0, displayWidth, displayHeight)
        var locations = listOf(sensorLocation)

        `when`(fingerprintManager.sensorPropertiesInternal).thenReturn(
            listOf(
                FingerprintSensorPropertiesInternal(
@@ -166,8 +197,11 @@ class SidefpsControllerTest : SysuiTestCase() {
        val display = Display(dmGlobal, DISPLAY_ID, displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS)
        `when`(dmGlobal.getDisplayInfo(eq(DISPLAY_ID))).thenReturn(displayInfo)
        `when`(windowManager.defaultDisplay).thenReturn(display)
        `when`(windowManager.maximumWindowMetrics).thenReturn(
                WindowMetrics(displayBounds, WindowInsets.CONSUMED)
        )
        `when`(windowManager.currentWindowMetrics).thenReturn(
            WindowMetrics(Rect(0, 0, DISPLAY_SIZE_X, DISPLAY_SIZE_Y), windowInsets)
            WindowMetrics(displayBounds, windowInsets)
        )

        sideFpsController = SidefpsController(
@@ -260,46 +294,56 @@ class SidefpsControllerTest : SysuiTestCase() {
    }

    @Test
    fun showsWithTaskbar() = testWithDisplay({ rotation = Surface.ROTATION_0 }) {
    fun showsWithTaskbar() = testWithDisplay(
        deviceConfig = DeviceConfig.X_ALIGNED,
        { rotation = Surface.ROTATION_0 }
    ) {
        hidesWithTaskbar(visible = true)
    }

    @Test
    fun showsWithTaskbarOnY() = testWithDisplay(
        { rotation = Surface.ROTATION_0 },
        locations = listOf(Y_LOCATION)
        deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
        { rotation = Surface.ROTATION_0 }
    ) {
        hidesWithTaskbar(visible = true)
    }

    @Test
    fun showsWithTaskbar90() = testWithDisplay({ rotation = Surface.ROTATION_90 }) {
    fun showsWithTaskbar90() = testWithDisplay(
        deviceConfig = DeviceConfig.X_ALIGNED,
        { rotation = Surface.ROTATION_90 }
    ) {
        hidesWithTaskbar(visible = true)
    }

    @Test
    fun showsWithTaskbar90OnY() = testWithDisplay(
        { rotation = Surface.ROTATION_90 },
        locations = listOf(Y_LOCATION)
        deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
        { rotation = Surface.ROTATION_90 }
    ) {
        hidesWithTaskbar(visible = true)
    }

    @Test
    fun showsWithTaskbar180() = testWithDisplay({ rotation = Surface.ROTATION_180 }) {
    fun showsWithTaskbar180() = testWithDisplay(
        deviceConfig = DeviceConfig.X_ALIGNED,
        { rotation = Surface.ROTATION_180 }
    ) {
        hidesWithTaskbar(visible = true)
    }

    @Test
    fun showsWithTaskbar270OnY() = testWithDisplay(
        { rotation = Surface.ROTATION_270 },
        locations = listOf(Y_LOCATION)
        deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
        { rotation = Surface.ROTATION_270 }
    ) {
        hidesWithTaskbar(visible = true)
    }

    @Test
    fun showsWithTaskbarCollapsedDown() = testWithDisplay(
        deviceConfig = DeviceConfig.X_ALIGNED,
        { rotation = Surface.ROTATION_270 },
        windowInsets = insetsForSmallNavbar()
    ) {
@@ -308,8 +352,8 @@ class SidefpsControllerTest : SysuiTestCase() {

    @Test
    fun showsWithTaskbarCollapsedDownOnY() = testWithDisplay(
        deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
        { rotation = Surface.ROTATION_180 },
        locations = listOf(Y_LOCATION),
        windowInsets = insetsForSmallNavbar()
    ) {
        hidesWithTaskbar(visible = true)
@@ -317,8 +361,8 @@ class SidefpsControllerTest : SysuiTestCase() {

    @Test
    fun hidesWithTaskbarDown() = testWithDisplay(
        deviceConfig = DeviceConfig.X_ALIGNED,
        { rotation = Surface.ROTATION_180 },
        locations = listOf(X_LOCATION),
        windowInsets = insetsForLargeNavbar()
    ) {
        hidesWithTaskbar(visible = false)
@@ -326,18 +370,18 @@ class SidefpsControllerTest : SysuiTestCase() {

    @Test
    fun hidesWithTaskbarDownOnY() = testWithDisplay(
        deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED,
        { rotation = Surface.ROTATION_270 },
        locations = listOf(Y_LOCATION),
        windowInsets = insetsForLargeNavbar()
    ) {
        hidesWithTaskbar(visible = false)
        hidesWithTaskbar(visible = true)
    }

    private fun hidesWithTaskbar(visible: Boolean) {
        overlayController.show(SENSOR_ID, REASON_UNKNOWN)
        executor.runAllReady()

        sideFpsController.overviewProxyListener.onTaskbarStatusUpdated(true, false)
        sideFpsController.overviewProxyListener.onTaskbarStatusUpdated(visible, false)
        executor.runAllReady()

        verify(windowManager).addView(any(), any())
@@ -346,25 +390,38 @@ class SidefpsControllerTest : SysuiTestCase() {
    }

    @Test
    fun setsXAlign() = testWithDisplay {
    fun testIndicatorPlacementForXAlignedSensor() = testWithDisplay(
        deviceConfig = DeviceConfig.X_ALIGNED
    ) {
        overlayController.show(SENSOR_ID, REASON_UNKNOWN)
        sideFpsController.overlayOffsets = sensorLocation
        sideFpsController.updateOverlayParams(
            windowManager.defaultDisplay,
            indicatorBounds
        )
        executor.runAllReady()

        verify(windowManager).addView(any(), overlayViewParamsCaptor.capture())
        verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())

        assertThat(overlayViewParamsCaptor.value.x).isEqualTo(X_LOCATION.sensorLocationX)
        assertThat(overlayViewParamsCaptor.value.x).isEqualTo(sensorLocation.sensorLocationX)
        assertThat(overlayViewParamsCaptor.value.y).isEqualTo(0)
    }

    @Test
    fun setYAlign() = testWithDisplay(locations = listOf(Y_LOCATION)) {
    fun testIndicatorPlacementForYAlignedSensor() = testWithDisplay(
        deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED
    ) {
        sideFpsController.overlayOffsets = sensorLocation
        sideFpsController.updateOverlayParams(
            windowManager.defaultDisplay,
            indicatorBounds
        )
        overlayController.show(SENSOR_ID, REASON_UNKNOWN)
        executor.runAllReady()

        verify(windowManager).addView(any(), overlayViewParamsCaptor.capture())

        assertThat(overlayViewParamsCaptor.value.x).isEqualTo(DISPLAY_SIZE_X)
        assertThat(overlayViewParamsCaptor.value.y).isEqualTo(Y_LOCATION.sensorLocationY)
        verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
        assertThat(overlayViewParamsCaptor.value.x).isEqualTo(displayWidth - boundsWidth)
        assertThat(overlayViewParamsCaptor.value.y).isEqualTo(sensorLocation.sensorLocationY)
    }
}

@@ -373,6 +430,7 @@ private fun insetsForLargeNavbar() = insetsWithBottom(100)
private fun insetsWithBottom(bottom: Int) = WindowInsets.Builder()
    .setInsets(WindowInsets.Type.navigationBars(), Insets.of(0, 0, 0, bottom))
    .build()

private fun fpEnrollTask() = settingsTask(".biometrics.fingerprint.FingerprintEnrollEnrolling")
private fun fpSettingsTask() = settingsTask(".biometrics.fingerprint.FingerprintSettings")
private fun settingsTask(cls: String) = ActivityManager.RunningTaskInfo().apply {