UI fixes for the progress bar and handle display density changes
Summary of changes:
- Change the code to use the sensor radius from fingerprintManager for the length of the progress bar
- Use length and thickness to describe the progress bar instead of height and width.
- The progress bar overlay is now fullscreen with the progress bar being a child element with fixed width and height. In previous setup, progress bar either kept getting clipped or the length changes were not getting reflected correctly.
- Update the view leftTop point calculation in the view model to take into account the thickness of the progress bar and the padding from screen edge
- Added a command to make the progress bar testing easier.
Bug: 305271359
Flag: LEGACY REST_TO_UNLOCK DEVELOPMENT
Test: tested with various display sizes in the settings and different orientations to make sure the progress is aligned next to the sensor.
Test: atest SideFpsSensorInteractorTest
Test: pending for the viewModel, will add in a follow-up CL
Change-Id: I1dd485a96c1c878329e9273f0d102ca009a3fdcd
diff --git a/packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml b/packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml
index 183f0e5..9d74677 100644
--- a/packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml
+++ b/packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml
@@ -15,18 +15,18 @@
~
-->
-<LinearLayout android:layout_height="match_parent"
+<RelativeLayout
android:layout_width="match_parent"
- android:orientation="vertical"
- android:layoutDirection="ltr"
- android:gravity="center"
+ android:layout_height="match_parent"
+ android:gravity="left|top"
+ android:background="@android:color/transparent"
xmlns:android="http://schemas.android.com/apk/res/android">
<ProgressBar
android:id="@+id/side_fps_progress_bar"
- android:layout_width="55dp"
- android:layout_height="10dp"
+ android:layout_width="0dp"
+ android:layout_height="@dimen/sfps_progress_bar_thickness"
android:indeterminateOnly="false"
android:min="0"
android:max="100"
android:progressDrawable="@drawable/progress_bar" />
-</LinearLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index d1067a9..0628c3e 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -157,4 +157,11 @@
<dimen name="weather_clock_smartspace_translateX">0dp</dimen>
<dimen name="weather_clock_smartspace_translateY">0dp</dimen>
+ <!-- Additional length to add to the SFPS sensor length we get from framework so that the length
+ of the progress bar matches the length of the power button -->
+ <dimen name="sfps_progress_bar_length_extra_padding">12dp</dimen>
+ <!-- Thickness of the progress bar we show for the SFPS based authentication. -->
+ <dimen name="sfps_progress_bar_thickness">6dp</dimen>
+ <!-- Padding from the edge of the screen for the progress bar -->
+ <dimen name="sfps_progress_bar_padding_from_edge">7dp</dimen>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
index 0567ea2..2bb19cd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt
@@ -34,9 +34,11 @@
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onEach
@SysUISingleton
class SideFpsSensorInteractor
@@ -51,7 +53,7 @@
private val logger: SideFpsLogger,
) {
- private val sensorForCurrentDisplay =
+ private val sensorLocationForCurrentDisplay =
combine(
displayStateInteractor.displayChanges,
fingerprintPropertyRepository.sensorLocations,
@@ -77,77 +79,89 @@
isAvailable,
fingerprintInteractiveToAuthProvider.get().enabledForCurrentUser
) { sfpsAvailable, isSettingEnabled ->
- logger.logStateChange(sfpsAvailable, isSettingEnabled)
sfpsAvailable && isSettingEnabled
}
}
val sensorLocation: Flow<SideFpsSensorLocation> =
- combine(displayStateInteractor.currentRotation, sensorForCurrentDisplay, ::Pair).map {
- (rotation, sensorLocation: SensorLocationInternal) ->
- val isSensorVerticalInDefaultOrientation = sensorLocation.sensorLocationY != 0
- // device dimensions in the current rotation
- val size = windowManager.maximumWindowMetrics.bounds
- val isDefaultOrientation = rotation.isDefaultOrientation()
- // Width and height are flipped is device is not in rotation_0 or rotation_180
- // Flipping it to the width and height of the device in default orientation.
- val displayWidth = if (isDefaultOrientation) size.width() else size.height()
- val displayHeight = if (isDefaultOrientation) size.height() else size.width()
- val sensorWidth = context.resources?.getInteger(R.integer.config_sfpsSensorWidth) ?: 0
+ combine(displayStateInteractor.currentRotation, sensorLocationForCurrentDisplay, ::Pair)
+ .map { (rotation, sensorLocation: SensorLocationInternal) ->
+ val isSensorVerticalInDefaultOrientation = sensorLocation.sensorLocationY != 0
+ // device dimensions in the current rotation
+ val windowMetrics = windowManager.maximumWindowMetrics
+ val size = windowMetrics.bounds
+ val isDefaultOrientation = rotation.isDefaultOrientation()
+ // Width and height are flipped is device is not in rotation_0 or rotation_180
+ // Flipping it to the width and height of the device in default orientation.
+ val displayWidth = if (isDefaultOrientation) size.width() else size.height()
+ val displayHeight = if (isDefaultOrientation) size.height() else size.width()
+ val sensorLengthInPx = sensorLocation.sensorRadius * 2
- val (sensorLeft, sensorTop) =
- if (isSensorVerticalInDefaultOrientation) {
- when (rotation) {
- DisplayRotation.ROTATION_0 -> {
- Pair(displayWidth, sensorLocation.sensorLocationY)
+ val (sensorLeft, sensorTop) =
+ if (isSensorVerticalInDefaultOrientation) {
+ when (rotation) {
+ DisplayRotation.ROTATION_0 -> {
+ Pair(displayWidth, sensorLocation.sensorLocationY)
+ }
+ DisplayRotation.ROTATION_90 -> {
+ Pair(sensorLocation.sensorLocationY, 0)
+ }
+ DisplayRotation.ROTATION_180 -> {
+ Pair(
+ 0,
+ displayHeight -
+ sensorLocation.sensorLocationY -
+ sensorLengthInPx
+ )
+ }
+ DisplayRotation.ROTATION_270 -> {
+ Pair(
+ displayHeight -
+ sensorLocation.sensorLocationY -
+ sensorLengthInPx,
+ displayWidth
+ )
+ }
}
- DisplayRotation.ROTATION_90 -> {
- Pair(sensorLocation.sensorLocationY, 0)
- }
- DisplayRotation.ROTATION_180 -> {
- Pair(0, displayHeight - sensorLocation.sensorLocationY - sensorWidth)
- }
- DisplayRotation.ROTATION_270 -> {
- Pair(
- displayHeight - sensorLocation.sensorLocationY - sensorWidth,
- displayWidth
- )
+ } else {
+ when (rotation) {
+ DisplayRotation.ROTATION_0 -> {
+ Pair(sensorLocation.sensorLocationX, 0)
+ }
+ DisplayRotation.ROTATION_90 -> {
+ Pair(
+ 0,
+ displayWidth - sensorLocation.sensorLocationX - sensorLengthInPx
+ )
+ }
+ DisplayRotation.ROTATION_180 -> {
+ Pair(
+ displayWidth -
+ sensorLocation.sensorLocationX -
+ sensorLengthInPx,
+ displayHeight
+ )
+ }
+ DisplayRotation.ROTATION_270 -> {
+ Pair(displayHeight, sensorLocation.sensorLocationX)
+ }
}
}
- } else {
- when (rotation) {
- DisplayRotation.ROTATION_0 -> {
- Pair(sensorLocation.sensorLocationX, 0)
- }
- DisplayRotation.ROTATION_90 -> {
- Pair(0, displayWidth - sensorLocation.sensorLocationX - sensorWidth)
- }
- DisplayRotation.ROTATION_180 -> {
- Pair(
- displayWidth - sensorLocation.sensorLocationX - sensorWidth,
- displayHeight
- )
- }
- DisplayRotation.ROTATION_270 -> {
- Pair(displayHeight, sensorLocation.sensorLocationX)
- }
- }
- }
- logger.sensorLocationStateChanged(
- size,
- rotation,
- displayWidth,
- displayHeight,
- sensorWidth,
- isSensorVerticalInDefaultOrientation
- )
-
- SideFpsSensorLocation(
- left = sensorLeft,
- top = sensorTop,
- width = sensorWidth,
- isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation
- )
- }
+ SideFpsSensorLocation(
+ left = sensorLeft,
+ top = sensorTop,
+ length = sensorLengthInPx,
+ isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation
+ )
+ }
+ .distinctUntilChanged()
+ .onEach {
+ logger.sensorLocationStateChanged(
+ it.left,
+ it.top,
+ it.length,
+ it.isSensorVerticalInDefaultOrientation
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/SideFpsSensorLocation.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/SideFpsSensorLocation.kt
index 35f8e3b..12f374f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/SideFpsSensorLocation.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/SideFpsSensorLocation.kt
@@ -21,8 +21,8 @@
val left: Int,
/** Pixel offset from the top of the screen */
val top: Int,
- /** Width in pixels of the SFPS sensor */
- val width: Int,
+ /** Length of the SFPS sensor in pixels in current display density */
+ val length: Int,
/**
* Whether the sensor is vertical when the device is in its default orientation (Rotation_0 or
* Rotation_180)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
index 1acea5c..ba4876f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt
@@ -16,19 +16,27 @@
package com.android.systemui.keyguard.ui.binder
+import android.animation.ValueAnimator
+import android.graphics.Point
import com.android.systemui.CoreStartable
import com.android.systemui.biometrics.SideFpsController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.ui.view.SideFpsProgressBar
import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel
+import com.android.systemui.log.SideFpsLogger
+import com.android.systemui.statusbar.commandline.Command
+import com.android.systemui.statusbar.commandline.CommandRegistry
import com.android.systemui.util.kotlin.Quint
+import java.io.PrintWriter
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
+private const val spfsProgressBarCommand = "sfps-progress-bar"
+
@SysUISingleton
class SideFpsProgressBarViewBinder
@Inject
@@ -37,38 +45,112 @@
private val view: SideFpsProgressBar,
@Application private val applicationScope: CoroutineScope,
private val sfpsController: dagger.Lazy<SideFpsController>,
+ private val logger: SideFpsLogger,
+ private val commandRegistry: CommandRegistry,
) : CoreStartable {
override fun start() {
+ commandRegistry.registerCommand(spfsProgressBarCommand) { SfpsProgressBarCommand() }
applicationScope.launch {
viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled ->
+ logger.isProlongedTouchRequiredForAuthenticationChanged(enabled)
if (enabled) {
launch {
combine(
viewModel.isVisible,
- viewModel.sensorLocation,
- viewModel.shouldRotate90Degrees,
+ viewModel.progressBarLocation,
+ viewModel.rotation,
viewModel.isFingerprintAuthRunning,
- viewModel.sensorWidth,
+ viewModel.progressBarLength,
::Quint
)
- .collectLatest {
- (visible, location, shouldRotate, fpDetectRunning, sensorWidth) ->
- view.updateView(visible, location, shouldRotate, sensorWidth)
- // We have to hide the SFPS indicator as the progress bar will
- // be shown at the same location
- if (visible) {
- sfpsController.get().hideIndicator()
- } else if (fpDetectRunning) {
- sfpsController.get().showIndicator()
- }
+ .collectLatest { (visible, location, rotation, fpDetectRunning, length)
+ ->
+ updateView(
+ visible,
+ location,
+ fpDetectRunning,
+ length,
+ viewModel.progressBarThickness,
+ rotation,
+ )
}
}
launch { viewModel.progress.collectLatest { view.setProgress(it) } }
} else {
- view.hideOverlay()
+ view.hide()
}
}
}
}
+
+ private fun updateView(
+ visible: Boolean,
+ location: Point,
+ fpDetectRunning: Boolean,
+ length: Int,
+ thickness: Int,
+ rotation: Float,
+ ) {
+ logger.sfpsProgressBarStateChanged(visible, location, fpDetectRunning, length, rotation)
+ view.updateView(visible, location, length, thickness, rotation)
+ // We have to hide the SFPS indicator as the progress bar will
+ // be shown at the same location
+ if (visible) {
+ logger.hidingSfpsIndicator()
+ sfpsController.get().hideIndicator()
+ } else if (fpDetectRunning) {
+ logger.showingSfpsIndicator()
+ sfpsController.get().showIndicator()
+ }
+ }
+
+ inner class SfpsProgressBarCommand : Command {
+ private var animator: ValueAnimator? = null
+ override fun execute(pw: PrintWriter, args: List<String>) {
+ if (args.isEmpty() || args[0] == "show" && args.size != 6) {
+ pw.println("invalid command")
+ help(pw)
+ } else {
+ when (args[0]) {
+ "show" -> {
+ animator?.cancel()
+ updateView(
+ visible = true,
+ location = Point(Integer.parseInt(args[1]), Integer.parseInt(args[2])),
+ fpDetectRunning = true,
+ length = Integer.parseInt(args[3]),
+ thickness = Integer.parseInt(args[4]),
+ rotation = Integer.parseInt(args[5]).toFloat(),
+ )
+ animator =
+ ValueAnimator.ofFloat(0.0f, 1.0f).apply {
+ repeatMode = ValueAnimator.REVERSE
+ repeatCount = ValueAnimator.INFINITE
+ addUpdateListener { view.setProgress(it.animatedValue as Float) }
+ }
+ animator?.start()
+ }
+ "hide" -> {
+ animator?.cancel()
+ updateView(
+ visible = false,
+ location = Point(0, 0),
+ fpDetectRunning = false,
+ length = 0,
+ thickness = 0,
+ rotation = 0.0f,
+ )
+ }
+ }
+ }
+ }
+
+ override fun help(pw: PrintWriter) {
+ pw.println("Usage: adb shell cmd statusbar $spfsProgressBarCommand <command>")
+ pw.println("Available commands:")
+ pw.println(" show x y width height rotation")
+ pw.println(" hide")
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/SideFpsProgressBar.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/SideFpsProgressBar.kt
index f7ab1ee..853f176 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/SideFpsProgressBar.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/SideFpsProgressBar.kt
@@ -22,17 +22,16 @@
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.WindowManager
import android.widget.ProgressBar
-import com.android.systemui.biometrics.Utils
+import androidx.core.view.isGone
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.res.R
import javax.inject.Inject
private const val TAG = "SideFpsProgressBar"
-const val progressBarHeight = 100
-
@SysUISingleton
class SideFpsProgressBar
@Inject
@@ -40,31 +39,36 @@
private val layoutInflater: LayoutInflater,
private val windowManager: WindowManager,
) {
- private var progressBarWidth = 200
+ private var overlayView: View? = null
+
fun updateView(
visible: Boolean,
- location: Point,
- shouldRotate90Degrees: Boolean,
- progressBarWidth: Int
+ viewLeftTopLocation: Point,
+ progressBarWidth: Int,
+ progressBarHeight: Int,
+ rotation: Float,
) {
if (visible) {
- this.progressBarWidth = progressBarWidth
- createAndShowOverlay(location, shouldRotate90Degrees)
+ createAndShowOverlay(viewLeftTopLocation, rotation, progressBarWidth, progressBarHeight)
} else {
- hideOverlay()
+ hide()
}
}
- fun hideOverlay() {
- overlayView = null
+ fun hide() {
+ progressBar?.isGone = true
}
private val overlayViewParams =
WindowManager.LayoutParams(
- progressBarHeight,
- progressBarWidth,
+ // overlay is always full screen
+ MATCH_PARENT,
+ MATCH_PARENT,
WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
- Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
PixelFormat.TRANSPARENT
)
.apply {
@@ -78,37 +82,31 @@
WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
}
- private var overlayView: View? = null
- set(value) {
- field?.let { oldView -> windowManager.removeView(oldView) }
- field = value
- field?.let { newView -> windowManager.addView(newView, overlayViewParams) }
- }
-
private fun createAndShowOverlay(
- fingerprintSensorLocation: Point,
- shouldRotate90Degrees: Boolean
+ viewLeftTop: Point,
+ rotation: Float,
+ progressBarLength: Int,
+ progressBarThickness: Int,
) {
if (overlayView == null) {
overlayView = layoutInflater.inflate(R.layout.sidefps_progress_bar, null, false)
+ windowManager.addView(overlayView, overlayViewParams)
+ progressBar?.pivotX = 0.0f
+ progressBar?.pivotY = 0.0f
}
- overlayViewParams.x = fingerprintSensorLocation.x
- overlayViewParams.y = fingerprintSensorLocation.y
- if (shouldRotate90Degrees) {
- overlayView?.rotation = 270.0f
- overlayViewParams.width = progressBarHeight
- overlayViewParams.height = progressBarWidth
- } else {
- overlayView?.rotation = 0.0f
- overlayViewParams.width = progressBarWidth
- overlayViewParams.height = progressBarHeight
- }
- windowManager.updateViewLayout(overlayView, overlayViewParams)
+ progressBar?.layoutParams?.width = progressBarLength
+ progressBar?.layoutParams?.height = progressBarThickness
+ progressBar?.translationX = viewLeftTop.x.toFloat()
+ progressBar?.translationY = viewLeftTop.y.toFloat()
+ progressBar?.rotation = rotation
+ progressBar?.isGone = false
+ overlayView?.requestLayout()
}
fun setProgress(value: Float) {
- overlayView
- ?.findViewById<ProgressBar?>(R.id.side_fps_progress_bar)
- ?.setProgress((value * 100).toInt(), false)
+ progressBar?.setProgress((value * 100).toInt(), false)
}
+
+ private val progressBar: ProgressBar?
+ get() = overlayView?.findViewById(R.id.side_fps_progress_bar)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
index 2c3b431..f8996b7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt
@@ -17,10 +17,12 @@
package com.android.systemui.keyguard.ui.viewmodel
import android.animation.ValueAnimator
+import android.content.Context
import android.graphics.Point
import androidx.core.animation.doOnEnd
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor
+import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.isDefaultOrientation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -29,6 +31,7 @@
import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
+import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
@@ -36,6 +39,7 @@
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@@ -43,6 +47,7 @@
class SideFpsProgressBarViewModel
@Inject
constructor(
+ private val context: Context,
private val fpAuthRepository: DeviceEntryFingerprintAuthRepository,
private val sfpsSensorInteractor: SideFpsSensorInteractor,
displayStateInteractor: DisplayStateInteractor,
@@ -57,24 +62,84 @@
_progress.value = 0.0f
}
+ private val additionalSensorLengthPadding =
+ context.resources.getDimension(R.dimen.sfps_progress_bar_length_extra_padding).toInt()
+
val isVisible: Flow<Boolean> = _visible.asStateFlow()
val progress: Flow<Float> = _progress.asStateFlow()
- val sensorWidth: Flow<Int> = sfpsSensorInteractor.sensorLocation.map { it.width }
+ val progressBarLength: Flow<Int> =
+ sfpsSensorInteractor.sensorLocation
+ .map { it.length + additionalSensorLengthPadding }
+ .distinctUntilChanged()
- val sensorLocation: Flow<Point> =
- sfpsSensorInteractor.sensorLocation.map { Point(it.left, it.top) }
+ val progressBarThickness =
+ context.resources.getDimension(R.dimen.sfps_progress_bar_thickness).toInt()
+
+ val progressBarLocation =
+ combine(displayStateInteractor.currentRotation, sfpsSensorInteractor.sensorLocation, ::Pair)
+ .map { (rotation, sensorLocation) ->
+ val paddingFromEdge =
+ context.resources
+ .getDimension(R.dimen.sfps_progress_bar_padding_from_edge)
+ .toInt()
+ val lengthOfTheProgressBar = sensorLocation.length + additionalSensorLengthPadding
+ val viewLeftTop = Point(sensorLocation.left, sensorLocation.top)
+ val totalDistanceFromTheEdge = paddingFromEdge + progressBarThickness
+
+ val isSensorVerticalNow =
+ sensorLocation.isSensorVerticalInDefaultOrientation ==
+ rotation.isDefaultOrientation()
+ if (isSensorVerticalNow) {
+ // Sensor is vertical to the current orientation, we rotate it 270 deg
+ // around the (left,top) point as the pivot. We need to push it down the
+ // length of the progress bar so that it is still aligned to the sensor
+ viewLeftTop.y += lengthOfTheProgressBar
+ val isSensorOnTheNearEdge =
+ rotation == DisplayRotation.ROTATION_180 ||
+ rotation == DisplayRotation.ROTATION_90
+ if (isSensorOnTheNearEdge) {
+ // Add just the padding from the edge to push the progress bar right
+ viewLeftTop.x += paddingFromEdge
+ } else {
+ // View left top is pushed left from the edge by the progress bar thickness
+ // and the padding.
+ viewLeftTop.x -= totalDistanceFromTheEdge
+ }
+ } else {
+ // Sensor is horizontal to the current orientation.
+ val isSensorOnTheNearEdge =
+ rotation == DisplayRotation.ROTATION_0 ||
+ rotation == DisplayRotation.ROTATION_90
+ if (isSensorOnTheNearEdge) {
+ // Add just the padding from the edge to push the progress bar down
+ viewLeftTop.y += paddingFromEdge
+ } else {
+ // Sensor is now at the bottom edge of the device in the current rotation.
+ // We want to push it up from the bottom edge by the padding and
+ // the thickness of the progressbar.
+ viewLeftTop.y -= totalDistanceFromTheEdge
+ viewLeftTop.x -= additionalSensorLengthPadding
+ }
+ }
+ viewLeftTop
+ }
val isFingerprintAuthRunning: Flow<Boolean> = fpAuthRepository.isRunning
- val shouldRotate90Degrees: Flow<Boolean> =
+ val rotation: Flow<Float> =
combine(displayStateInteractor.currentRotation, sfpsSensorInteractor.sensorLocation, ::Pair)
.map { (rotation, sensorLocation) ->
- if (rotation.isDefaultOrientation()) {
- sensorLocation.isSensorVerticalInDefaultOrientation
+ if (
+ rotation.isDefaultOrientation() ==
+ sensorLocation.isSensorVerticalInDefaultOrientation
+ ) {
+ // We should rotate the progress bar 270 degrees in the clockwise direction with
+ // the left top point as the pivot so that it fills up from bottom to top
+ 270.0f
} else {
- !sensorLocation.isSensorVerticalInDefaultOrientation
+ 0.0f
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt
index 74923ee..919072a 100644
--- a/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt
@@ -17,8 +17,6 @@
package com.android.systemui.log
import android.graphics.Point
-import android.graphics.Rect
-import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.BouncerLog
@@ -40,9 +38,9 @@
fun sfpsProgressBarStateChanged(
visible: Boolean,
location: Point,
- shouldRotate: Boolean,
fpDetectRunning: Boolean,
- sensorWidth: Int
+ sensorWidth: Int,
+ rotation: Float,
) {
buffer.log(
TAG,
@@ -51,14 +49,14 @@
bool1 = visible
int1 = location.x
int2 = location.y
- bool2 = shouldRotate
+ str1 = "$rotation"
bool3 = fpDetectRunning
long1 = sensorWidth.toLong()
},
{
"SFPS progress bar state changed: visible: $bool1, " +
"sensorLocation (x, y): ($int1, $int2), " +
- "shouldRotate = $bool2, " +
+ "rotation = $str1, " +
"fpDetectRunning: $bool3, " +
"sensorWidth: $long1"
}
@@ -87,44 +85,25 @@
)
}
- fun logStateChange(sfpsAvailable: Boolean, settingEnabled: Boolean) {
- buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- bool1 = sfpsAvailable
- bool2 = settingEnabled
- },
- { "SFPS rest to unlock state changed: sfpsAvailable: $bool1, settingEnabled: $bool2" }
- )
- }
-
fun sensorLocationStateChanged(
- windowSize: Rect?,
- rotation: DisplayRotation,
- displayWidth: Int,
- displayHeight: Int,
- sensorWidth: Int,
- sensorVerticalInDefaultOrientation: Boolean
+ pointOnScreenX: Int,
+ pointOnScreenY: Int,
+ sensorLength: Int,
+ isSensorVerticalInDefaultOrientation: Boolean
) {
buffer.log(
TAG,
LogLevel.DEBUG,
{
- str1 = "$windowSize"
- str2 = rotation.name
- int1 = displayWidth
- int2 = displayHeight
- long1 = sensorWidth.toLong()
- bool1 = sensorVerticalInDefaultOrientation
+ int1 = pointOnScreenX
+ int2 = pointOnScreenY
+ str2 = "$sensorLength"
+ bool1 = isSensorVerticalInDefaultOrientation
},
{
- "sensorLocation state changed: " +
- "windowSize: $str1, " +
- "rotation: $str2, " +
- "widthInRotation0: $int1, " +
- "heightInRotation0: $int2, " +
- "sensorWidth: $long1, " +
+ "SideFpsSensorLocation state changed: " +
+ "pointOnScreen: ($int1, $int2), " +
+ "sensorLength: $str2, " +
"sensorVerticalInDefaultOrientation: $bool1"
}
)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt
index 1e7a3d3..3fbdeec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt
@@ -165,7 +165,7 @@
assertThat(sensorLocation!!.left).isEqualTo(1000)
assertThat(sensorLocation!!.top).isEqualTo(200)
assertThat(sensorLocation!!.isSensorVerticalInDefaultOrientation).isEqualTo(true)
- assertThat(sensorLocation!!.width).isEqualTo(100)
+ assertThat(sensorLocation!!.length).isEqualTo(100)
}
@Test
@@ -193,7 +193,7 @@
assertThat(sensorLocation!!.left).isEqualTo(500)
assertThat(sensorLocation!!.top).isEqualTo(1000)
assertThat(sensorLocation!!.isSensorVerticalInDefaultOrientation).isEqualTo(true)
- assertThat(sensorLocation!!.width).isEqualTo(100)
+ assertThat(sensorLocation!!.length).isEqualTo(100)
}
@Test
@@ -221,7 +221,7 @@
assertThat(sensorLocation!!.left).isEqualTo(200)
assertThat(sensorLocation!!.top).isEqualTo(0)
assertThat(sensorLocation!!.isSensorVerticalInDefaultOrientation).isEqualTo(true)
- assertThat(sensorLocation!!.width).isEqualTo(100)
+ assertThat(sensorLocation!!.length).isEqualTo(100)
}
@Test
@@ -274,7 +274,7 @@
assertThat(sensorLocation!!.left).isEqualTo(500)
assertThat(sensorLocation!!.top).isEqualTo(0)
assertThat(sensorLocation!!.isSensorVerticalInDefaultOrientation).isEqualTo(false)
- assertThat(sensorLocation!!.width).isEqualTo(100)
+ assertThat(sensorLocation!!.length).isEqualTo(100)
}
@Test
@@ -301,7 +301,7 @@
assertThat(sensorLocation!!.left).isEqualTo(0)
assertThat(sensorLocation!!.top).isEqualTo(400)
assertThat(sensorLocation!!.isSensorVerticalInDefaultOrientation).isEqualTo(false)
- assertThat(sensorLocation!!.width).isEqualTo(100)
+ assertThat(sensorLocation!!.length).isEqualTo(100)
}
@Test
@@ -328,7 +328,7 @@
assertThat(sensorLocation!!.left).isEqualTo(400)
assertThat(sensorLocation!!.top).isEqualTo(800)
assertThat(sensorLocation!!.isSensorVerticalInDefaultOrientation).isEqualTo(false)
- assertThat(sensorLocation!!.width).isEqualTo(100)
+ assertThat(sensorLocation!!.length).isEqualTo(100)
}
@Test
@@ -355,7 +355,7 @@
assertThat(sensorLocation!!.left).isEqualTo(800)
assertThat(sensorLocation!!.top).isEqualTo(500)
assertThat(sensorLocation!!.isSensorVerticalInDefaultOrientation).isEqualTo(false)
- assertThat(sensorLocation!!.width).isEqualTo(100)
+ assertThat(sensorLocation!!.length).isEqualTo(100)
}
@Test
@@ -381,10 +381,14 @@
rotation: DisplayRotation,
sensorWidth: Int
) {
- overrideResource(R.integer.config_sfpsSensorWidth, sensorWidth)
setupDisplayDimensions(width, height)
currentRotation.value = rotation
- setupFingerprint(x = sensorLocationX, y = sensorLocationY, displayId = "expanded_display")
+ setupFingerprint(
+ x = sensorLocationX,
+ y = sensorLocationY,
+ displayId = "expanded_display",
+ sensorRadius = sensorWidth / 2
+ )
}
private fun setupDisplayDimensions(displayWidth: Int, displayHeight: Int) {
@@ -392,7 +396,7 @@
.thenReturn(
WindowMetrics(
Rect(0, 0, displayWidth, displayHeight),
- mock(WindowInsets::class.java)
+ mock(WindowInsets::class.java),
)
)
}
@@ -401,7 +405,8 @@
fingerprintSensorType: FingerprintSensorType = FingerprintSensorType.POWER_BUTTON,
x: Int = 0,
y: Int = 0,
- displayId: String = "display_id_1"
+ displayId: String = "display_id_1",
+ sensorRadius: Int = 150
) {
contextDisplayInfo.uniqueId = displayId
fingerprintRepository.setProperties(
@@ -415,14 +420,14 @@
"someOtherDisplayId",
x + 100,
y + 100,
- 0,
+ sensorRadius,
),
displayId to
SensorLocationInternal(
displayId,
x,
y,
- 0,
+ sensorRadius,
)
)
)