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