Home | History | Annotate | Download | only in wifi
      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