1 /* 2 * Copyright (C) 2010 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.settings.wifi; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.net.NetworkInfo; 24 import android.net.wifi.SupplicantState; 25 import android.net.wifi.WifiInfo; 26 import android.net.wifi.WifiManager; 27 import android.os.Handler; 28 import android.os.Message; 29 import android.provider.Settings; 30 import android.widget.Switch; 31 import android.widget.Toast; 32 33 import com.android.internal.logging.MetricsLogger; 34 import com.android.settings.R; 35 import com.android.settings.search.Index; 36 import com.android.settings.widget.SwitchBar; 37 import com.android.settingslib.WirelessUtils; 38 39 import java.util.concurrent.atomic.AtomicBoolean; 40 41 public class WifiEnabler implements SwitchBar.OnSwitchChangeListener { 42 private Context mContext; 43 private SwitchBar mSwitchBar; 44 private boolean mListeningToOnSwitchChange = false; 45 private AtomicBoolean mConnected = new AtomicBoolean(false); 46 47 private final WifiManager mWifiManager; 48 private boolean mStateMachineEvent; 49 private final IntentFilter mIntentFilter; 50 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 51 @Override 52 public void onReceive(Context context, Intent intent) { 53 String action = intent.getAction(); 54 if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) { 55 handleWifiStateChanged(intent.getIntExtra( 56 WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN)); 57 } else if (WifiManager.SUPPLICANT_STATE_CHANGED_ACTION.equals(action)) { 58 if (!mConnected.get()) { 59 handleStateChanged(WifiInfo.getDetailedStateOf((SupplicantState) 60 intent.getParcelableExtra(WifiManager.EXTRA_NEW_STATE))); 61 } 62 } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { 63 NetworkInfo info = (NetworkInfo) intent.getParcelableExtra( 64 WifiManager.EXTRA_NETWORK_INFO); 65 mConnected.set(info.isConnected()); 66 handleStateChanged(info.getDetailedState()); 67 } 68 } 69 }; 70 71 private static final String EVENT_DATA_IS_WIFI_ON = "is_wifi_on"; 72 private static final int EVENT_UPDATE_INDEX = 0; 73 74 private Handler mHandler = new Handler() { 75 @Override 76 public void handleMessage(Message msg) { 77 switch (msg.what) { 78 case EVENT_UPDATE_INDEX: 79 final boolean isWiFiOn = msg.getData().getBoolean(EVENT_DATA_IS_WIFI_ON); 80 Index.getInstance(mContext).updateFromClassNameResource( 81 WifiSettings.class.getName(), true, isWiFiOn); 82 break; 83 } 84 } 85 }; 86 87 public WifiEnabler(Context context, SwitchBar switchBar) { 88 mContext = context; 89 mSwitchBar = switchBar; 90 91 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); 92 93 mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); 94 // The order matters! We really should not depend on this. :( 95 mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); 96 mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 97 98 setupSwitchBar(); 99 } 100 101 public void setupSwitchBar() { 102 final int state = mWifiManager.getWifiState(); 103 handleWifiStateChanged(state); 104 if (!mListeningToOnSwitchChange) { 105 mSwitchBar.addOnSwitchChangeListener(this); 106 mListeningToOnSwitchChange = true; 107 } 108 mSwitchBar.show(); 109 } 110 111 public void teardownSwitchBar() { 112 if (mListeningToOnSwitchChange) { 113 mSwitchBar.removeOnSwitchChangeListener(this); 114 mListeningToOnSwitchChange = false; 115 } 116 mSwitchBar.hide(); 117 } 118 119 public void resume(Context context) { 120 mContext = context; 121 // Wi-Fi state is sticky, so just let the receiver update UI 122 mContext.registerReceiver(mReceiver, mIntentFilter); 123 if (!mListeningToOnSwitchChange) { 124 mSwitchBar.addOnSwitchChangeListener(this); 125 mListeningToOnSwitchChange = true; 126 } 127 } 128 129 public void pause() { 130 mContext.unregisterReceiver(mReceiver); 131 if (mListeningToOnSwitchChange) { 132 mSwitchBar.removeOnSwitchChangeListener(this); 133 mListeningToOnSwitchChange = false; 134 } 135 } 136 137 private void handleWifiStateChanged(int state) { 138 switch (state) { 139 case WifiManager.WIFI_STATE_ENABLING: 140 mSwitchBar.setEnabled(false); 141 break; 142 case WifiManager.WIFI_STATE_ENABLED: 143 setSwitchBarChecked(true); 144 mSwitchBar.setEnabled(true); 145 updateSearchIndex(true); 146 break; 147 case WifiManager.WIFI_STATE_DISABLING: 148 mSwitchBar.setEnabled(false); 149 break; 150 case WifiManager.WIFI_STATE_DISABLED: 151 setSwitchBarChecked(false); 152 mSwitchBar.setEnabled(true); 153 updateSearchIndex(false); 154 break; 155 default: 156 setSwitchBarChecked(false); 157 mSwitchBar.setEnabled(true); 158 updateSearchIndex(false); 159 } 160 } 161 162 private void updateSearchIndex(boolean isWiFiOn) { 163 mHandler.removeMessages(EVENT_UPDATE_INDEX); 164 165 Message msg = new Message(); 166 msg.what = EVENT_UPDATE_INDEX; 167 msg.getData().putBoolean(EVENT_DATA_IS_WIFI_ON, isWiFiOn); 168 mHandler.sendMessage(msg); 169 } 170 171 private void setSwitchBarChecked(boolean checked) { 172 mStateMachineEvent = true; 173 mSwitchBar.setChecked(checked); 174 mStateMachineEvent = false; 175 } 176 177 private void handleStateChanged(@SuppressWarnings("unused") NetworkInfo.DetailedState state) { 178 // After the refactoring from a CheckBoxPreference to a Switch, this method is useless since 179 // there is nowhere to display a summary. 180 // This code is kept in case a future change re-introduces an associated text. 181 /* 182 // WifiInfo is valid if and only if Wi-Fi is enabled. 183 // Here we use the state of the switch as an optimization. 184 if (state != null && mSwitch.isChecked()) { 185 WifiInfo info = mWifiManager.getConnectionInfo(); 186 if (info != null) { 187 //setSummary(Summary.get(mContext, info.getSSID(), state)); 188 } 189 } 190 */ 191 } 192 193 @Override 194 public void onSwitchChanged(Switch switchView, boolean isChecked) { 195 //Do nothing if called as a result of a state machine event 196 if (mStateMachineEvent) { 197 return; 198 } 199 // Show toast message if Wi-Fi is not allowed in airplane mode 200 if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) { 201 Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show(); 202 // Reset switch to off. No infinite check/listenenr loop. 203 mSwitchBar.setChecked(false); 204 return; 205 } 206 207 // Disable tethering if enabling Wifi 208 int wifiApState = mWifiManager.getWifiApState(); 209 if (isChecked && ((wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) || 210 (wifiApState == WifiManager.WIFI_AP_STATE_ENABLED))) { 211 mWifiManager.setWifiApEnabled(null, false); 212 } 213 MetricsLogger.action(mContext, 214 isChecked ? MetricsLogger.ACTION_WIFI_ON : MetricsLogger.ACTION_WIFI_OFF); 215 if (!mWifiManager.setWifiEnabled(isChecked)) { 216 // Error 217 mSwitchBar.setEnabled(true); 218 Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show(); 219 } 220 } 221 } 222