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 51 WifiSettingsStore(Context context) { 52 mContext = context; 53 mAirplaneModeOn = getPersistedAirplaneModeOn(); 54 mPersistWifiState = getPersistedWifiState(); 55 mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); 56 } 57 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 */ 75 public synchronized boolean isAirplaneModeOn() { 76 return mAirplaneModeOn; 77 } 78 79 public synchronized boolean isScanAlwaysAvailable() { 80 return !mAirplaneModeOn && mScanAlwaysAvailable; 81 } 82 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 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 persistWifiState(WIFI_ENABLED); 122 } 123 } 124 return true; 125 } 126 127 synchronized void handleWifiScanAlwaysAvailableToggled() { 128 mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); 129 } 130 131 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 132 pw.println("mPersistWifiState " + mPersistWifiState); 133 pw.println("mAirplaneModeOn " + mAirplaneModeOn); 134 } 135 136 private void persistWifiState(int state) { 137 final ContentResolver cr = mContext.getContentResolver(); 138 mPersistWifiState = state; 139 Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state); 140 } 141 142 /* Does Wi-Fi need to be disabled when airplane mode is on ? */ 143 private boolean isAirplaneSensitive() { 144 String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(), 145 Settings.Global.AIRPLANE_MODE_RADIOS); 146 return airplaneModeRadios == null 147 || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI); 148 } 149 150 /* Is Wi-Fi allowed to be re-enabled while airplane mode is on ? */ 151 private boolean isAirplaneToggleable() { 152 String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(), 153 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 154 return toggleableRadios != null 155 && toggleableRadios.contains(Settings.Global.RADIO_WIFI); 156 } 157 158 /** 159 * After a reboot, we restore wi-fi to be on if it was turned off temporarily for tethering. 160 * The settings app tracks the saved state, but the framework has to check it at boot to 161 * make sure the wi-fi is turned on in case it was turned off for the purpose of tethering. 162 * 163 * Note that this is not part of the regular WIFI_ON setting because this only needs to 164 * be controlled through the settings app and not the Wi-Fi public API. 165 */ 166 private boolean testAndClearWifiSavedState() { 167 int wifiSavedState = getWifiSavedState(); 168 if (wifiSavedState == WIFI_ENABLED) { 169 setWifiSavedState(WIFI_DISABLED); 170 } 171 return (wifiSavedState == WIFI_ENABLED); 172 } 173 174 /** 175 * Allow callers to set the Settings.Global.WIFI_SAVED_STATE property. 176 * 177 * When changing states, we need to remember what the wifi state was before switching. An 178 * example of this is when WiFiController switches to APEnabledState. Before swtiching to the 179 * new state, WifiController sets the current WiFi enabled/disabled state. When the AP is 180 * turned off, the WIFI_SAVED_STATE setting is used to restore the previous wifi state. 181 * 182 * @param state WiFi state to store with the Settings.Global.WIFI_SAVED_STATE property. 183 */ 184 public void setWifiSavedState(int state) { 185 Settings.Global.putInt(mContext.getContentResolver(), 186 Settings.Global.WIFI_SAVED_STATE, state); 187 } 188 189 /** 190 * Allow callers to get the Settings.Global.WIFI_SAVED_STATE property. 191 * 192 * When changing states we remember what the wifi state was before switching. This function is 193 * used to get the saved state. 194 * 195 * @return int Value for the previously saved state. 196 */ 197 public int getWifiSavedState() { 198 try { 199 return Settings.Global.getInt(mContext.getContentResolver(), 200 Settings.Global.WIFI_SAVED_STATE); 201 } catch (Settings.SettingNotFoundException e) { 202 // If we have an error, return wifiSavedState off. 203 return WIFI_DISABLED; 204 } 205 } 206 207 private int getPersistedWifiState() { 208 final ContentResolver cr = mContext.getContentResolver(); 209 try { 210 return Settings.Global.getInt(cr, Settings.Global.WIFI_ON); 211 } catch (Settings.SettingNotFoundException e) { 212 Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED); 213 return WIFI_DISABLED; 214 } 215 } 216 217 private boolean getPersistedAirplaneModeOn() { 218 return Settings.Global.getInt(mContext.getContentResolver(), 219 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 220 } 221 222 private boolean getPersistedScanAlwaysAvailable() { 223 return Settings.Global.getInt(mContext.getContentResolver(), 224 Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 225 0) == 1; 226 } 227 228 /** 229 * Get Location Mode settings for the context 230 * @param context 231 * @return Location Mode setting 232 */ 233 public int getLocationModeSetting(Context context) { 234 return Settings.Secure.getInt(context.getContentResolver(), 235 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 236 } 237 } 238