1 /* 2 * 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.wifi 18 19 import android.content.BroadcastReceiver 20 import android.content.Context 21 import android.content.Intent 22 import android.content.IntentFilter 23 import android.net.wifi.WifiManager 24 import android.os.UserManager 25 import android.provider.Settings 26 import android.util.Log 27 import android.widget.Toast 28 import androidx.preference.Preference 29 import androidx.preference.Preference.OnPreferenceChangeListener 30 import com.android.settings.PreferenceRestrictionMixin 31 import com.android.settings.R 32 import com.android.settings.network.SatelliteRepository 33 import com.android.settings.network.SatelliteWarningDialogActivity 34 import com.android.settingslib.RestrictedSwitchPreference 35 import com.android.settingslib.WirelessUtils 36 import com.android.settingslib.datastore.AbstractKeyedDataObservable 37 import com.android.settingslib.datastore.DataChangeReason 38 import com.android.settingslib.datastore.KeyValueStore 39 import com.android.settingslib.metadata.PreferenceLifecycleProvider 40 import com.android.settingslib.metadata.PreferenceMetadata 41 import com.android.settingslib.metadata.ReadWritePermit 42 import com.android.settingslib.metadata.SensitivityLevel 43 import com.android.settingslib.metadata.SwitchPreference 44 import com.android.settingslib.preference.SwitchPreferenceBinding 45 import java.util.concurrent.Executors 46 import java.util.concurrent.TimeUnit 47 48 // LINT.IfChange 49 class WifiSwitchPreference : 50 SwitchPreference(KEY, R.string.wifi), 51 SwitchPreferenceBinding, 52 OnPreferenceChangeListener, 53 PreferenceLifecycleProvider, 54 PreferenceRestrictionMixin { 55 56 override val keywords: Int 57 get() = R.string.keywords_wifi 58 isEnablednull59 override fun isEnabled(context: Context) = super<PreferenceRestrictionMixin>.isEnabled(context) 60 61 override val restrictionKeys 62 get() = arrayOf(UserManager.DISALLOW_CHANGE_WIFI_STATE) 63 64 override val useAdminDisabledSummary: Boolean 65 get() = true 66 67 override fun createWidget(context: Context) = RestrictedSwitchPreference(context) 68 69 override fun bind(preference: Preference, metadata: PreferenceMetadata) { 70 super.bind(preference, metadata) 71 preference.onPreferenceChangeListener = this 72 } 73 onPreferenceChangenull74 override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { 75 val context = preference.context 76 77 // Show dialog and do nothing under satellite mode. 78 if (context.isSatelliteOn()) { 79 context.startActivity( 80 Intent(context, SatelliteWarningDialogActivity::class.java) 81 .putExtra( 82 SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, 83 SatelliteWarningDialogActivity.TYPE_IS_WIFI, 84 ) 85 ) 86 return false 87 } 88 89 // Show toast message if Wi-Fi is not allowed in airplane mode 90 if (newValue == true && !context.isRadioAllowed()) { 91 Toast.makeText(context, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show() 92 return false 93 } 94 95 return true 96 } 97 getReadPermitnull98 override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) = 99 ReadWritePermit.ALLOW 100 101 override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) = 102 when { 103 (value == true && !context.isRadioAllowed()) || context.isSatelliteOn() -> 104 ReadWritePermit.DISALLOW 105 else -> ReadWritePermit.ALLOW 106 } 107 108 override val sensitivityLevel 109 get() = SensitivityLevel.LOW_SENSITIVITY 110 storagenull111 override fun storage(context: Context): KeyValueStore = WifiSwitchStore(context) 112 113 @Suppress("UNCHECKED_CAST") 114 private class WifiSwitchStore(private val context: Context) : 115 AbstractKeyedDataObservable<String>(), KeyValueStore { 116 117 private var broadcastReceiver: BroadcastReceiver? = null 118 119 override fun contains(key: String) = 120 key == KEY && context.getSystemService(WifiManager::class.java) != null 121 122 override fun <T : Any> getValue(key: String, valueType: Class<T>): T? = 123 context.getSystemService(WifiManager::class.java)?.isWifiEnabled as T? 124 125 @Suppress("DEPRECATION") 126 override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) { 127 if (value is Boolean) { 128 context.getSystemService(WifiManager::class.java)?.isWifiEnabled = value 129 } 130 } 131 132 override fun onFirstObserverAdded() { 133 broadcastReceiver = 134 object : BroadcastReceiver() { 135 override fun onReceive(context: Context, intent: Intent) { 136 val wifiState = intent.wifiState 137 // do not notify for enabling/disabling state 138 if ( 139 wifiState == WifiManager.WIFI_STATE_ENABLED || 140 wifiState == WifiManager.WIFI_STATE_DISABLED 141 ) { 142 notifyChange(KEY, DataChangeReason.UPDATE) 143 } 144 } 145 } 146 context.registerReceiver( 147 broadcastReceiver, 148 IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION), 149 ) 150 } 151 152 override fun onLastObserverRemoved() { 153 broadcastReceiver?.let { context.unregisterReceiver(it) } 154 } 155 } 156 157 companion object { 158 const val TAG = "WifiSwitchPreference" 159 const val KEY = "main_toggle_wifi" 160 Contextnull161 private fun Context.isRadioAllowed() = 162 WirelessUtils.isRadioAllowed(this, Settings.Global.RADIO_WIFI) 163 164 private fun Context.isSatelliteOn() = 165 try { 166 SatelliteRepository(this) 167 .requestIsSessionStarted(Executors.newSingleThreadExecutor()) 168 .get(2000, TimeUnit.MILLISECONDS) 169 } catch (e: Exception) { 170 Log.e(TAG, "Error to get satellite status : $e") 171 false 172 } 173 174 private val Intent.wifiState 175 get() = getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN) 176 } 177 } 178 // LINT.ThenChange(WifiSwitchPreferenceController.java) 179