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

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

Merge "Add all the derived state needed for rest to unlock feature to...

Merge "Add all the derived state needed for rest to unlock feature to SideFpsSensorInteractor" into main
parents 9526fa3b 60f9c514
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -957,4 +957,15 @@
    bouncer, lockscreen, shade, and quick settings.
    -->
    <bool name="config_sceneContainerFrameworkEnabled">true</bool>

    <!--
    Time in milliseconds the user has to touch the side FPS sensor to successfully authenticate
    TODO(b/302332976) Get this value from the HAL if they can provide an API for it.
    -->
    <integer name="config_restToUnlockDuration">300</integer>

    <!--
    Width in pixels of the Side FPS sensor.
    -->
    <integer name="config_sfpsSensorWidth">200</integer>
</resources>
+0 −8
Original line number Diff line number Diff line
@@ -23,8 +23,6 @@ import com.android.systemui.biometrics.domain.interactor.LogContextInteractor
import com.android.systemui.biometrics.domain.interactor.LogContextInteractorImpl
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractorImpl
import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractor
import com.android.systemui.biometrics.domain.interactor.SideFpsOverlayInteractorImpl
import com.android.systemui.dagger.SysUISingleton
import dagger.Binds
import dagger.Module
@@ -49,10 +47,4 @@ interface BiometricsDomainLayerModule {
    @Binds
    @SysUISingleton
    fun bindsLogContextInteractor(impl: LogContextInteractorImpl): LogContextInteractor

    @Binds
    @SysUISingleton
    fun providesSideFpsOverlayInteractor(
        impl: SideFpsOverlayInteractorImpl
    ): SideFpsOverlayInteractor
}
+5 −0
Original line number Diff line number Diff line
@@ -54,6 +54,9 @@ interface DisplayStateInteractor {
    /** Current rotation of the display */
    val currentRotation: StateFlow<DisplayRotation>

    /** Display change event indicating a change to the given displayId has occurred. */
    val displayChanges: Flow<Int>

    /** Called on configuration changes, used to keep the display state in sync */
    fun onConfigurationChanged(newConfig: Configuration)
}
@@ -74,6 +77,8 @@ constructor(
        screenSizeFoldProvider = foldProvider
    }

    override val displayChanges = displayRepository.displayChangeEvent

    override val isFolded: Flow<Boolean> =
        conflatedCallbackFlow {
                val sendFoldStateUpdate = { state: Boolean ->
+0 −62
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.biometrics.domain.interactor

import android.hardware.biometrics.SensorLocationInternal
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine

/** Business logic for SideFps overlay offsets. */
interface SideFpsOverlayInteractor {

    /** The displayId of the current display. */
    val displayId: Flow<String>

    /** Overlay offsets corresponding to given displayId. */
    val overlayOffsets: Flow<SensorLocationInternal>

    /** Called on display changes, used to keep the display state in sync */
    fun onDisplayChanged(displayId: String)
}

@SysUISingleton
class SideFpsOverlayInteractorImpl
@Inject
constructor(fingerprintPropertyRepository: FingerprintPropertyRepository) :
    SideFpsOverlayInteractor {

    private val _displayId: MutableStateFlow<String> = MutableStateFlow("")
    override val displayId: Flow<String> = _displayId.asStateFlow()

    override val overlayOffsets: Flow<SensorLocationInternal> =
        combine(displayId, fingerprintPropertyRepository.sensorLocations) { displayId, offsets ->
            offsets[displayId] ?: SensorLocationInternal.DEFAULT
        }

    override fun onDisplayChanged(displayId: String) {
        _displayId.value = displayId
    }

    companion object {
        private const val TAG = "SideFpsOverlayInteractorImpl"
    }
}
+136 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.biometrics.domain.interactor

import android.content.Context
import android.hardware.biometrics.SensorLocationInternal
import android.view.WindowManager
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.biometrics.domain.model.SideFpsSensorLocation
import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.isDefaultOrientation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.res.R
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map

@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class SideFpsSensorInteractor
@Inject
constructor(
    private val context: Context,
    fingerprintPropertyRepository: FingerprintPropertyRepository,
    windowManager: WindowManager,
    displayStateInteractor: DisplayStateInteractor,
    featureFlags: FeatureFlagsClassic,
) {

    private val sensorForCurrentDisplay =
        combine(
                displayStateInteractor.displayChanges,
                fingerprintPropertyRepository.sensorLocations,
                ::Pair
            )
            .map { (_, locations) -> locations[context.display?.uniqueId] }
            .filterNotNull()

    val isAvailable: Flow<Boolean> =
        fingerprintPropertyRepository.sensorType.map { it == FingerprintSensorType.POWER_BUTTON }

    val authenticationDuration: Flow<Long> =
        flowOf(context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L)

    val isProlongedTouchRequiredForAuthentication: Flow<Boolean> =
        isAvailable.flatMapLatest { sfpsAvailable ->
            if (sfpsAvailable) {
                // todo (b/305236201) also add the settings check here.
                flowOf(featureFlags.isEnabled(Flags.REST_TO_UNLOCK))
            } else {
                flowOf(false)
            }
        }

    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

            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 - 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 - sensorWidth)
                        }
                        DisplayRotation.ROTATION_180 -> {
                            Pair(
                                displayWidth - sensorLocation.sensorLocationX - sensorWidth,
                                displayHeight
                            )
                        }
                        DisplayRotation.ROTATION_270 -> {
                            Pair(displayHeight, sensorLocation.sensorLocationX)
                        }
                    }
                }

            SideFpsSensorLocation(
                left = sensorLeft,
                top = sensorTop,
                width = sensorWidth,
                isSensorVerticalInDefaultOrientation = isSensorVerticalInDefaultOrientation
            )
        }
}
Loading