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