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

Commit d6562879 authored by Beverly Tai's avatar Beverly Tai Committed by Android (Google) Code Review
Browse files

Merge "Gate face auth on display off in the face auth refactor" into main

parents a4736e35 098ee26d
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -18,13 +18,16 @@ package com.android.systemui.biometrics.domain.interactor

import android.content.Context
import android.content.res.Configuration
import android.view.Display
import com.android.systemui.biometrics.data.repository.RearDisplayStateRepository
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.display.data.repository.DisplayRepository
import com.android.systemui.unfold.compat.ScreenSizeFoldProvider
import com.android.systemui.unfold.updates.FoldProvider
import com.android.systemui.util.kotlin.sample
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -32,10 +35,14 @@ import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn

/** Aggregates display state information. */
interface DisplayStateInteractor {
    /** Whether the default display is currently off. */
    val isDefaultDisplayOff: Flow<Boolean>

    /** Whether the device is currently in rear display mode. */
    val isInRearDisplayMode: StateFlow<Boolean>
@@ -55,6 +62,7 @@ constructor(
    @Application context: Context,
    @Main mainExecutor: Executor,
    rearDisplayStateRepository: RearDisplayStateRepository,
    displayRepository: DisplayRepository,
) : DisplayStateInteractor {
    private var screenSizeFoldProvider: ScreenSizeFoldProvider = ScreenSizeFoldProvider(context)

@@ -96,6 +104,17 @@ constructor(
        screenSizeFoldProvider.onConfigurationChange(newConfig)
    }

    private val defaultDisplay =
        displayRepository.displays.map { displays ->
            displays.firstOrNull { it.displayId == Display.DEFAULT_DISPLAY }
        }

    override val isDefaultDisplayOff =
        displayRepository.displayChangeEvent
            .filter { it == Display.DEFAULT_DISPLAY }
            .sample(defaultDisplay)
            .map { it?.state == Display.STATE_OFF }

    companion object {
        private const val TAG = "DisplayStateInteractor"
    }
+24 −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.display.data

sealed interface DisplayEvent {
    val displayId: Int
    data class Added(override val displayId: Int) : DisplayEvent
    data class Removed(override val displayId: Int) : DisplayEvent
    data class Changed(override val displayId: Int) : DisplayEvent
}
+35 −24
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCall
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.data.DisplayEvent
import com.android.systemui.util.Compile
import com.android.systemui.util.traceSection
import javax.inject.Inject
@@ -41,6 +42,7 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -48,7 +50,13 @@ import kotlinx.coroutines.flow.stateIn

/** Provides a [Flow] of [Display] as returned by [DisplayManager]. */
interface DisplayRepository {
    /** Provides a nullable set of displays. */
    /** Display change event indicating a change to the given displayId has occurred. */
    val displayChangeEvent: Flow<Int>

    /**
     * Provides a nullable set of displays. Updates when new displays have been added or removed but
     * not when a display's info has changed.
     */
    val displays: Flow<Set<Display>>

    /**
@@ -86,33 +94,36 @@ constructor(
    @Application applicationScope: CoroutineScope,
    @Background backgroundCoroutineDispatcher: CoroutineDispatcher
) : DisplayRepository {

    // Displays are enabled only after receiving them in [onDisplayAdded]
    private val enabledDisplays: StateFlow<Set<Display>> =
        conflatedCallbackFlow {
    private val allDisplayEvents: Flow<DisplayEvent> = conflatedCallbackFlow {
        val callback =
            object : DisplayListener {
                override fun onDisplayAdded(displayId: Int) {
                            trySend(getDisplays())
                    trySend(DisplayEvent.Added(displayId))
                }

                override fun onDisplayRemoved(displayId: Int) {
                            trySend(getDisplays())
                    trySend(DisplayEvent.Removed(displayId))
                }

                override fun onDisplayChanged(displayId: Int) {
                            trySend(getDisplays())
                    trySend(DisplayEvent.Changed(displayId))
                }
            }
        displayManager.registerDisplayListener(
            callback,
            backgroundHandler,
                    EVENT_FLAG_DISPLAY_ADDED or
                        EVENT_FLAG_DISPLAY_CHANGED or
                        EVENT_FLAG_DISPLAY_REMOVED,
            EVENT_FLAG_DISPLAY_ADDED or EVENT_FLAG_DISPLAY_CHANGED or EVENT_FLAG_DISPLAY_REMOVED,
        )
        awaitClose { displayManager.unregisterDisplayListener(callback) }
    }

    override val displayChangeEvent: Flow<Int> =
        allDisplayEvents.filter { it is DisplayEvent.Changed }.map { it.displayId }

    private val enabledDisplays =
        allDisplayEvents
            .map { getDisplays() }
            .flowOn(backgroundCoroutineDispatcher)
            .stateIn(
                applicationScope,
+12 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.internal.logging.UiEventLogger
import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.Dumpable
import com.android.systemui.R
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
@@ -161,6 +162,7 @@ constructor(
    @FaceDetectTableLog private val faceDetectLog: TableLogBuffer,
    @FaceAuthTableLog private val faceAuthLog: TableLogBuffer,
    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
    private val displayStateInteractor: DisplayStateInteractor,
    private val featureFlags: FeatureFlags,
    dumpManager: DumpManager,
) : DeviceEntryFaceAuthRepository, Dumpable {
@@ -362,6 +364,16 @@ constructor(

    private fun gatingConditionsForAuthAndDetect(): Array<Pair<Flow<Boolean>, String>> {
        return arrayOf(
            Pair(
                and(
                        displayStateInteractor.isDefaultDisplayOff,
                        keyguardRepository.wakefulness.map { it.isAwake() },
                    )
                    .isFalse(),
                // this can happen if an app is requesting for screen off, the display can
                // turn off without wakefulness.isStartingToSleepOrAsleep calls
                "displayIsNotOffWhileAwake",
            ),
            Pair(
                biometricSettingsRepository.isFaceAuthEnrolledAndEnabled,
                "isFaceAuthEnrolledAndEnabled"
+1 −1
Original line number Diff line number Diff line
@@ -36,7 +36,7 @@ data class WakefulnessModel(

    private fun isAsleep() = state == ASLEEP

    private fun isAwake() = state == AWAKE
    fun isAwake() = state == AWAKE

    fun isStartingToWakeOrAwake() = isStartingToWake() || isAwake()

Loading