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