WifiEnabler.java revision 4e14211d21387d645ecdad406f3350d36e5a8643
1/*
2 * Copyright (C) 2007 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
17package com.android.settings.wifi;
18
19import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
20import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
21import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
22import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
23import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
24
25import com.android.settings.R;
26import com.android.settings.AirplaneModeEnabler;
27
28import android.content.BroadcastReceiver;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.net.NetworkInfo;
33import android.net.wifi.WifiManager;
34import android.preference.Preference;
35import android.preference.CheckBoxPreference;
36import android.provider.Settings;
37import android.text.TextUtils;
38import android.util.Config;
39import android.util.Log;
40
41public class WifiEnabler implements Preference.OnPreferenceChangeListener {
42
43    private static final boolean LOCAL_LOGD = Config.LOGD || WifiLayer.LOGV;
44    private static final String TAG = "SettingsWifiEnabler";
45
46    private final Context mContext;
47    private final WifiManager mWifiManager;
48    private final CheckBoxPreference mWifiCheckBoxPref;
49    private final CharSequence mOriginalSummary;
50
51    private final IntentFilter mWifiStateFilter;
52    private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
53
54        @Override
55        public void onReceive(Context context, Intent intent) {
56            if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
57                handleWifiStateChanged(
58                        intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WIFI_STATE_UNKNOWN),
59                        intent.getIntExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE,
60                                WIFI_STATE_UNKNOWN));
61            } else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
62                handleNetworkStateChanged(
63                        (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO));
64            }
65        }
66    };
67
68    public WifiEnabler(Context context, CheckBoxPreference wifiCheckBoxPreference) {
69        this(context, (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
70                wifiCheckBoxPreference);
71    }
72
73    public WifiEnabler(Context context, WifiManager wifiManager,
74            CheckBoxPreference wifiCheckBoxPreference) {
75        mContext = context;
76        mWifiCheckBoxPref = wifiCheckBoxPreference;
77        mWifiManager = wifiManager;
78
79        mOriginalSummary = wifiCheckBoxPreference.getSummary();
80        wifiCheckBoxPreference.setPersistent(false);
81
82        mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
83        mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
84    }
85
86    public void resume() {
87        int state = mWifiManager.getWifiState();
88        // This is the widget enabled state, not the preference toggled state
89        mWifiCheckBoxPref.setEnabled(state == WIFI_STATE_ENABLED || state == WIFI_STATE_DISABLED
90                || state == WIFI_STATE_UNKNOWN);
91
92        mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter);
93        mWifiCheckBoxPref.setOnPreferenceChangeListener(this);
94    }
95
96    public void pause() {
97        mContext.unregisterReceiver(mWifiStateReceiver);
98        mWifiCheckBoxPref.setOnPreferenceChangeListener(null);
99    }
100
101    public boolean onPreferenceChange(Preference preference, Object value) {
102        // Turn on/off Wi-Fi
103        setWifiEnabled((Boolean) value);
104
105        // Don't update UI to opposite state until we're sure
106        return false;
107    }
108
109    private void setWifiEnabled(final boolean enable) {
110        // Disable button
111        mWifiCheckBoxPref.setEnabled(false);
112
113        if (!mWifiManager.setWifiEnabled(enable)) {
114            mWifiCheckBoxPref.setSummary(enable ? R.string.error_starting : R.string.error_stopping);
115        }
116    }
117
118    private void handleWifiStateChanged(int wifiState, int previousWifiState) {
119
120        if (LOCAL_LOGD) {
121            Log.d(TAG, "Received wifi state changed from "
122                    + getHumanReadableWifiState(previousWifiState) + " to "
123                    + getHumanReadableWifiState(wifiState));
124        }
125
126        if (wifiState == WIFI_STATE_DISABLED || wifiState == WIFI_STATE_ENABLED) {
127            mWifiCheckBoxPref.setChecked(wifiState == WIFI_STATE_ENABLED);
128            mWifiCheckBoxPref
129                    .setSummary(wifiState == WIFI_STATE_DISABLED ? mOriginalSummary : null);
130
131            final boolean hasDependency = !TextUtils.isEmpty(mWifiCheckBoxPref.getDependency());
132            final boolean wifiAllowed = isWifiAllowed(mContext);
133
134            // Avoid disabling when dependencies have been manually set,
135            // workaround for framework bug http://b/2053751
136            if (wifiAllowed) {
137                mWifiCheckBoxPref.setEnabled(true);
138            } else if (!hasDependency) {
139                mWifiCheckBoxPref.setEnabled(false);
140            }
141
142        } else if (wifiState == WIFI_STATE_DISABLING || wifiState == WIFI_STATE_ENABLING) {
143            mWifiCheckBoxPref.setSummary(wifiState == WIFI_STATE_ENABLING ? R.string.wifi_starting
144                    : R.string.wifi_stopping);
145
146        } else if (wifiState == WIFI_STATE_UNKNOWN) {
147            int message = R.string.wifi_error;
148            if (previousWifiState == WIFI_STATE_ENABLING) message = R.string.error_starting;
149            else if (previousWifiState == WIFI_STATE_DISABLING) message = R.string.error_stopping;
150
151            mWifiCheckBoxPref.setChecked(false);
152            mWifiCheckBoxPref.setSummary(message);
153            mWifiCheckBoxPref.setEnabled(true);
154        }
155    }
156
157    private void handleNetworkStateChanged(NetworkInfo networkInfo) {
158
159        if (LOCAL_LOGD) {
160            Log.d(TAG, "Received network state changed to " + networkInfo);
161        }
162
163        if (mWifiManager.isWifiEnabled()) {
164            String summary = WifiStatus.getStatus(mContext,
165                    mWifiManager.getConnectionInfo().getSSID(), networkInfo.getDetailedState());
166            mWifiCheckBoxPref.setSummary(summary);
167        }
168    }
169
170    private static boolean isWifiAllowed(Context context) {
171        // allowed if we are not in airplane mode
172        if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
173            return true;
174        }
175        // allowed if wifi is not in AIRPLANE_MODE_RADIOS
176        String radios = Settings.System.getString(context.getContentResolver(),
177                Settings.System.AIRPLANE_MODE_RADIOS);
178        if (radios == null || !radios.contains(Settings.System.RADIO_WIFI)) {
179            return true;
180        }
181        // allowed if wifi is in AIRPLANE_MODE_TOGGLEABLE_RADIOS
182        radios = Settings.System.getString(context.getContentResolver(),
183                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
184        return (radios != null && radios.contains(Settings.System.RADIO_WIFI));
185    }
186
187    private static String getHumanReadableWifiState(int wifiState) {
188        switch (wifiState) {
189            case WIFI_STATE_DISABLED:
190                return "Disabled";
191            case WIFI_STATE_DISABLING:
192                return "Disabling";
193            case WIFI_STATE_ENABLED:
194                return "Enabled";
195            case WIFI_STATE_ENABLING:
196                return "Enabling";
197            case WIFI_STATE_UNKNOWN:
198                return "Unknown";
199            default:
200                return "Some other state!";
201        }
202    }
203}
204