Settings: revise WifiEnabler and BluetoothEnabler.

This mainly changes the way both enablers react to the airplane mode. Now
enablers show a toast message instead of disabling the check box directly. This
avoids the inconsistent state introduced by WirelessSettings which controls the
check box using layout dependency.

Related bug: 2053751
This commit is contained in:
Chia-chi Yeh
2010-01-13 06:11:29 +08:00
parent e751e555f7
commit b90452f3d2
4 changed files with 139 additions and 221 deletions

View File

@@ -707,12 +707,14 @@
<string name="ip_address">IP address</string> <string name="ip_address">IP address</string>
<!-- Label for the signal strength --> <!-- Label for the signal strength -->
<string name="signal">Signal strength</string> <string name="signal">Signal strength</string>
<!--Wireless controls setting screen, Wi-Fi check box summary text when turning Wi-Fi on --> <!-- Summary text when turning Wi-Fi or bluetooth on -->
<string name="wifi_starting">Turning on\u2026</string> <string name="wifi_starting">Turning on\u2026</string>
<!--Wireless controls setting screen, Wi-Fi check box summary text when turning Wi-Fi off --> <!-- Summary text when turning Wi-Fi or bluetooth off -->
<string name="wifi_stopping">Turning off\u2026</string> <string name="wifi_stopping">Turning off\u2026</string>
<!-- Generic error message , probably not used--> <!-- Summary text when Wi-Fi or bluetooth has error -->
<string name="wifi_error">Error</string> <string name="wifi_error">Error</string>
<!-- Toast message when Wi-Fi or bluetooth is disallowed in airplane mode -->
<string name="wifi_in_airplane_mode">In airplane mode</string>
<!-- Error message when Wi-Fi can't start --> <!-- Error message when Wi-Fi can't start -->
<string name="error_starting">Unable to start Wi-Fi</string> <string name="error_starting">Unable to start Wi-Fi</string>
<!-- Error message when Wi-Fi can't stop --> <!-- Error message when Wi-Fi can't stop -->

View File

