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     private final Context mContext;
43     private final WifiSettingsConfigStore mSettingsConfigStore;
44 
WifiSettingsStore(Context context, WifiSettingsConfigStore sharedPreferences)45     WifiSettingsStore(Context context, WifiSettingsConfigStore sharedPreferences) {
46         mContext = context;
47         mSettingsConfigStore = sharedPreferences;
48         mAirplaneModeOn = getPersistedAirplaneModeOn();
49         mPersistWifiState = getPersistedWifiState();
50     }
51 
isWifiToggleEnabled()52     public synchronized boolean isWifiToggleEnabled() {
53         if (mAirplaneModeOn) {
54             return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE;
55         } else {
56             return mPersistWifiState != WIFI_DISABLED;
57         }
58     }
59 
60     /**
61      * Returns true if airplane mode is currently on.
62      * @return {@code true} if airplane mode is on.
63      */
isAirplaneModeOn()64     public synchronized boolean isAirplaneModeOn() {
65         return mAirplaneModeOn;
66     }
67 
isScanAlwaysAvailable()68     public synchronized boolean isScanAlwaysAvailable() {
69         return !mAirplaneModeOn && getPersistedScanAlwaysAvailable();
70     }
71 
handleWifiToggled(boolean wifiEnabled)72     public synchronized boolean handleWifiToggled(boolean wifiEnabled) {
73         // Can Wi-Fi be toggled in airplane mode ?
74         if (mAirplaneModeOn && !isAirplaneToggleable()) {
75             return false;
76         }
77 
78         if (wifiEnabled) {
79             if (mAirplaneModeOn) {
80                 persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
81             } else {
82                 persistWifiState(WIFI_ENABLED);
83             }
84         } else {
85             // When wifi state is disabled, we do not care
86             // if airplane mode is on or not. The scenario of
87             // wifi being disabled due to airplane mode being turned on
88             // is handled handleAirplaneModeToggled()
89             persistWifiState(WIFI_DISABLED);
90         }
91         return true;
92     }
93 
handleAirplaneModeToggled()94     synchronized boolean handleAirplaneModeToggled() {
95         // Is Wi-Fi sensitive to airplane mode changes ?
96         if (!isAirplaneSensitive()) {
97             return false;
98         }
99 
100         mAirplaneModeOn = getPersistedAirplaneModeOn();
101         if (mAirplaneModeOn) {
102             // Wifi disabled due to airplane on
103             if (mPersistWifiState == WIFI_ENABLED) {
104                 persistWifiState(WIFI_DISABLED_AIRPLANE_ON);
105             }
106         } else {
107             /* On airplane mode disable, restore wifi state if necessary */
108             if (mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE
109                     || mPersistWifiState == WIFI_DISABLED_AIRPLANE_ON) {
110                 persistWifiState(WIFI_ENABLED);
111             }
112         }
113         return true;
114     }
115 
handleWifiScanAlwaysAvailableToggled(boolean isAvailable)116     synchronized void handleWifiScanAlwaysAvailableToggled(boolean isAvailable) {
117         persistScanAlwaysAvailableState(isAvailable);
118     }
119 
dump(FileDescriptor fd, PrintWriter pw, String[] args)120     void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
121         pw.println("mPersistWifiState " + mPersistWifiState);
122         pw.println("mAirplaneModeOn " + mAirplaneModeOn);
123     }
124 
persistWifiState(int state)125     private void persistWifiState(int state) {
126         final ContentResolver cr = mContext.getContentResolver();
127         mPersistWifiState = state;
128         Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
129     }
130 
persistScanAlwaysAvailableState(boolean isAvailable)131     private void persistScanAlwaysAvailableState(boolean isAvailable) {
132         mSettingsConfigStore.put(
133                 WifiSettingsConfigStore.WIFI_SCAN_ALWAYS_AVAILABLE, isAvailable);
134     }
135 
136     /* Does Wi-Fi need to be disabled when airplane mode is on ? */
isAirplaneSensitive()137     private boolean isAirplaneSensitive() {
138         String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(),
139                 Settings.Global.AIRPLANE_MODE_RADIOS);
140         return airplaneModeRadios == null
141                 || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI);
142     }
143 
144     /* Is Wi-Fi allowed to be re-enabled while airplane mode is on ? */
isAirplaneToggleable()145     private boolean isAirplaneToggleable() {
146         String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(),
147                 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
148         return toggleableRadios != null
149                 && toggleableRadios.contains(Settings.Global.RADIO_WIFI);
150     }
151 
getPersistedWifiState()152     private int getPersistedWifiState() {
153         final ContentResolver cr = mContext.getContentResolver();
154         try {
155             return Settings.Global.getInt(cr, Settings.Global.WIFI_ON);
156         } catch (Settings.SettingNotFoundException e) {
157             Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED);
158             return WIFI_DISABLED;
159         }
160     }
161 
getPersistedAirplaneModeOn()162     private boolean getPersistedAirplaneModeOn() {
163         return Settings.Global.getInt(mContext.getContentResolver(),
164                 Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
165     }
166 
getPersistedScanAlwaysAvailable()167     private boolean getPersistedScanAlwaysAvailable() {
168         return mSettingsConfigStore.get(
169                 WifiSettingsConfigStore.WIFI_SCAN_ALWAYS_AVAILABLE);
170     }
171 }
172