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.statusbar.pipeline.shared.ui.viewmodel 18 19 import com.android.systemui.dagger.SysUISingleton 20 import com.android.systemui.dagger.qualifiers.Application 21 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor 22 import com.android.systemui.keyguard.shared.model.Edge 23 import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING 24 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN 25 import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED 26 import com.android.systemui.keyguard.shared.model.TransitionState 27 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel 28 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel 29 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor 30 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor 31 import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor 32 import javax.inject.Inject 33 import kotlinx.coroutines.CoroutineScope 34 import kotlinx.coroutines.flow.Flow 35 import kotlinx.coroutines.flow.SharingStarted 36 import kotlinx.coroutines.flow.StateFlow 37 import kotlinx.coroutines.flow.combine 38 import kotlinx.coroutines.flow.distinctUntilChanged 39 import kotlinx.coroutines.flow.emptyFlow 40 import kotlinx.coroutines.flow.filter 41 import kotlinx.coroutines.flow.map 42 import kotlinx.coroutines.flow.stateIn 43 44 /** 45 * A view model that manages the visibility of the [CollapsedStatusBarFragment] based on the device 46 * state. 47 * 48 * Right now, most of the status bar visibility management is actually in 49 * [CollapsedStatusBarFragment.calculateInternalModel], which uses 50 * [CollapsedStatusBarFragment.shouldHideNotificationIcons] and 51 * [StatusBarHideIconsForBouncerManager]. We should move those pieces of logic to this class instead 52 * so that it's all in one place and easily testable outside of the fragment. 53 */ 54 interface CollapsedStatusBarViewModel { 55 /** 56 * True if the device is currently transitioning from lockscreen to occluded and false 57 * otherwise. 58 */ 59 val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean> 60 61 /** Emits whenever a transition from lockscreen to dream has started. */ 62 val transitionFromLockscreenToDreamStartedEvent: Flow<Unit> 63 64 /** The ongoing activity chip that should be shown on the left-hand side of the status bar. */ 65 val ongoingActivityChip: StateFlow<OngoingActivityChipModel> 66 67 /** 68 * Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where 69 * status bar and navigation icons dim. In this mode, a notification dot appears where the 70 * notification icons would appear if they would be shown outside of this mode. 71 * 72 * This flow tells when to show or hide the notification dot in the status bar to indicate 73 * whether there are notifications when the device is in 74 * [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE]. 75 */ 76 fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> 77 } 78 79 @SysUISingleton 80 class CollapsedStatusBarViewModelImpl 81 @Inject 82 constructor( 83 private val lightsOutInteractor: LightsOutInteractor, 84 private val notificationsInteractor: ActiveNotificationsInteractor, 85 keyguardTransitionInteractor: KeyguardTransitionInteractor, 86 ongoingActivityChipsViewModel: OngoingActivityChipsViewModel, 87 @Application coroutineScope: CoroutineScope, 88 ) : CollapsedStatusBarViewModel { 89 override val isTransitioningFromLockscreenToOccluded: StateFlow<Boolean> = 90 keyguardTransitionInteractor 91 .isInTransition(Edge.create(from = LOCKSCREEN, to = OCCLUDED)) 92 .stateIn(coroutineScope, SharingStarted.WhileSubscribed(), initialValue = false) 93 94 override val transitionFromLockscreenToDreamStartedEvent: Flow<Unit> = 95 keyguardTransitionInteractor 96 .transition(Edge.create(from = LOCKSCREEN, to = DREAMING)) <lambda>null97 .filter { it.transitionState == TransitionState.STARTED } <lambda>null98 .map {} 99 100 override val ongoingActivityChip = ongoingActivityChipsViewModel.chip 101 areNotificationsLightsOutnull102 override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = 103 if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) { 104 emptyFlow() 105 } else { 106 combine( 107 notificationsInteractor.areAnyNotificationsPresent, 108 lightsOutInteractor.isLowProfile(displayId), hasNotificationsnull109 ) { hasNotifications, isLowProfile -> 110 hasNotifications && isLowProfile 111 } 112 .distinctUntilChanged() 113 } 114 } 115