• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 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.mobile.ui.viewmodel
18 
19 import androidx.compose.runtime.State as ComposeState
20 import androidx.compose.runtime.getValue
21 import com.android.systemui.Flags
22 import com.android.systemui.KairosActivatable
23 import com.android.systemui.KairosBuilder
24 import com.android.systemui.activated
25 import com.android.systemui.dagger.SysUISingleton
26 import com.android.systemui.flags.FeatureFlagsClassic
27 import com.android.systemui.kairos.BuildScope
28 import com.android.systemui.kairos.BuildSpec
29 import com.android.systemui.kairos.ExperimentalKairosApi
30 import com.android.systemui.kairos.Incremental
31 import com.android.systemui.kairos.State as KairosState
32 import com.android.systemui.kairos.State
33 import com.android.systemui.kairos.buildSpec
34 import com.android.systemui.kairos.combine
35 import com.android.systemui.kairos.flatten
36 import com.android.systemui.kairos.map
37 import com.android.systemui.kairos.mapValues
38 import com.android.systemui.kairos.stateOf
39 import com.android.systemui.kairosBuilder
40 import com.android.systemui.statusbar.phone.StatusBarLocation
41 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
42 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorKairos
43 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorKairos
44 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger
45 import com.android.systemui.statusbar.pipeline.mobile.ui.VerboseMobileViewLogger
46 import com.android.systemui.statusbar.pipeline.mobile.ui.view.ModernStatusBarMobileView
47 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
48 import com.android.systemui.util.composable.kairos.toComposeState
49 import dagger.Provides
50 import dagger.multibindings.ElementsIntoSet
51 import javax.inject.Inject
52 import javax.inject.Provider
53 
54 /**
55  * View model for describing the system's current mobile cellular connections. The result is a list
56  * of [MobileIconViewModelKairos]s which describe the individual icons and can be bound to
57  * [ModernStatusBarMobileView].
58  */
59 @ExperimentalKairosApi
60 @SysUISingleton
61 class MobileIconsViewModelKairos
62 @Inject
63 constructor(
64     val logger: MobileViewLogger,
65     private val verboseLogger: VerboseMobileViewLogger,
66     private val interactor: MobileIconsInteractorKairos,
67     private val airplaneModeInteractor: AirplaneModeInteractor,
68     private val constants: ConnectivityConstants,
69     private val flags: FeatureFlagsClassic,
70 ) : KairosBuilder by kairosBuilder() {
71 
72     val activeSubscriptionId: State<Int?>
73         get() = interactor.activeDataIconInteractor.map { it?.subscriptionId }
74 
75     val subscriptionIds: KairosState<List<Int>> =
76         interactor.filteredSubscriptions.map { subscriptions ->
77             subscriptions.map { it.subscriptionId }
78         }
79 
80     val icons: Incremental<Int, MobileIconViewModelKairos> = buildIncremental {
81         interactor.icons
82             .mapValues { (subId, icon) -> buildSpec { commonViewModel(subId, icon) } }
83             .applyLatestSpecForKey()
84     }
85 
86     /** Whether the mobile sub that's displayed first visually is showing its network type icon. */
87     val firstMobileSubShowingNetworkTypeIcon: KairosState<Boolean> = buildState {
88         combine(subscriptionIds.map { it.lastOrNull() }, icons) { lastId, icons ->
89                 icons[lastId]?.networkTypeIcon?.map { it != null } ?: stateOf(false)
90             }
91             .flatten()
92     }
93 
94     val isStackable: KairosState<Boolean>
95         get() = interactor.isStackable
96 
97     fun viewModelForSub(
98         subId: Int,
99         location: StatusBarLocation,
100     ): BuildSpec<LocationBasedMobileViewModelKairos> = buildSpec {
101         val iconInteractor =
102             interactor.icons.sample().getOrElse(subId) { error("Unknown subscription id: $subId") }
103         val commonViewModel =
104             icons.sample().getOrElse(subId) { error("Unknown subscription id: $subId") }
105         LocationBasedMobileViewModelKairos.viewModelForLocation(
106             commonViewModel,
107             iconInteractor,
108             verboseLogger,
109             location,
110         )
111     }
112 
113     fun shadeCarrierGroupIcon(subId: Int): BuildSpec<ShadeCarrierGroupMobileIconViewModelKairos> =
114         buildSpec {
115             val iconInteractor =
116                 interactor.icons.sample().getOrElse(subId) {
117                     error("Unknown subscription id: $subId")
118                 }
119             val commonViewModel =
120                 icons.sample().getOrElse(subId) { error("Unknown subscription id: $subId") }
121             ShadeCarrierGroupMobileIconViewModelKairos(commonViewModel, iconInteractor)
122         }
123 
124     private fun BuildScope.commonViewModel(subId: Int, iconInteractor: MobileIconInteractorKairos) =
125         activated {
126             MobileIconViewModelKairos(
127                 subscriptionId = subId,
128                 iconInteractor = iconInteractor,
129                 airplaneModeInteractor = airplaneModeInteractor,
130                 constants = constants,
131                 flags = flags,
132             )
133         }
134 
135     @dagger.Module
136     object Module {
137         @Provides
138         @ElementsIntoSet
139         fun bindKairosActivatable(
140             impl: Provider<MobileIconsViewModelKairos>
141         ): Set<@JvmSuppressWildcards KairosActivatable> =
142             if (Flags.statusBarMobileIconKairos()) setOf(impl.get()) else emptySet()
143     }
144 }
145 
146 @ExperimentalKairosApi
147 class MobileIconsViewModelKairosComposeWrapper(
148     icons: ComposeState<Map<Int, MobileIconViewModelKairos>>,
149     val logger: MobileViewLogger,
150 ) {
151     val icons: Map<Int, MobileIconViewModelKairos> by icons
152 }
153 
154 @ExperimentalKairosApi
<lambda>null155 fun MobileIconsViewModelKairos.composeWrapper(): BuildSpec<MobileIconsViewModelKairosComposeWrapper> = buildSpec {
156     MobileIconsViewModelKairosComposeWrapper(
157         icons = toComposeState(icons),
158         logger = logger,
159     )
160 }
161