@@ -17,6 +17,7 @@
package com.android.settings; package com.android.settings;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.Bundle; import android.os.Bundle;
@@ -67,7 +68,17 @@ public class WirelessSettings extends PreferenceActivity {
// Let the intents be launched by the Preference manager // Let the intents be launched by the Preference manager
return false; return false;
} }
public static boolean isRadioAllowed(Context context, String type) {
if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
return true;
}
// Here we use the same logic in onCreate().
String toggleable = Settings.System.getString(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
return toggleable != null && toggleable.contains(type);
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@@ -86,7 +97,7 @@ public class WirelessSettings extends PreferenceActivity {
String toggleable = Settings.System.getString(getContentResolver(), String toggleable = Settings.System.getString(getContentResolver(),
Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
// Manually set up dependencies for Wifi when not toggleable. // Manually set dependencies for Wifi when not toggleable.
if (toggleable == null || !toggleable.contains(Settings.System.RADIO_WIFI)) { if (toggleable == null || !toggleable.contains(Settings.System.RADIO_WIFI)) {
wifi.setDependency(KEY_TOGGLE_AIRPLANE); wifi.setDependency(KEY_TOGGLE_AIRPLANE);
findPreference(KEY_WIFI_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE); findPreference(KEY_WIFI_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
@@ -99,7 +110,7 @@ public class WirelessSettings extends PreferenceActivity {
findPreference(KEY_BT_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE); findPreference(KEY_BT_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
} }
// Disable BT Settings if BT service is not available. // Disable Bluetooth Settings if Bluetooth service is not available.
if (ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE) == null) { if (ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE) == null) {
findPreference(KEY_BT_SETTINGS).setEnabled(false); findPreference(KEY_BT_SETTINGS).setEnabled(false);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2008 The Android Open Source Project * Copyright (C) 2010 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
package com.android.settings.bluetooth; package com.android.settings.bluetooth;
import com.android.settings.AirplaneModeEnabler;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.WirelessSettings;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
@@ -28,7 +28,7 @@ import android.preference.Preference;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Config; import android.widget.Toast;
/** /**
* BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox
@@ -36,16 +36,12 @@ import android.util.Config;
* preference reflects the current state. * preference reflects the current state.
*/ */
public class BluetoothEnabler implements Preference.OnPreferenceChangeListener { public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
private static final boolean LOCAL_LOGD = Config.LOGD || false;
private static final String TAG = "BluetoothEnabler";
private final Context mContext; private final Context mContext;
private final CheckBoxPreference mCheckBoxPreference; private final CheckBoxPreference mCheckBox;
private final CharSequence mOriginalSummary; private final CharSequence mOriginalSummary;
private final LocalBluetoothManager mLocalManager; private final LocalBluetoothManager mLocalManager;
private final IntentFilter mIntentFilter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() { private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@@ -54,18 +50,18 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
} }
}; };
public BluetoothEnabler(Context context, CheckBoxPreference checkBoxPreference) { public BluetoothEnabler(Context context, CheckBoxPreference checkBox) {
mContext = context; mContext = context;
mCheckBoxPreference = checkBoxPreference; mCheckBox = checkBox;
mOriginalSummary = checkBox.getSummary();
mOriginalSummary = checkBoxPreference.getSummary(); checkBox.setPersistent(false);
checkBoxPreference.setPersistent(false);
mLocalManager = LocalBluetoothManager.getInstance(context); mLocalManager = LocalBluetoothManager.getInstance(context);
if (mLocalManager == null) { if (mLocalManager == null) {
// Bluetooth not supported // Bluetooth is not supported
checkBoxPreference.setEnabled(false); checkBox.setEnabled(false);
} }
mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
} }
public void resume() { public void resume() {
@@ -73,16 +69,11 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
return; return;
} }
int state = mLocalManager.getBluetoothState(); // Bluetooth state is not sticky, so set it manually
// This is the widget enabled state, not the preference toggled state handleStateChanged(mLocalManager.getBluetoothState());
mCheckBoxPreference.setEnabled(state == BluetoothAdapter.STATE_ON ||
state == BluetoothAdapter.STATE_OFF);
// BT state is not a sticky broadcast, so set it manually
handleStateChanged(state);
mContext.registerReceiver(mReceiver, mContext.registerReceiver(mReceiver, mIntentFilter);
new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); mCheckBox.setOnPreferenceChangeListener(this);
mCheckBoxPreference.setOnPreferenceChangeListener(this);
} }
public void pause() { public void pause() {
@@ -91,72 +82,51 @@ public class BluetoothEnabler implements Preference.OnPreferenceChangeListener {
} }
mContext.unregisterReceiver(mReceiver); mContext.unregisterReceiver(mReceiver);
mCheckBoxPreference.setOnPreferenceChangeListener(null); mCheckBox.setOnPreferenceChangeListener(null);
} }
public boolean onPreferenceChange(Preference preference, Object value) { public boolean onPreferenceChange(Preference preference, Object value) {
// Turn on/off BT boolean enable = (Boolean) value;
setEnabled((Boolean) value);
// Show toast message if Bluetooth is not allowed in airplane mode
if (enable && !WirelessSettings
.isRadioAllowed(mContext, Settings.System.RADIO_BLUETOOTH)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode,
Toast.LENGTH_SHORT).show();
return false;
}
mLocalManager.setBluetoothEnabled(enable);
mCheckBox.setEnabled(false);
// Don't update UI to opposite state until we're sure // Don't update UI to opposite state until we're sure
return false; return false;
} }
private void setEnabled(final boolean enable) {
// Disable preference
mCheckBoxPreference.setEnabled(false);
mLocalManager.setBluetoothEnabled(enable);
}
private void handleStateChanged(int state) { private void handleStateChanged(int state) {
switch (state) {
if (state == BluetoothAdapter.STATE_OFF || case BluetoothAdapter.STATE_TURNING_ON:
state == BluetoothAdapter.STATE_ON) { mCheckBox.setSummary(R.string.wifi_starting);
mCheckBoxPreference.setChecked(state == BluetoothAdapter.STATE_ON); mCheckBox.setEnabled(false);
mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_OFF ? break;
mOriginalSummary : case BluetoothAdapter.STATE_ON:
null); mCheckBox.setChecked(true);
mCheckBox.setSummary(null);
final boolean hasDependency = !TextUtils.isEmpty(mCheckBoxPreference.getDependency()); mCheckBox.setEnabled(true);
final boolean bluetoothAllowed = isBluetoothAllowed(mContext); break;
case BluetoothAdapter.STATE_TURNING_OFF:
// Avoid disabling when dependencies have been manually set, mCheckBox.setSummary(R.string.wifi_stopping);
// workaround for framework bug http://b/2053751 mCheckBox.setEnabled(false);
if (bluetoothAllowed) { break;
mCheckBoxPreference.setEnabled(true); case BluetoothAdapter.STATE_OFF:
} else if (!hasDependency) { mCheckBox.setChecked(false);
mCheckBoxPreference.setEnabled(false); mCheckBox.setSummary(mOriginalSummary);
} mCheckBox.setEnabled(true);
break;
} else if (state == BluetoothAdapter.STATE_TURNING_ON || default:
state == BluetoothAdapter.STATE_TURNING_OFF) { mCheckBox.setChecked(false);
mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_TURNING_ON mCheckBox.setSummary(R.string.wifi_error);
? R.string.wifi_starting mCheckBox.setEnabled(true);
: R.string.wifi_stopping);
} else {
mCheckBoxPreference.setChecked(false);
mCheckBoxPreference.setSummary(R.string.wifi_error);
mCheckBoxPreference.setEnabled(true);
} }
} }
private static boolean isBluetoothAllowed(Context context) {
// allowed if we are not in airplane mode
if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
return true;
}
// allowed if bluetooth is not in AIRPLANE_MODE_RADIOS
String radios = Settings.System.getString(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_RADIOS);
if (radios == null || !radios.contains(Settings.System.RADIO_BLUETOOTH)) {
return true;
}
// allowed if bluetooth is in AIRPLANE_MODE_TOGGLEABLE_RADIOS
radios = Settings.System.getString(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
return (radios != null && radios.contains(Settings.System.RADIO_BLUETOOTH));
}
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2007 The Android Open Source Project * Copyright (C) 2010 The Android Open Source Project
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,14 +16,8 @@
package com.android.settings.wifi; package com.android.settings.wifi;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.AirplaneModeEnabler; import com.android.settings.WirelessSettings;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@@ -35,169 +29,110 @@ import android.preference.Preference;
import android.preference.CheckBoxPreference; import android.preference.CheckBoxPreference;
import android.provider.Settings; import android.provider.Settings;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Config; import android.widget.Toast;
import android.util.Log;
public class WifiEnabler implements Preference.OnPreferenceChangeListener { public class WifiEnabler implements Preference.OnPreferenceChangeListener {
private static final boolean LOCAL_LOGD = Config.LOGD || WifiLayer.LOGV;
private static final String TAG = "SettingsWifiEnabler";
private final Context mContext; private final Context mContext;
private final WifiManager mWifiManager; private final CheckBoxPreference mCheckBox;
private final CheckBoxPreference mWifiCheckBoxPref;
private final CharSequence mOriginalSummary; private final CharSequence mOriginalSummary;
private final IntentFilter mWifiStateFilter;
private final BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() {
private final WifiManager mWifiManager;
private final IntentFilter mIntentFilter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { String action = intent.getAction();
handleWifiStateChanged( if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WIFI_STATE_UNKNOWN), handleWifiStateChanged(intent.getIntExtra(
intent.getIntExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
WIFI_STATE_UNKNOWN)); } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
} else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { handleNetworkStateChanged((NetworkInfo)
handleNetworkStateChanged( intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO));
(NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO));
} }
} }
}; };
public WifiEnabler(Context context, CheckBoxPreference wifiCheckBoxPreference) { public WifiEnabler(Context context, CheckBoxPreference checkBox) {
this(context, (WifiManager) context.getSystemService(Context.WIFI_SERVICE), this(context, (WifiManager) context.getSystemService(Context.WIFI_SERVICE),
wifiCheckBoxPreference); checkBox);
} }
public WifiEnabler(Context context, WifiManager wifiManager, public WifiEnabler(Context context, WifiManager wifiManager,
CheckBoxPreference wifiCheckBoxPreference) { CheckBoxPreference checkBox) {
mContext = context; mContext = context;
mWifiCheckBoxPref = wifiCheckBoxPreference; mCheckBox = checkBox;
mWifiManager = wifiManager; mWifiManager = wifiManager;
mOriginalSummary = checkBox.getSummary();
checkBox.setPersistent(false);
mOriginalSummary = wifiCheckBoxPreference.getSummary(); mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
wifiCheckBoxPreference.setPersistent(false); mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
} }
public void resume() { public void resume() {
int state = mWifiManager.getWifiState(); // Wi-Fi state is sticky, so just let the receiver update UI
// This is the widget enabled state, not the preference toggled state mContext.registerReceiver(mReceiver, mIntentFilter);
mWifiCheckBoxPref.setEnabled(state == WIFI_STATE_ENABLED || state == WIFI_STATE_DISABLED mCheckBox.setOnPreferenceChangeListener(this);
|| state == WIFI_STATE_UNKNOWN);
mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter);
mWifiCheckBoxPref.setOnPreferenceChangeListener(this);
} }
public void pause() { public void pause() {
mContext.unregisterReceiver(mWifiStateReceiver); mContext.unregisterReceiver(mReceiver);
mWifiCheckBoxPref.setOnPreferenceChangeListener(null); mCheckBox.setOnPreferenceChangeListener(null);
} }
public boolean onPreferenceChange(Preference preference, Object value) { public boolean onPreferenceChange(Preference preference, Object value) {
// Turn on/off Wi-Fi boolean enable = (Boolean) value;
setWifiEnabled((Boolean) value);
// Show toast message if Wi-Fi is not allowed in airplane mode
if (enable && !WirelessSettings
.isRadioAllowed(mContext, Settings.System.RADIO_WIFI)) {
Toast.makeText(mContext, R.string.wifi_in_airplane_mode,
Toast.LENGTH_SHORT).show();
return false;
}
if (mWifiManager.setWifiEnabled(enable)) {
mCheckBox.setEnabled(false);
} else {
mCheckBox.setSummary(R.string.wifi_error);
}
// Don't update UI to opposite state until we're sure // Don't update UI to opposite state until we're sure
return false; return false;
} }
private void setWifiEnabled(final boolean enable) { private void handleWifiStateChanged(int state) {
// Disable button switch (state) {
mWifiCheckBoxPref.setEnabled(false); case WifiManager.WIFI_STATE_ENABLING:
mCheckBox.setSummary(R.string.wifi_starting);
if (!mWifiManager.setWifiEnabled(enable)) { mCheckBox.setEnabled(false);
mWifiCheckBoxPref.setSummary(enable ? R.string.error_starting : R.string.error_stopping); break;
} case WifiManager.WIFI_STATE_ENABLED:
} mCheckBox.setChecked(true);
mCheckBox.setSummary(null);
private void handleWifiStateChanged(int wifiState, int previousWifiState) { mCheckBox.setEnabled(true);
break;
if (LOCAL_LOGD) { case WifiManager.WIFI_STATE_DISABLING:
Log.d(TAG, "Received wifi state changed from " mCheckBox.setSummary(R.string.wifi_stopping);
+ getHumanReadableWifiState(previousWifiState) + " to " mCheckBox.setEnabled(false);
+ getHumanReadableWifiState(wifiState)); break;
} case WifiManager.WIFI_STATE_DISABLED:
mCheckBox.setChecked(false);
if (wifiState == WIFI_STATE_DISABLED || wifiState == WIFI_STATE_ENABLED) { mCheckBox.setSummary(mOriginalSummary);
mWifiCheckBoxPref.setChecked(wifiState == WIFI_STATE_ENABLED); mCheckBox.setEnabled(true);
mWifiCheckBoxPref break;
.setSummary(wifiState == WIFI_STATE_DISABLED ? mOriginalSummary : null); default:
mCheckBox.setChecked(false);
final boolean hasDependency = !TextUtils.isEmpty(mWifiCheckBoxPref.getDependency()); mCheckBox.setSummary(R.string.wifi_error);
final boolean wifiAllowed = isWifiAllowed(mContext); mCheckBox.setEnabled(true);
// Avoid disabling when dependencies have been manually set,
// workaround for framework bug http://b/2053751
if (wifiAllowed) {
mWifiCheckBoxPref.setEnabled(true);
} else if (!hasDependency) {
mWifiCheckBoxPref.setEnabled(false);
}
} else if (wifiState == WIFI_STATE_DISABLING || wifiState == WIFI_STATE_ENABLING) {
mWifiCheckBoxPref.setSummary(wifiState == WIFI_STATE_ENABLING ? R.string.wifi_starting
: R.string.wifi_stopping);
} else if (wifiState == WIFI_STATE_UNKNOWN) {
int message = R.string.wifi_error;
if (previousWifiState == WIFI_STATE_ENABLING) message = R.string.error_starting;
else if (previousWifiState == WIFI_STATE_DISABLING) message = R.string.error_stopping;
mWifiCheckBoxPref.setChecked(false);
mWifiCheckBoxPref.setSummary(message);
mWifiCheckBoxPref.setEnabled(true);
} }
} }
private void handleNetworkStateChanged(NetworkInfo networkInfo) { private void handleNetworkStateChanged(NetworkInfo networkInfo) {
if (LOCAL_LOGD) {
Log.d(TAG, "Received network state changed to " + networkInfo);
}
if (mWifiManager.isWifiEnabled()) { if (mWifiManager.isWifiEnabled()) {
String summary = WifiStatus.getStatus(mContext, String summary = WifiStatus.getStatus(mContext,
mWifiManager.getConnectionInfo().getSSID(), networkInfo.getDetailedState()); mWifiManager.getConnectionInfo().getSSID(), networkInfo.getDetailedState());
mWifiCheckBoxPref.setSummary(summary); mCheckBox.setSummary(summary);
}
}
private static boolean isWifiAllowed(Context context) {
// allowed if we are not in airplane mode
if (!AirplaneModeEnabler.isAirplaneModeOn(context)) {
return true;
}
// allowed if wifi is not in AIRPLANE_MODE_RADIOS
String radios = Settings.System.getString(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_RADIOS);
if (radios == null || !radios.contains(Settings.System.RADIO_WIFI)) {
return true;
}
// allowed if wifi is in AIRPLANE_MODE_TOGGLEABLE_RADIOS
radios = Settings.System.getString(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
return (radios != null && radios.contains(Settings.System.RADIO_WIFI));
}
private static String getHumanReadableWifiState(int wifiState) {
switch (wifiState) {
case WIFI_STATE_DISABLED:
return "Disabled";
case WIFI_STATE_DISABLING:
return "Disabling";
case WIFI_STATE_ENABLED:
return "Enabled";
case WIFI_STATE_ENABLING:
return "Enabling";
case WIFI_STATE_UNKNOWN:
return "Unknown";
default:
return "Some other state!";
} }
} }
} }