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 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