• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2022 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.wifi.ui.viewmodel
18 
19 import android.content.Context
20 import com.android.systemui.Flags.statusBarStaticInoutIndicators
21 import com.android.systemui.dagger.SysUISingleton
22 import com.android.systemui.dagger.qualifiers.Background
23 import com.android.systemui.log.table.TableLogBuffer
24 import com.android.systemui.log.table.logDiffsForTable
25 import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
26 import com.android.systemui.statusbar.pipeline.dagger.StatusBarPipelineModule.Companion.FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON
27 import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
28 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
29 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
30 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
31 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
32 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
33 import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
34 import java.util.function.Supplier
35 import javax.inject.Inject
36 import javax.inject.Named
37 import kotlinx.coroutines.CoroutineScope
38 import kotlinx.coroutines.flow.Flow
39 import kotlinx.coroutines.flow.SharingStarted
40 import kotlinx.coroutines.flow.StateFlow
41 import kotlinx.coroutines.flow.combine
42 import kotlinx.coroutines.flow.flowOf
43 import kotlinx.coroutines.flow.map
44 import kotlinx.coroutines.flow.stateIn
45 
46 /**
47  * Models the UI state for the status bar wifi icon.
48  *
49  * This is a singleton so that we don't have duplicate logs and should *not* be used directly to
50  * control views. Instead, use an instance of [LocationBasedWifiViewModel]. See
51  * [LocationBasedWifiViewModel.viewModelForLocation].
52  */
53 @SysUISingleton
54 class WifiViewModel
55 @Inject
56 constructor(
57     airplaneModeViewModel: AirplaneModeViewModel,
58     // TODO(b/238425913): The wifi icon shouldn't need to consume mobile information. A
59     //  container-level view model should do the work instead.
60     @Named(FIRST_MOBILE_SUB_SHOWING_NETWORK_TYPE_ICON)
61     shouldShowSignalSpacerProvider: Supplier<Flow<Boolean>>,
62     connectivityConstants: ConnectivityConstants,
63     private val context: Context,
64     @WifiTableLog wifiTableLogBuffer: TableLogBuffer,
65     interactor: WifiInteractor,
66     @Background scope: CoroutineScope,
67     wifiConstants: WifiConstants,
68 ) : WifiViewModelCommon {
69     override val wifiIcon: StateFlow<WifiIcon> =
70         combine(
71                 interactor.isEnabled,
72                 interactor.isDefault,
73                 interactor.isForceHidden,
74                 interactor.wifiNetwork,
75             ) { isEnabled, isDefault, isForceHidden, wifiNetwork ->
76                 if (!isEnabled || isForceHidden || wifiNetwork is WifiNetworkModel.CarrierMerged) {
77                     return@combine WifiIcon.Hidden
78                 }
79 
80                 // Don't show any hotspot info in the status bar.
81                 val icon = WifiIcon.fromModel(wifiNetwork, context, showHotspotInfo = false)
82 
83                 return@combine when {
84                     isDefault -> icon
85                     wifiConstants.alwaysShowIconIfEnabled -> icon
86                     !connectivityConstants.hasDataCapabilities -> icon
87                     // See b/272509965: Even if we have an active and validated wifi network, we
88                     // don't want to show the icon if wifi isn't the default network.
89                     else -> WifiIcon.Hidden
90                 }
91             }
92             .logDiffsForTable(wifiTableLogBuffer, initialValue = WifiIcon.Hidden)
93             .stateIn(
94                 scope,
95                 started = SharingStarted.WhileSubscribed(),
96                 initialValue = WifiIcon.Hidden,
97             )
98 
99     /** The wifi activity status. Null if we shouldn't display the activity status. */
100     private val activity: Flow<DataActivityModel?> =
101         if (!connectivityConstants.shouldShowActivityConfig) {
102                 flowOf(null)
103             } else {
104                 combine(interactor.activity, interactor.ssid) { activity, ssid ->
105                     when (ssid) {
106                         null -> null
107                         else -> activity
108                     }
109                 }
110             }
111             .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
112 
113     override val isActivityInViewVisible: Flow<Boolean> =
114         activity
115             .map { it?.hasActivityIn ?: false }
116             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
117 
118     override val isActivityOutViewVisible: Flow<Boolean> =
119         activity
120             .map { it?.hasActivityOut ?: false }
121             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
122 
123     override val isActivityContainerVisible: Flow<Boolean> =
124         if (statusBarStaticInoutIndicators()) {
125                 flowOf(connectivityConstants.shouldShowActivityConfig)
126             } else {
127                 activity.map { it != null && (it.hasActivityIn || it.hasActivityOut) }
128             }
129             .stateIn(scope, SharingStarted.WhileSubscribed(), false)
130 
131     // TODO(b/238425913): It isn't ideal for the wifi icon to need to know about whether the
132     //  airplane icon is visible. Instead, we should have a parent StatusBarSystemIconsViewModel
133     //  that appropriately knows about both icons and sets the padding appropriately.
134     override val isAirplaneSpacerVisible: Flow<Boolean> =
135         airplaneModeViewModel.isAirplaneModeIconVisible
136 
137     override val isSignalSpacerVisible: Flow<Boolean> = shouldShowSignalSpacerProvider.get()
138 }
139