1 /* <lambda>null2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.keyguard.domain.interactor 18 19 import android.content.Context 20 import android.util.Log 21 import com.android.keyguard.KeyguardUpdateMonitor 22 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor 23 import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor 24 import com.android.systemui.dagger.SysUISingleton 25 import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository 26 import com.android.systemui.res.R 27 import com.android.systemui.scene.domain.interactor.SceneInteractor 28 import com.android.systemui.scene.shared.flag.SceneContainerFlag 29 import com.android.systemui.scene.shared.model.Overlays 30 import com.android.systemui.shade.ShadeDisplayAware 31 import javax.inject.Inject 32 import kotlinx.coroutines.flow.Flow 33 import kotlinx.coroutines.flow.combine 34 import kotlinx.coroutines.flow.distinctUntilChanged 35 import kotlinx.coroutines.flow.filter 36 import kotlinx.coroutines.flow.filterNotNull 37 import kotlinx.coroutines.flow.flowOf 38 import kotlinx.coroutines.flow.map 39 import kotlinx.coroutines.flow.merge 40 import kotlinx.coroutines.flow.onEach 41 42 /** 43 * Encapsulates business logic for device entry events that impact the side fingerprint sensor 44 * overlay. 45 */ 46 @SysUISingleton 47 class DeviceEntrySideFpsOverlayInteractor 48 @Inject 49 constructor( 50 @ShadeDisplayAware private val context: Context, 51 deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository, 52 private val sceneInteractor: SceneInteractor, 53 private val primaryBouncerInteractor: PrimaryBouncerInteractor, 54 alternateBouncerInteractor: AlternateBouncerInteractor, 55 private val keyguardUpdateMonitor: KeyguardUpdateMonitor, 56 ) { 57 58 private val isSideFpsIndicatorOnPrimaryBouncerEnabled: Boolean 59 get() = context.resources.getBoolean(R.bool.config_show_sidefps_hint_on_bouncer) 60 61 private val isBouncerOverlayActive: Flow<Boolean> = 62 if (SceneContainerFlag.isEnabled) { 63 sceneInteractor.currentOverlays.map { Overlays.Bouncer in it }.distinctUntilChanged() 64 } else { 65 flowOf(false) 66 } 67 68 private val showIndicatorForPrimaryBouncer: Flow<Boolean> = 69 merge( 70 // Legacy bouncer visibility changes. 71 primaryBouncerInteractor.isShowing, 72 primaryBouncerInteractor.startingToHide, 73 primaryBouncerInteractor.startingDisappearAnimation.filterNotNull(), 74 // Bouncer scene visibility changes. 75 isBouncerOverlayActive, 76 deviceEntryFingerprintAuthRepository.shouldUpdateIndicatorVisibility.filter { it }, 77 ) 78 .map { 79 isBouncerActive() && 80 isSideFpsIndicatorOnPrimaryBouncerEnabled && 81 keyguardUpdateMonitor.isFingerprintDetectionRunning && 82 keyguardUpdateMonitor.isUnlockingWithFingerprintAllowed 83 } 84 .onEach { Log.d(TAG, "showIndicatorForPrimaryBouncer updated: $it") } 85 86 private val showIndicatorForAlternateBouncer: Flow<Boolean> = 87 // Note: this interactor internally verifies that SideFPS is enabled and running. 88 alternateBouncerInteractor.isVisible.onEach { 89 Log.d(TAG, "showIndicatorForAlternateBouncer updated: $it") 90 } 91 92 /** 93 * Indicates whether the primary or alternate bouncers request showing the side fingerprint 94 * sensor indicator. 95 */ 96 val showIndicatorForDeviceEntry: Flow<Boolean> = 97 combine(showIndicatorForPrimaryBouncer, showIndicatorForAlternateBouncer) { 98 showForPrimaryBouncer, 99 showForAlternateBouncer -> 100 showForPrimaryBouncer || showForAlternateBouncer 101 } 102 .distinctUntilChanged() 103 .onEach { Log.d(TAG, "showIndicatorForDeviceEntry updated: $it") } 104 105 private fun isBouncerActive(): Boolean { 106 if (SceneContainerFlag.isEnabled) { 107 return Overlays.Bouncer in sceneInteractor.currentOverlays.value 108 } 109 return primaryBouncerInteractor.isBouncerShowing() && 110 !primaryBouncerInteractor.isAnimatingAway() 111 } 112 113 companion object { 114 private const val TAG = "DeviceEntrySideFpsOverlayInteractor" 115 } 116 } 117