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.Application 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 @Application private val 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( 93 wifiTableLogBuffer, 94 columnPrefix = "", 95 initialValue = WifiIcon.Hidden, 96 ) 97 .stateIn( 98 scope, 99 started = SharingStarted.WhileSubscribed(), 100 initialValue = WifiIcon.Hidden 101 ) 102 103 /** The wifi activity status. Null if we shouldn't display the activity status. */ 104 private val activity: Flow<DataActivityModel?> = 105 if (!connectivityConstants.shouldShowActivityConfig) { 106 flowOf(null) 107 } else { 108 combine(interactor.activity, interactor.ssid) { activity, ssid -> 109 when (ssid) { 110 null -> null 111 else -> activity 112 } 113 } 114 } 115 .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null) 116 117 override val isActivityInViewVisible: Flow<Boolean> = 118 activity 119 .map { it?.hasActivityIn ?: false } 120 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 121 122 override val isActivityOutViewVisible: Flow<Boolean> = 123 activity 124 .map { it?.hasActivityOut ?: false } 125 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 126 127 override val isActivityContainerVisible: Flow<Boolean> = 128 if (statusBarStaticInoutIndicators()) { 129 flowOf(connectivityConstants.shouldShowActivityConfig) 130 } else { 131 activity.map { it != null && (it.hasActivityIn || it.hasActivityOut) } 132 } 133 .stateIn(scope, SharingStarted.WhileSubscribed(), false) 134 135 // TODO(b/238425913): It isn't ideal for the wifi icon to need to know about whether the 136 // airplane icon is visible. Instead, we should have a parent StatusBarSystemIconsViewModel 137 // that appropriately knows about both icons and sets the padding appropriately. 138 override val isAirplaneSpacerVisible: Flow<Boolean> = 139 airplaneModeViewModel.isAirplaneModeIconVisible 140 141 override val isSignalSpacerVisible: Flow<Boolean> = shouldShowSignalSpacerProvider.get() 142 } 143