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.settings.network 18 19 import android.content.Context 20 import android.net.NetworkCapabilities 21 import android.net.wifi.WifiInfo 22 import android.net.wifi.WifiManager 23 import android.provider.Settings 24 import android.util.Log 25 import androidx.annotation.DrawableRes 26 import com.android.settings.R 27 import com.android.settings.network.telephony.DataSubscriptionRepository 28 import com.android.settings.wifi.WifiSummaryRepository 29 import com.android.settings.wifi.repository.WifiRepository 30 import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow 31 import kotlinx.coroutines.Dispatchers 32 import kotlinx.coroutines.ExperimentalCoroutinesApi 33 import kotlinx.coroutines.flow.Flow 34 import kotlinx.coroutines.flow.combine 35 import kotlinx.coroutines.flow.conflate 36 import kotlinx.coroutines.flow.flatMapLatest 37 import kotlinx.coroutines.flow.flowOf 38 import kotlinx.coroutines.flow.flowOn 39 import kotlinx.coroutines.flow.map 40 import kotlinx.coroutines.flow.onEach 41 42 @OptIn(ExperimentalCoroutinesApi::class) 43 class InternetPreferenceRepository( 44 private val context: Context, 45 private val connectivityRepository: ConnectivityRepository = ConnectivityRepository(context), 46 private val wifiSummaryRepository: WifiSummaryRepository = WifiSummaryRepository(context), 47 private val dataSubscriptionRepository: DataSubscriptionRepository = 48 DataSubscriptionRepository(context), 49 private val wifiRepository: WifiRepository = WifiRepository(context), 50 private val airplaneModeOnFlow: Flow<Boolean> = 51 context.settingsGlobalBooleanFlow(Settings.Global.AIRPLANE_MODE_ON), 52 ) { 53 54 data class DisplayInfo( 55 val summary: String, 56 @DrawableRes val iconResId: Int, 57 ) 58 59 fun displayInfoFlow(): Flow<DisplayInfo> = 60 connectivityRepository 61 .networkCapabilitiesFlow() 62 .flatMapLatest { capabilities -> capabilities.displayInfoFlow() } 63 .onEach { Log.d(TAG, "displayInfoFlow: $it") } 64 .conflate() 65 .flowOn(Dispatchers.Default) 66 67 private fun NetworkCapabilities.displayInfoFlow(): Flow<DisplayInfo> { 68 if ( 69 hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && 70 hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) 71 ) { 72 val transportInfo = transportInfo 73 if (transportInfo is WifiInfo && transportInfo.isCarrierMerged) { 74 Log.i(TAG, "Detect a merged carrier Wi-Fi connected.") 75 return cellularDisplayInfoFlow() 76 } 77 for (transportType in transportTypes) { 78 when (transportType) { 79 NetworkCapabilities.TRANSPORT_WIFI -> return wifiDisplayInfoFlow() 80 NetworkCapabilities.TRANSPORT_CELLULAR -> return cellularDisplayInfoFlow() 81 NetworkCapabilities.TRANSPORT_ETHERNET -> return ethernetDisplayInfoFlow() 82 } 83 } 84 } 85 return defaultDisplayInfoFlow() 86 } 87 88 private fun wifiDisplayInfoFlow() = 89 wifiSummaryRepository.summaryFlow().map { summary -> 90 DisplayInfo( 91 summary = summary, 92 iconResId = R.drawable.ic_wifi_signal_4, 93 ) 94 } 95 96 private fun cellularDisplayInfoFlow() = 97 dataSubscriptionRepository.dataSummaryFlow().map { summary -> 98 DisplayInfo( 99 summary = summary, 100 iconResId = R.drawable.ic_network_cell, 101 ) 102 } 103 104 private fun ethernetDisplayInfoFlow() = 105 flowOf( 106 DisplayInfo( 107 summary = context.getString(R.string.to_switch_networks_disconnect_ethernet), 108 iconResId = R.drawable.ic_settings_ethernet, 109 ) 110 ) 111 112 private fun defaultDisplayInfoFlow(): Flow<DisplayInfo> = 113 combine( 114 airplaneModeOnFlow, 115 wifiRepository.wifiStateFlow(), 116 ) { airplaneModeOn: Boolean, wifiState: Int -> 117 if (airplaneModeOn && wifiState != WifiManager.WIFI_STATE_ENABLED) { 118 DisplayInfo( 119 summary = context.getString(R.string.condition_airplane_title), 120 iconResId = R.drawable.ic_no_internet_unavailable, 121 ) 122 } else { 123 DisplayInfo( 124 summary = context.getString(R.string.networks_available), 125 iconResId = R.drawable.ic_no_internet_available, 126 ) 127 } 128 } 129 130 private companion object { 131 private const val TAG = "InternetPreferenceRepo" 132 } 133 } 134