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

Commit 7a0ccd8b authored by Chandru S's avatar Chandru S Committed by Android (Google) Code Review
Browse files

Merge "UI fixes for the progress bar and handle display density changes" into main

parents b323a663 9e3ed4f7
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -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>
+7 −0
Original line number Diff line number Diff line
@@ -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>
+78 −64
Original line number Diff line number Diff line
@@ -34,9 +34,11 @@ import java.util.Optional
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 @@ constructor(
    private val logger: SideFpsLogger,
) {

    private val sensorForCurrentDisplay =
    private val sensorLocationForCurrentDisplay =
        combine(
                displayStateInteractor.displayChanges,
                fingerprintPropertyRepository.sensorLocations,
@@ -77,23 +79,23 @@ constructor(
                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) ->
        combine(displayStateInteractor.currentRotation, sensorLocationForCurrentDisplay, ::Pair)
            .map { (rotation, sensorLocation: SensorLocationInternal) ->
                val isSensorVerticalInDefaultOrientation = sensorLocation.sensorLocationY != 0
                // device dimensions in the current rotation
            val size = windowManager.maximumWindowMetrics.bounds
                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 sensorWidth = context.resources?.getInteger(R.integer.config_sfpsSensorWidth) ?: 0
                val sensorLengthInPx = sensorLocation.sensorRadius * 2

                val (sensorLeft, sensorTop) =
                    if (isSensorVerticalInDefaultOrientation) {
@@ -105,11 +107,18 @@ constructor(
                                Pair(sensorLocation.sensorLocationY, 0)
                            }
                            DisplayRotation.ROTATION_180 -> {
                            Pair(0, displayHeight - sensorLocation.sensorLocationY - sensorWidth)
                                Pair(
                                    0,
                                    displayHeight -
                                        sensorLocation.sensorLocationY -
                                        sensorLengthInPx
                                )
                            }
                            DisplayRotation.ROTATION_270 -> {
                                Pair(
                                displayHeight - sensorLocation.sensorLocationY - sensorWidth,
                                    displayHeight -
                                        sensorLocation.sensorLocationY -
                                        sensorLengthInPx,
                                    displayWidth
                                )
                            }
@@ -120,11 +129,16 @@ constructor(
                                Pair(sensorLocation.sensorLocationX, 0)
                            }
                            DisplayRotation.ROTATION_90 -> {
                            Pair(0, displayWidth - sensorLocation.sensorLocationX - sensorWidth)
                                Pair(
                                    0,
                                    displayWidth - sensorLocation.sensorLocationX - sensorLengthInPx
                                )
                            }
                            DisplayRotation.ROTATION_180 -> {
                                Pair(
                                displayWidth - sensorLocation.sensorLocationX - sensorWidth,
                                    displayWidth -
                                        sensorLocation.sensorLocationX -
                                        sensorLengthInPx,
                                    displayHeight
                                )
                            }
@@ -134,20 +148,20 @@ constructor(
                        }
                    }

            logger.sensorLocationStateChanged(
                size,
                rotation,
                displayWidth,
                displayHeight,
                sensorWidth,
                isSensorVerticalInDefaultOrientation
            )

                SideFpsSensorLocation(
                    left = sensorLeft,
                    top = sensorTop,
                width = sensorWidth,
                    length = sensorLengthInPx,
                    isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation
                )
            }
            .distinctUntilChanged()
            .onEach {
                logger.sensorLocationStateChanged(
                    it.left,
                    it.top,
                    it.length,
                    it.isSensorVerticalInDefaultOrientation
                )
            }
}
+2 −2
Original line number Diff line number Diff line
@@ -21,8 +21,8 @@ data class SideFpsSensorLocation(
    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)
+96 −14
Original line number Diff line number Diff line
@@ -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 @@ constructor(
    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)
                            .collectLatest { (visible, location, rotation, fpDetectRunning, length)
                                ->
                                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
        // be shown at the same location
        if (visible) {
            logger.hidingSfpsIndicator()
            sfpsController.get().hideIndicator()
        } else if (fpDetectRunning) {
            logger.showingSfpsIndicator()
            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 {
                    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