1 /* 2 * Copyright (C) 2013 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.server.wifi; 18 19 import android.content.ContentResolver; 20 import android.content.Context; 21 import android.provider.Settings; 22 23 import java.io.FileDescriptor; 24 import java.io.PrintWriter; 25 26 /* Tracks persisted settings for Wi-Fi and airplane mode interaction */ 27 public class WifiSettingsStore { 28 /* Values tracked in Settings.Global.WIFI_ON */ 29 static final int WIFI_DISABLED = 0; 30 static final int WIFI_ENABLED = 1; 31 32 /* Wifi enabled while in airplane mode */ 33 private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2; 34 /* Wifi disabled due to airplane mode on */ 35 private static final int WIFI_DISABLED_AIRPLANE_ON = 3; 36 37 /* Persisted state that tracks the wifi & airplane interaction from settings */ 38 private int mPersistWifiState = WIFI_DISABLED; 39 /* Tracks current airplane mode state */ 40 private boolean mAirplaneModeOn = false; 41 42 /* Tracks the setting of scan being available even when wi-fi is turned off 43 */ 44 private boolean mScanAlwaysAvailable; 45 46 private final Context mContext; 47 48 /* Tracks if we have checked the saved wi-fi state after boot */ 49 private boolean mCheckSavedStateAtBoot = false; 50 WifiSettingsStore(Context context)51 WifiSettingsStore(Context context) { 52 mContext = context; 53 mAirplaneModeOn = getPersistedAirplaneModeOn(); 54 mPersistWifiState = getPersistedWifiState(); 55 mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); 56 } 57 isWifiToggleEnabled()58 public synchronized boolean isWifiToggleEnabled() { 59 if (!mCheckSavedStateAtBoot) { 60 mCheckSavedStateAtBoot = true; 61 if (testAndClearWifiSavedState()) return true; 62 } 63 64 if (mAirplaneModeOn) { 65 return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE; 66 } else { 67 return mPersistWifiState != WIFI_DISABLED; 68 } 69 } 70 71 /** 72 * Returns true if airplane mode is currently on. 73 * @return {@code true} if airplane mode is on. 74 */ isAirplaneModeOn()75 public synchronized boolean isAirplaneModeOn() { 76 return mAirplaneModeOn; 77 } 78 isScanAlwaysAvailable()79 public synchronized boolean isScanAlwaysAvailable() { 80 return !mAirplaneModeOn && mScanAlwaysAvailable; 81 } 82 handleWifiToggled(boolean wifiEnabled)83 public synchronized boolean handleWifiToggled(boolean wifiEnabled) { 84 // Can Wi-Fi be toggled in airplane mode ? 85 if (mAirplaneModeOn && !isAirplaneToggleable()) { 86 return false; 87 } 88 89 if (wifiEnabled) { 90 if (mAirplaneModeOn) { 91 persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE); 92 } else { 93 persistWifiState(WIFI_ENABLED); 94 } 95 } else { 96 // When wifi state is disabled, we do not care 97 // if airplane mode is on or not. The scenario of 98 // wifi being disabled due to airplane mode being turned on 99 // is handled handleAirplaneModeToggled() 100 persistWifiState(WIFI_DISABLED); 101 } 102 return true; 103 } 104 handleAirplaneModeToggled()105 synchronized boolean handleAirplaneModeToggled() { 106 // Is Wi-Fi sensitive to airplane mode changes ? 107 if (!isAirplaneSensitive()) { 108 return false; 109 } 110 111 mAirplaneModeOn = getPersistedAirplaneModeOn(); 112 if (mAirplaneModeOn) { 113 // Wifi disabled due to airplane on 114 if (mPersistWifiState == WIFI_ENABLED) { 115 persistWifiState(WIFI_DISABLED_AIRPLANE_ON); 116 } 117 } else { 118 /* On airplane mode disable, restore wifi state if necessary */ 119 if (testAndClearWifiSavedState() || 120 mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE 121 || mPersistWifiState == WIFI_DISABLED_AIRPLANE_ON) { 122 persistWifiState(WIFI_ENABLED); 123 } 124 } 125 return true; 126 } 127 handleWifiScanAlwaysAvailableToggled()128 synchronized void handleWifiScanAlwaysAvailableToggled() { 129 mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); 130 } 131 dump(FileDescriptor fd, PrintWriter pw, String[] args)132 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 133 pw.println("mPersistWifiState " + mPersistWifiState); 134 pw.println("mAirplaneModeOn " + mAirplaneModeOn); 135 } 136 persistWifiState(int state)137 private void persistWifiState(int state) { 138 final ContentResolver cr = mContext.getContentResolver(); 139 mPersistWifiState = state; 140 Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state); 141 } 142 143 /* Does Wi-Fi need to be disabled when airplane mode is on ? */ isAirplaneSensitive()144 private boolean isAirplaneSensitive() { 145 String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(), 146 Settings.Global.AIRPLANE_MODE_RADIOS); 147 return airplaneModeRadios == null 148 || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI); 149 } 150 151 /* Is Wi-Fi allowed to be re-enabled while airplane mode is on ? */ isAirplaneToggleable()152 private boolean isAirplaneToggleable() { 153 String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(), 154 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 155 return toggleableRadios != null 156 && toggleableRadios.contains(Settings.Global.RADIO_WIFI); 157 } 158 159 /** 160 * After a reboot, we restore wi-fi to be on if it was turned off temporarily for tethering. 161 * The settings app tracks the saved state, but the framework has to check it at boot to 162 * make sure the wi-fi is turned on in case it was turned off for the purpose of tethering. 163 * 164 * Note that this is not part of the regular WIFI_ON setting because this only needs to 165 * be controlled through the settings app and not the Wi-Fi public API. 166 */ testAndClearWifiSavedState()167 private boolean testAndClearWifiSavedState() { 168 int wifiSavedState = getWifiSavedState(); 169 if (wifiSavedState == WIFI_ENABLED) { 170 setWifiSavedState(WIFI_DISABLED); 171 } 172 return (wifiSavedState == WIFI_ENABLED); 173 } 174 175 /** 176 * Allow callers to set the Settings.Global.WIFI_SAVED_STATE property. 177 * 178 * When changing states, we need to remember what the wifi state was before switching. An 179 * example of this is when WiFiController switches to APEnabledState. Before swtiching to the 180 * new state, WifiController sets the current WiFi enabled/disabled state. When the AP is 181 * turned off, the WIFI_SAVED_STATE setting is used to restore the previous wifi state. 182 * 183 * @param state WiFi state to store with the Settings.Global.WIFI_SAVED_STATE property. 184 */ setWifiSavedState(int state)185 public void setWifiSavedState(int state) { 186 Settings.Global.putInt(mContext.getContentResolver(), 187 Settings.Global.WIFI_SAVED_STATE, state); 188 } 189 190 /** 191 * Allow callers to get the Settings.Global.WIFI_SAVED_STATE property. 192 * 193 * When changing states we remember what the wifi state was before switching. This function is 194 * used to get the saved state. 195 * 196 * @return int Value for the previously saved state. 197 */ getWifiSavedState()198 public int getWifiSavedState() { 199 try { 200 return Settings.Global.getInt(mContext.getContentResolver(), 201 Settings.Global.WIFI_SAVED_STATE); 202 } catch (Settings.SettingNotFoundException e) { 203 // If we have an error, return wifiSavedState off. 204 return WIFI_DISABLED; 205 } 206 } 207 getPersistedWifiState()208 private int getPersistedWifiState() { 209 final ContentResolver cr = mContext.getContentResolver(); 210 try { 211 return Settings.Global.getInt(cr, Settings.Global.WIFI_ON); 212 } catch (Settings.SettingNotFoundException e) { 213 Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED); 214 return WIFI_DISABLED; 215 } 216 } 217 getPersistedAirplaneModeOn()218 private boolean getPersistedAirplaneModeOn() { 219 return Settings.Global.getInt(mContext.getContentResolver(), 220 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 221 } 222 getPersistedScanAlwaysAvailable()223 private boolean getPersistedScanAlwaysAvailable() { 224 return Settings.Global.getInt(mContext.getContentResolver(), 225 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 226 0) == 1; 227 } 228 } 229