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