Loading packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml +7 −7 Original line number Original line Diff line number Diff line Loading @@ -15,18 +15,18 @@ ~ ~ --> --> <LinearLayout android:layout_height="match_parent" <RelativeLayout android:layout_width="match_parent" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" android:layoutDirection="ltr" android:gravity="left|top" android:gravity="center" android:background="@android:color/transparent" xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android"> <ProgressBar <ProgressBar android:id="@+id/side_fps_progress_bar" android:id="@+id/side_fps_progress_bar" android:layout_width="55dp" android:layout_width="0dp" android:layout_height="10dp" android:layout_height="@dimen/sfps_progress_bar_thickness" android:indeterminateOnly="false" android:indeterminateOnly="false" android:min="0" android:min="0" android:max="100" android:max="100" android:progressDrawable="@drawable/progress_bar" /> android:progressDrawable="@drawable/progress_bar" /> </LinearLayout> </RelativeLayout> packages/SystemUI/res-keyguard/values/dimens.xml +7 −0 Original line number Original line Diff line number Diff line Loading @@ -157,4 +157,11 @@ <dimen name="weather_clock_smartspace_translateX">0dp</dimen> <dimen name="weather_clock_smartspace_translateX">0dp</dimen> <dimen name="weather_clock_smartspace_translateY">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> </resources> packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt +78 −64 Original line number Original line Diff line number Diff line Loading @@ -34,9 +34,11 @@ import java.util.Optional import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @SysUISingleton @SysUISingleton class SideFpsSensorInteractor class SideFpsSensorInteractor Loading @@ -51,7 +53,7 @@ constructor( private val logger: SideFpsLogger, private val logger: SideFpsLogger, ) { ) { private val sensorForCurrentDisplay = private val sensorLocationForCurrentDisplay = combine( combine( displayStateInteractor.displayChanges, displayStateInteractor.displayChanges, fingerprintPropertyRepository.sensorLocations, fingerprintPropertyRepository.sensorLocations, Loading @@ -77,23 +79,23 @@ constructor( isAvailable, isAvailable, fingerprintInteractiveToAuthProvider.get().enabledForCurrentUser fingerprintInteractiveToAuthProvider.get().enabledForCurrentUser ) { sfpsAvailable, isSettingEnabled -> ) { sfpsAvailable, isSettingEnabled -> logger.logStateChange(sfpsAvailable, isSettingEnabled) sfpsAvailable && isSettingEnabled sfpsAvailable && isSettingEnabled } } } } val sensorLocation: Flow<SideFpsSensorLocation> = val sensorLocation: Flow<SideFpsSensorLocation> = combine(displayStateInteractor.currentRotation, sensorForCurrentDisplay, ::Pair).map { combine(displayStateInteractor.currentRotation, sensorLocationForCurrentDisplay, ::Pair) (rotation, sensorLocation: SensorLocationInternal) -> .map { (rotation, sensorLocation: SensorLocationInternal) -> val isSensorVerticalInDefaultOrientation = sensorLocation.sensorLocationY != 0 val isSensorVerticalInDefaultOrientation = sensorLocation.sensorLocationY != 0 // device dimensions in the current rotation // device dimensions in the current rotation val size = windowManager.maximumWindowMetrics.bounds val windowMetrics = windowManager.maximumWindowMetrics val size = windowMetrics.bounds val isDefaultOrientation = rotation.isDefaultOrientation() val isDefaultOrientation = rotation.isDefaultOrientation() // Width and height are flipped is device is not in rotation_0 or rotation_180 // 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. // Flipping it to the width and height of the device in default orientation. val displayWidth = if (isDefaultOrientation) size.width() else size.height() val displayWidth = if (isDefaultOrientation) size.width() else size.height() val displayHeight = if (isDefaultOrientation) size.height() else size.width() val displayHeight = if (isDefaultOrientation) size.height() else size.width() val sensorWidth = context.resources?.getInteger(R.integer.config_sfpsSensorWidth) ?: 0 val sensorLengthInPx = sensorLocation.sensorRadius * 2 val (sensorLeft, sensorTop) = val (sensorLeft, sensorTop) = if (isSensorVerticalInDefaultOrientation) { if (isSensorVerticalInDefaultOrientation) { Loading @@ -105,11 +107,18 @@ constructor( Pair(sensorLocation.sensorLocationY, 0) Pair(sensorLocation.sensorLocationY, 0) } } DisplayRotation.ROTATION_180 -> { DisplayRotation.ROTATION_180 -> { Pair(0, displayHeight - sensorLocation.sensorLocationY - sensorWidth) Pair( 0, displayHeight - sensorLocation.sensorLocationY - sensorLengthInPx ) } } DisplayRotation.ROTATION_270 -> { DisplayRotation.ROTATION_270 -> { Pair( Pair( displayHeight - sensorLocation.sensorLocationY - sensorWidth, displayHeight - sensorLocation.sensorLocationY - sensorLengthInPx, displayWidth displayWidth ) ) } } Loading @@ -120,11 +129,16 @@ constructor( Pair(sensorLocation.sensorLocationX, 0) Pair(sensorLocation.sensorLocationX, 0) } } DisplayRotation.ROTATION_90 -> { DisplayRotation.ROTATION_90 -> { Pair(0, displayWidth - sensorLocation.sensorLocationX - sensorWidth) Pair( 0, displayWidth - sensorLocation.sensorLocationX - sensorLengthInPx ) } } DisplayRotation.ROTATION_180 -> { DisplayRotation.ROTATION_180 -> { Pair( Pair( displayWidth - sensorLocation.sensorLocationX - sensorWidth, displayWidth - sensorLocation.sensorLocationX - sensorLengthInPx, displayHeight displayHeight ) ) } } Loading @@ -134,20 +148,20 @@ constructor( } } } } logger.sensorLocationStateChanged( size, rotation, displayWidth, displayHeight, sensorWidth, isSensorVerticalInDefaultOrientation ) SideFpsSensorLocation( SideFpsSensorLocation( left = sensorLeft, left = sensorLeft, top = sensorTop, top = sensorTop, width = sensorWidth, length = sensorLengthInPx, isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation ) ) } } .distinctUntilChanged() .onEach { logger.sensorLocationStateChanged( it.left, it.top, it.length, it.isSensorVerticalInDefaultOrientation ) } } } packages/SystemUI/src/com/android/systemui/biometrics/domain/model/SideFpsSensorLocation.kt +2 −2 Original line number Original line Diff line number Diff line Loading @@ -21,8 +21,8 @@ data class SideFpsSensorLocation( val left: Int, val left: Int, /** Pixel offset from the top of the screen */ /** Pixel offset from the top of the screen */ val top: Int, val top: Int, /** Width in pixels of the SFPS sensor */ /** Length of the SFPS sensor in pixels in current display density */ val width: Int, val length: Int, /** /** * Whether the sensor is vertical when the device is in its default orientation (Rotation_0 or * Whether the sensor is vertical when the device is in its default orientation (Rotation_0 or * Rotation_180) * Rotation_180) Loading packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt +96 −14 Original line number Original line Diff line number Diff line Loading @@ -16,19 +16,27 @@ package com.android.systemui.keyguard.ui.binder package com.android.systemui.keyguard.ui.binder import android.animation.ValueAnimator import android.graphics.Point import com.android.systemui.CoreStartable import com.android.systemui.CoreStartable import com.android.systemui.biometrics.SideFpsController import com.android.systemui.biometrics.SideFpsController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.ui.view.SideFpsProgressBar import com.android.systemui.keyguard.ui.view.SideFpsProgressBar import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel 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 com.android.systemui.util.kotlin.Quint import java.io.PrintWriter import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import kotlinx.coroutines.launch private const val spfsProgressBarCommand = "sfps-progress-bar" @SysUISingleton @SysUISingleton class SideFpsProgressBarViewBinder class SideFpsProgressBarViewBinder @Inject @Inject Loading @@ -37,38 +45,112 @@ constructor( private val view: SideFpsProgressBar, private val view: SideFpsProgressBar, @Application private val applicationScope: CoroutineScope, @Application private val applicationScope: CoroutineScope, private val sfpsController: dagger.Lazy<SideFpsController>, private val sfpsController: dagger.Lazy<SideFpsController>, private val logger: SideFpsLogger, private val commandRegistry: CommandRegistry, ) : CoreStartable { ) : CoreStartable { override fun start() { override fun start() { commandRegistry.registerCommand(spfsProgressBarCommand) { SfpsProgressBarCommand() } applicationScope.launch { applicationScope.launch { viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> logger.isProlongedTouchRequiredForAuthenticationChanged(enabled) if (enabled) { if (enabled) { launch { launch { combine( combine( viewModel.isVisible, viewModel.isVisible, viewModel.sensorLocation, viewModel.progressBarLocation, viewModel.shouldRotate90Degrees, viewModel.rotation, viewModel.isFingerprintAuthRunning, viewModel.isFingerprintAuthRunning, viewModel.sensorWidth, viewModel.progressBarLength, ::Quint ::Quint ) ) .collectLatest { .collectLatest { (visible, location, rotation, fpDetectRunning, length) (visible, location, shouldRotate, fpDetectRunning, sensorWidth) -> -> view.updateView(visible, location, shouldRotate, sensorWidth) updateView( visible, location, fpDetectRunning, length, viewModel.progressBarThickness, rotation, ) } } launch { viewModel.progress.collectLatest { view.setProgress(it) } } } else { 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 // We have to hide the SFPS indicator as the progress bar will // be shown at the same location // be shown at the same location if (visible) { if (visible) { logger.hidingSfpsIndicator() sfpsController.get().hideIndicator() sfpsController.get().hideIndicator() } else if (fpDetectRunning) { } else if (fpDetectRunning) { logger.showingSfpsIndicator() sfpsController.get().showIndicator() sfpsController.get().showIndicator() } } } } } launch { viewModel.progress.collectLatest { view.setProgress(it) } } 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 { } else { view.hideOverlay() 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") } } } } } Loading
packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml +7 −7 Original line number Original line Diff line number Diff line Loading @@ -15,18 +15,18 @@ ~ ~ --> --> <LinearLayout android:layout_height="match_parent" <RelativeLayout android:layout_width="match_parent" android:layout_width="match_parent" android:orientation="vertical" android:layout_height="match_parent" android:layoutDirection="ltr" android:gravity="left|top" android:gravity="center" android:background="@android:color/transparent" xmlns:android="http://schemas.android.com/apk/res/android"> xmlns:android="http://schemas.android.com/apk/res/android"> <ProgressBar <ProgressBar android:id="@+id/side_fps_progress_bar" android:id="@+id/side_fps_progress_bar" android:layout_width="55dp" android:layout_width="0dp" android:layout_height="10dp" android:layout_height="@dimen/sfps_progress_bar_thickness" android:indeterminateOnly="false" android:indeterminateOnly="false" android:min="0" android:min="0" android:max="100" android:max="100" android:progressDrawable="@drawable/progress_bar" /> android:progressDrawable="@drawable/progress_bar" /> </LinearLayout> </RelativeLayout>
packages/SystemUI/res-keyguard/values/dimens.xml +7 −0 Original line number Original line Diff line number Diff line Loading @@ -157,4 +157,11 @@ <dimen name="weather_clock_smartspace_translateX">0dp</dimen> <dimen name="weather_clock_smartspace_translateX">0dp</dimen> <dimen name="weather_clock_smartspace_translateY">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> </resources>
packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt +78 −64 Original line number Original line Diff line number Diff line Loading @@ -34,9 +34,11 @@ import java.util.Optional import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach @SysUISingleton @SysUISingleton class SideFpsSensorInteractor class SideFpsSensorInteractor Loading @@ -51,7 +53,7 @@ constructor( private val logger: SideFpsLogger, private val logger: SideFpsLogger, ) { ) { private val sensorForCurrentDisplay = private val sensorLocationForCurrentDisplay = combine( combine( displayStateInteractor.displayChanges, displayStateInteractor.displayChanges, fingerprintPropertyRepository.sensorLocations, fingerprintPropertyRepository.sensorLocations, Loading @@ -77,23 +79,23 @@ constructor( isAvailable, isAvailable, fingerprintInteractiveToAuthProvider.get().enabledForCurrentUser fingerprintInteractiveToAuthProvider.get().enabledForCurrentUser ) { sfpsAvailable, isSettingEnabled -> ) { sfpsAvailable, isSettingEnabled -> logger.logStateChange(sfpsAvailable, isSettingEnabled) sfpsAvailable && isSettingEnabled sfpsAvailable && isSettingEnabled } } } } val sensorLocation: Flow<SideFpsSensorLocation> = val sensorLocation: Flow<SideFpsSensorLocation> = combine(displayStateInteractor.currentRotation, sensorForCurrentDisplay, ::Pair).map { combine(displayStateInteractor.currentRotation, sensorLocationForCurrentDisplay, ::Pair) (rotation, sensorLocation: SensorLocationInternal) -> .map { (rotation, sensorLocation: SensorLocationInternal) -> val isSensorVerticalInDefaultOrientation = sensorLocation.sensorLocationY != 0 val isSensorVerticalInDefaultOrientation = sensorLocation.sensorLocationY != 0 // device dimensions in the current rotation // device dimensions in the current rotation val size = windowManager.maximumWindowMetrics.bounds val windowMetrics = windowManager.maximumWindowMetrics val size = windowMetrics.bounds val isDefaultOrientation = rotation.isDefaultOrientation() val isDefaultOrientation = rotation.isDefaultOrientation() // Width and height are flipped is device is not in rotation_0 or rotation_180 // 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. // Flipping it to the width and height of the device in default orientation. val displayWidth = if (isDefaultOrientation) size.width() else size.height() val displayWidth = if (isDefaultOrientation) size.width() else size.height() val displayHeight = if (isDefaultOrientation) size.height() else size.width() val displayHeight = if (isDefaultOrientation) size.height() else size.width() val sensorWidth = context.resources?.getInteger(R.integer.config_sfpsSensorWidth) ?: 0 val sensorLengthInPx = sensorLocation.sensorRadius * 2 val (sensorLeft, sensorTop) = val (sensorLeft, sensorTop) = if (isSensorVerticalInDefaultOrientation) { if (isSensorVerticalInDefaultOrientation) { Loading @@ -105,11 +107,18 @@ constructor( Pair(sensorLocation.sensorLocationY, 0) Pair(sensorLocation.sensorLocationY, 0) } } DisplayRotation.ROTATION_180 -> { DisplayRotation.ROTATION_180 -> { Pair(0, displayHeight - sensorLocation.sensorLocationY - sensorWidth) Pair( 0, displayHeight - sensorLocation.sensorLocationY - sensorLengthInPx ) } } DisplayRotation.ROTATION_270 -> { DisplayRotation.ROTATION_270 -> { Pair( Pair( displayHeight - sensorLocation.sensorLocationY - sensorWidth, displayHeight - sensorLocation.sensorLocationY - sensorLengthInPx, displayWidth displayWidth ) ) } } Loading @@ -120,11 +129,16 @@ constructor( Pair(sensorLocation.sensorLocationX, 0) Pair(sensorLocation.sensorLocationX, 0) } } DisplayRotation.ROTATION_90 -> { DisplayRotation.ROTATION_90 -> { Pair(0, displayWidth - sensorLocation.sensorLocationX - sensorWidth) Pair( 0, displayWidth - sensorLocation.sensorLocationX - sensorLengthInPx ) } } DisplayRotation.ROTATION_180 -> { DisplayRotation.ROTATION_180 -> { Pair( Pair( displayWidth - sensorLocation.sensorLocationX - sensorWidth, displayWidth - sensorLocation.sensorLocationX - sensorLengthInPx, displayHeight displayHeight ) ) } } Loading @@ -134,20 +148,20 @@ constructor( } } } } logger.sensorLocationStateChanged( size, rotation, displayWidth, displayHeight, sensorWidth, isSensorVerticalInDefaultOrientation ) SideFpsSensorLocation( SideFpsSensorLocation( left = sensorLeft, left = sensorLeft, top = sensorTop, top = sensorTop, width = sensorWidth, length = sensorLengthInPx, isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation ) ) } } .distinctUntilChanged() .onEach { logger.sensorLocationStateChanged( it.left, it.top, it.length, it.isSensorVerticalInDefaultOrientation ) } } }
packages/SystemUI/src/com/android/systemui/biometrics/domain/model/SideFpsSensorLocation.kt +2 −2 Original line number Original line Diff line number Diff line Loading @@ -21,8 +21,8 @@ data class SideFpsSensorLocation( val left: Int, val left: Int, /** Pixel offset from the top of the screen */ /** Pixel offset from the top of the screen */ val top: Int, val top: Int, /** Width in pixels of the SFPS sensor */ /** Length of the SFPS sensor in pixels in current display density */ val width: Int, val length: Int, /** /** * Whether the sensor is vertical when the device is in its default orientation (Rotation_0 or * Whether the sensor is vertical when the device is in its default orientation (Rotation_0 or * Rotation_180) * Rotation_180) Loading
packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt +96 −14 Original line number Original line Diff line number Diff line Loading @@ -16,19 +16,27 @@ package com.android.systemui.keyguard.ui.binder package com.android.systemui.keyguard.ui.binder import android.animation.ValueAnimator import android.graphics.Point import com.android.systemui.CoreStartable import com.android.systemui.CoreStartable import com.android.systemui.biometrics.SideFpsController import com.android.systemui.biometrics.SideFpsController import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.ui.view.SideFpsProgressBar import com.android.systemui.keyguard.ui.view.SideFpsProgressBar import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel 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 com.android.systemui.util.kotlin.Quint import java.io.PrintWriter import javax.inject.Inject import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch import kotlinx.coroutines.launch private const val spfsProgressBarCommand = "sfps-progress-bar" @SysUISingleton @SysUISingleton class SideFpsProgressBarViewBinder class SideFpsProgressBarViewBinder @Inject @Inject Loading @@ -37,38 +45,112 @@ constructor( private val view: SideFpsProgressBar, private val view: SideFpsProgressBar, @Application private val applicationScope: CoroutineScope, @Application private val applicationScope: CoroutineScope, private val sfpsController: dagger.Lazy<SideFpsController>, private val sfpsController: dagger.Lazy<SideFpsController>, private val logger: SideFpsLogger, private val commandRegistry: CommandRegistry, ) : CoreStartable { ) : CoreStartable { override fun start() { override fun start() { commandRegistry.registerCommand(spfsProgressBarCommand) { SfpsProgressBarCommand() } applicationScope.launch { applicationScope.launch { viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> logger.isProlongedTouchRequiredForAuthenticationChanged(enabled) if (enabled) { if (enabled) { launch { launch { combine( combine( viewModel.isVisible, viewModel.isVisible, viewModel.sensorLocation, viewModel.progressBarLocation, viewModel.shouldRotate90Degrees, viewModel.rotation, viewModel.isFingerprintAuthRunning, viewModel.isFingerprintAuthRunning, viewModel.sensorWidth, viewModel.progressBarLength, ::Quint ::Quint ) ) .collectLatest { .collectLatest { (visible, location, rotation, fpDetectRunning, length) (visible, location, shouldRotate, fpDetectRunning, sensorWidth) -> -> view.updateView(visible, location, shouldRotate, sensorWidth) updateView( visible, location, fpDetectRunning, length, viewModel.progressBarThickness, rotation, ) } } launch { viewModel.progress.collectLatest { view.setProgress(it) } } } else { 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 // We have to hide the SFPS indicator as the progress bar will // be shown at the same location // be shown at the same location if (visible) { if (visible) { logger.hidingSfpsIndicator() sfpsController.get().hideIndicator() sfpsController.get().hideIndicator() } else if (fpDetectRunning) { } else if (fpDetectRunning) { logger.showingSfpsIndicator() sfpsController.get().showIndicator() sfpsController.get().showIndicator() } } } } } launch { viewModel.progress.collectLatest { view.setProgress(it) } } 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 { } else { view.hideOverlay() 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") } } } } }