/*
* 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 */
final class WifiSettingsStore {
/* Values tracked in Settings.Global.WIFI_ON */
private static final int WIFI_DISABLED = 0;
private 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();
}
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.
*/
synchronized boolean isAirplaneModeOn() {
return mAirplaneModeOn;
}
synchronized boolean isScanAlwaysAvailable() {
return !mAirplaneModeOn && mScanAlwaysAvailable;
}
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() {
final ContentResolver cr = mContext.getContentResolver();
int wifiSavedState = 0;
try {
wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE);
if(wifiSavedState == 1)
Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
} catch (Settings.SettingNotFoundException e) {
;
}
return (wifiSavedState == 1);
}
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;
}
}