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

This commit is contained in:
Grace Cheng
2022-05-02 19:38:24 +00:00
committed by Android (Google) Code Review
3 changed files with 138 additions and 83 deletions

View File

@@ -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

View File

@@ -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()
)
Surface.ROTATION_180 ->
Pair(0, displayHeight - overlayOffsets.sensorLocationY - bounds.height())
else ->
Pair(displayWidth, overlayOffsets.sensorLocationY)
}
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
)
} 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
)
else ->
Pair(overlayOffsets.sensorLocationX, 0)
}
Rect(
overlayOffsets.sensorLocationX,
0,
overlayOffsets.sensorLocationX + boundsWidth,
boundsHeight
)
}
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 =

View File

@@ -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 {