/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.wifi; import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; import java.io.FileDescriptor; import java.io.PrintWriter; /* Tracks persisted settings for Wi-Fi and airplane mode interaction */ public class WifiSettingsStore { /* Values tracked in Settings.Global.WIFI_ON */ static final int WIFI_DISABLED = 0; static final int WIFI_ENABLED = 1; /* Wifi enabled while in airplane mode */ private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2; /* Wifi disabled due to airplane mode on */ private static final int WIFI_DISABLED_AIRPLANE_ON = 3; /* Persisted state that tracks the wifi & airplane interaction from settings */ private int mPersistWifiState = WIFI_DISABLED; /* Tracks current airplane mode state */ private boolean mAirplaneModeOn = false; /* Tracks the setting of scan being available even when wi-fi is turned off */ private boolean mScanAlwaysAvailable; private final Context mContext; /* Tracks if we have checked the saved wi-fi state after boot */ private boolean mCheckSavedStateAtBoot = false; WifiSettingsStore(Context context) { mContext = context; mAirplaneModeOn = getPersistedAirplaneModeOn(); mPersistWifiState = getPersistedWifiState(); mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); } public synchronized boolean isWifiToggleEnabled() { if (!mCheckSavedStateAtBoot) { mCheckSavedStateAtBoot = true; if (testAndClearWifiSavedState()) return true; } if (mAirplaneModeOn) { return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE; } else { return mPersistWifiState != WIFI_DISABLED; } } /** * Returns true if airplane mode is currently on. * @return {@code true} if airplane mode is on. */ public synchronized boolean isAirplaneModeOn() { return mAirplaneModeOn; } public synchronized boolean isScanAlwaysAvailable() { return !mAirplaneModeOn && mScanAlwaysAvailable; } public synchronized boolean handleWifiToggled(boolean wifiEnabled) { // Can Wi-Fi be toggled in airplane mode ? if (mAirplaneModeOn && !isAirplaneToggleable()) { return false; } if (wifiEnabled) { if (mAirplaneModeOn) { persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE); } else { persistWifiState(WIFI_ENABLED); } } else { // When wifi state is disabled, we do not care // if airplane mode is on or not. The scenario of // wifi being disabled due to airplane mode being turned on // is handled handleAirplaneModeToggled() persistWifiState(WIFI_DISABLED); } return true; } synchronized boolean handleAirplaneModeToggled() { // Is Wi-Fi sensitive to airplane mode changes ? if (!isAirplaneSensitive()) { return false; } mAirplaneModeOn = getPersistedAirplaneModeOn(); if (mAirplaneModeOn) { // Wifi disabled due to airplane on if (mPersistWifiState == WIFI_ENABLED) { persistWifiState(WIFI_DISABLED_AIRPLANE_ON); } } else { /* On airplane mode disable, restore wifi state if necessary */ if (testAndClearWifiSavedState() || mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE) { persistWifiState(WIFI_ENABLED); } } return true; } synchronized void handleWifiScanAlwaysAvailableToggled() { mScanAlwaysAvailable = getPersistedScanAlwaysAvailable(); } void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("mPersistWifiState " + mPersistWifiState); pw.println("mAirplaneModeOn " + mAirplaneModeOn); } private void persistWifiState(int state) { final ContentResolver cr = mContext.getContentResolver(); mPersistWifiState = state; Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state); } /* Does Wi-Fi need to be disabled when airplane mode is on ? */ private boolean isAirplaneSensitive() { String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_RADIOS); return airplaneModeRadios == null || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI); } /* Is Wi-Fi allowed to be re-enabled while airplane mode is on ? */ private boolean isAirplaneToggleable() { String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); return toggleableRadios != null && toggleableRadios.contains(Settings.Global.RADIO_WIFI); } /** * After a reboot, we restore wi-fi to be on if it was turned off temporarily for tethering. * The settings app tracks the saved state, but the framework has to check it at boot to * make sure the wi-fi is turned on in case it was turned off for the purpose of tethering. * * Note that this is not part of the regular WIFI_ON setting because this only needs to * be controlled through the settings app and not the Wi-Fi public API. */ private boolean testAndClearWifiSavedState() { int wifiSavedState = getWifiSavedState(); if (wifiSavedState == WIFI_ENABLED) { setWifiSavedState(WIFI_DISABLED); } return (wifiSavedState == WIFI_ENABLED); } /** * Allow callers to set the Settings.Global.WIFI_SAVED_STATE property. * * When changing states, we need to remember what the wifi state was before switching. An * example of this is when WiFiController switches to APEnabledState. Before swtiching to the * new state, WifiController sets the current WiFi enabled/disabled state. When the AP is * turned off, the WIFI_SAVED_STATE setting is used to restore the previous wifi state. * * @param state WiFi state to store with the Settings.Global.WIFI_SAVED_STATE property. */ public void setWifiSavedState(int state) { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.WIFI_SAVED_STATE, state); } /** * Allow callers to get the Settings.Global.WIFI_SAVED_STATE property. * * When changing states we remember what the wifi state was before switching. This function is * used to get the saved state. * * @return int Value for the previously saved state. */ public int getWifiSavedState() { try { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.WIFI_SAVED_STATE); } catch (Settings.SettingNotFoundException e) { // If we have an error, return wifiSavedState off. return WIFI_DISABLED; } } private int getPersistedWifiState() { final ContentResolver cr = mContext.getContentResolver(); try { return Settings.Global.getInt(cr, Settings.Global.WIFI_ON); } catch (Settings.SettingNotFoundException e) { Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED); return WIFI_DISABLED; } } private boolean getPersistedAirplaneModeOn() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1; } private boolean getPersistedScanAlwaysAvailable() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1; } }