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.ui.viewmodel 18 19 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor 20 import com.android.systemui.dagger.qualifiers.Background 21 import com.android.systemui.dagger.qualifiers.Main 22 import com.android.systemui.doze.util.BurnInHelperWrapper 23 import com.android.systemui.keyguard.KeyguardBottomAreaRefactor 24 import com.android.systemui.keyguard.MigrateClocksToBlueprint 25 import com.android.systemui.keyguard.domain.interactor.BurnInInteractor 26 import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor 27 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor 28 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor 29 import com.android.systemui.keyguard.shared.model.BurnInModel 30 import com.android.systemui.keyguard.shared.model.KeyguardState 31 import com.android.systemui.res.R 32 import javax.inject.Inject 33 import kotlin.coroutines.CoroutineContext 34 import kotlinx.coroutines.CoroutineDispatcher 35 import kotlinx.coroutines.ExperimentalCoroutinesApi 36 import kotlinx.coroutines.flow.Flow 37 import kotlinx.coroutines.flow.combine 38 import kotlinx.coroutines.flow.distinctUntilChanged 39 import kotlinx.coroutines.flow.flowOn 40 import kotlinx.coroutines.flow.map 41 42 /** View-model for the keyguard indication area view */ 43 class KeyguardIndicationAreaViewModel 44 @Inject 45 constructor( 46 private val keyguardInteractor: KeyguardInteractor, 47 private val bottomAreaInteractor: KeyguardBottomAreaInteractor, 48 keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel, 49 private val burnInHelperWrapper: BurnInHelperWrapper, 50 private val burnInInteractor: BurnInInteractor, 51 private val shortcutsCombinedViewModel: KeyguardQuickAffordancesCombinedViewModel, 52 configurationInteractor: ConfigurationInteractor, 53 keyguardTransitionInteractor: KeyguardTransitionInteractor, 54 @Background private val backgroundCoroutineContext: CoroutineContext, 55 @Main private val mainDispatcher: CoroutineDispatcher, 56 ) { 57 58 /** Notifies when a new configuration is set */ 59 val configurationChange: Flow<Unit> = configurationInteractor.onAnyConfigurationChange 60 61 /** An observable for the alpha level for the entire bottom area. */ 62 val alpha: Flow<Float> = keyguardBottomAreaViewModel.alpha 63 64 /** An observable for whether the indication area should be padded. */ 65 val isIndicationAreaPadded: Flow<Boolean> = 66 if (KeyguardBottomAreaRefactor.isEnabled) { 67 combine(shortcutsCombinedViewModel.startButton, shortcutsCombinedViewModel.endButton) { 68 startButtonModel, 69 endButtonModel -> 70 startButtonModel.isVisible || endButtonModel.isVisible 71 } 72 .distinctUntilChanged() 73 } else { 74 combine( 75 keyguardBottomAreaViewModel.startButton, 76 keyguardBottomAreaViewModel.endButton 77 ) { startButtonModel, endButtonModel -> 78 startButtonModel.isVisible || endButtonModel.isVisible 79 } 80 .distinctUntilChanged() 81 } 82 83 @OptIn(ExperimentalCoroutinesApi::class) 84 private val burnIn: Flow<BurnInModel> = 85 combine( 86 burnInInteractor.burnIn( 87 xDimenResourceId = R.dimen.burn_in_prevention_offset_x, 88 yDimenResourceId = R.dimen.default_burn_in_prevention_offset, 89 ), 90 keyguardTransitionInteractor.transitionValue(KeyguardState.AOD), 91 ) { burnIn, aodTransitionValue -> 92 BurnInModel( 93 (burnIn.translationX * aodTransitionValue).toInt(), 94 (burnIn.translationY * aodTransitionValue).toInt(), 95 burnIn.scale, 96 burnIn.scaleClockOnly, 97 ) 98 } 99 .distinctUntilChanged() 100 .flowOn(backgroundCoroutineContext) 101 102 /** An observable for the x-offset by which the indication area should be translated. */ 103 val indicationAreaTranslationX: Flow<Float> = 104 if (MigrateClocksToBlueprint.isEnabled || KeyguardBottomAreaRefactor.isEnabled) { 105 burnIn.map { it.translationX.toFloat() }.flowOn(mainDispatcher) 106 } else { 107 bottomAreaInteractor.clockPosition.map { it.x.toFloat() }.distinctUntilChanged() 108 } 109 110 /** Returns an observable for the y-offset by which the indication area should be translated. */ 111 fun indicationAreaTranslationY(defaultBurnInOffset: Int): Flow<Float> { 112 return if (MigrateClocksToBlueprint.isEnabled) { 113 burnIn.map { it.translationY.toFloat() }.flowOn(mainDispatcher) 114 } else { 115 keyguardInteractor.dozeAmount 116 .map { dozeAmount -> 117 dozeAmount * 118 (burnInHelperWrapper.burnInOffset( 119 /* amplitude = */ defaultBurnInOffset * 2, 120 /* xAxis= */ false, 121 ) - defaultBurnInOffset) 122 } 123 .distinctUntilChanged() 124 } 125 } 126 } 127