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 18 package com.android.systemui.keyguard.ui.viewmodel 19 20 import android.content.Context 21 import com.android.settingslib.Utils 22 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor 23 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor 24 import com.android.systemui.dagger.SysUISingleton 25 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor 26 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor 27 import com.android.systemui.keyguard.shared.model.KeyguardState 28 import com.android.systemui.keyguard.ui.view.DeviceEntryIconView 29 import com.android.systemui.res.R 30 import javax.inject.Inject 31 import kotlin.math.roundToInt 32 import kotlinx.coroutines.ExperimentalCoroutinesApi 33 import kotlinx.coroutines.flow.Flow 34 import kotlinx.coroutines.flow.combine 35 import kotlinx.coroutines.flow.distinctUntilChanged 36 import kotlinx.coroutines.flow.flatMapLatest 37 import kotlinx.coroutines.flow.flowOf 38 import kotlinx.coroutines.flow.map 39 import kotlinx.coroutines.flow.onStart 40 41 /** Models the UI state for the device entry icon foreground view (displayed icon). */ 42 @ExperimentalCoroutinesApi 43 @SysUISingleton 44 class DeviceEntryForegroundViewModel 45 @Inject 46 constructor( 47 val context: Context, 48 configurationInteractor: ConfigurationInteractor, 49 deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor, 50 transitionInteractor: KeyguardTransitionInteractor, 51 deviceEntryIconViewModel: DeviceEntryIconViewModel, 52 udfpsOverlayInteractor: UdfpsOverlayInteractor, 53 ) { 54 private val isShowingAodOrDozing: Flow<Boolean> = 55 combine( 56 transitionInteractor.startedKeyguardState, 57 transitionInteractor.transitionValue(KeyguardState.DOZING), 58 ) { startedKeyguardState, dozingTransitionValue -> 59 startedKeyguardState == KeyguardState.AOD || dozingTransitionValue == 1f 60 } 61 62 private fun getColor(usingBackgroundProtection: Boolean): Int { 63 return if (usingBackgroundProtection) { 64 Utils.getColorAttrDefaultColor(context, android.R.attr.textColorPrimary) 65 } else { 66 Utils.getColorAttrDefaultColor(context, R.attr.wallpaperTextColorAccent) 67 } 68 } 69 70 // While dozing, the display can show the AOD UI; show the AOD udfps when dozing 71 private val useAodIconVariant: Flow<Boolean> = 72 deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfspEnrolled -> 73 if (udfspEnrolled) { 74 isShowingAodOrDozing.distinctUntilChanged() 75 } else { 76 flowOf(false) 77 } 78 } 79 80 private val color: Flow<Int> = 81 useAodIconVariant 82 .flatMapLatest { useAodVariant -> 83 if (useAodVariant) { 84 flowOf(android.graphics.Color.WHITE) 85 } else { 86 deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBgProtection 87 -> 88 configurationInteractor.onAnyConfigurationChange 89 .map { getColor(useBgProtection) } 90 .onStart { emit(getColor(useBgProtection)) } 91 } 92 } 93 } 94 .distinctUntilChanged() 95 96 private val padding: Flow<Int> = 97 deviceEntryUdfpsInteractor.isUdfpsSupported.flatMapLatest { udfpsSupported -> 98 if (udfpsSupported) { 99 udfpsOverlayInteractor.iconPadding 100 } else { 101 configurationInteractor.scaleForResolution.map { scale -> 102 (context.resources.getDimensionPixelSize(R.dimen.lock_icon_padding) * scale) 103 .roundToInt() 104 } 105 } 106 } 107 108 val viewModel: Flow<ForegroundIconViewModel> = 109 combine( 110 deviceEntryIconViewModel.iconType, 111 useAodIconVariant, 112 color, 113 padding, 114 ) { iconType, useAodVariant, color, padding -> 115 ForegroundIconViewModel( 116 type = iconType, 117 useAodVariant = useAodVariant, 118 tint = color, 119 padding = padding, 120 ) 121 } 122 123 data class ForegroundIconViewModel( 124 val type: DeviceEntryIconView.IconType, 125 val useAodVariant: Boolean, 126 val tint: Int, 127 val padding: Int, 128 ) 129 } 130