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
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c289038..b86950b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -707,12 +707,14 @@
     <string name="ip_address">IP address</string>
     <!-- Label for the signal strength -->
     <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>
-    <!--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>
-    <!-- Generic error message , probably not used-->
+    <!-- Summary text when Wi-Fi or bluetooth has error -->
     <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 -->
     <string name="error_starting">Unable to start Wi-Fi</string>
     <!-- Error message when Wi-Fi can't stop -->
diff --git a/src/com/android/settings/WirelessSettings.java b/src/com/android/settings/WirelessSettings.java
index 1d0b2d8..bf75e27 100644
--- a/src/com/android/settings/WirelessSettings.java
+++ b/src/com/android/settings/WirelessSettings.java
@@ -17,6 +17,7 @@
 package com.android.settings;
 
 import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
 import android.content.Intent;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
@@ -67,7 +68,17 @@
         // Let the intents be launched by the Preference manager
         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
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -86,7 +97,7 @@
         String toggleable = Settings.System.getString(getContentResolver(),
                 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)) {
             wifi.setDependency(KEY_TOGGLE_AIRPLANE);
             findPreference(KEY_WIFI_SETTINGS).setDependency(KEY_TOGGLE_AIRPLANE);
@@ -99,7 +110,7 @@
             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) {
             findPreference(KEY_BT_SETTINGS).setEnabled(false);
         }
diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java
index 46793ce..426a4d3 100644
--- a/src/com/android/settings/bluetooth/BluetoothEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java
@@ -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");
  * you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
 
 package com.android.settings.bluetooth;
 
-import com.android.settings.AirplaneModeEnabler;
 import com.android.settings.R;
+import com.android.settings.WirelessSettings;
 
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
@@ -28,7 +28,7 @@
 import android.preference.CheckBoxPreference;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.Config;
+import android.widget.Toast;
 
 /**
  * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox
@@ -36,16 +36,12 @@
  * preference reflects the current state.
  */
 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 CheckBoxPreference mCheckBoxPreference;
+    private final CheckBoxPreference mCheckBox;
     private final CharSequence mOriginalSummary;
 
     private final LocalBluetoothManager mLocalManager;
-
+    private final IntentFilter mIntentFilter;
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -54,18 +50,18 @@
         }
     };
 
-    public BluetoothEnabler(Context context, CheckBoxPreference checkBoxPreference) {
+    public BluetoothEnabler(Context context, CheckBoxPreference checkBox) {
         mContext = context;
-        mCheckBoxPreference = checkBoxPreference;
-
-        mOriginalSummary = checkBoxPreference.getSummary();
-        checkBoxPreference.setPersistent(false);
+        mCheckBox = checkBox;
+        mOriginalSummary = checkBox.getSummary();
+        checkBox.setPersistent(false);
 
         mLocalManager = LocalBluetoothManager.getInstance(context);
         if (mLocalManager == null) {
-            // Bluetooth not supported
-            checkBoxPreference.setEnabled(false);
+            // Bluetooth is not supported
+            checkBox.setEnabled(false);
         }
+        mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
     }
 
     public void resume() {
@@ -73,16 +69,11 @@
             return;
         }
 
-        int state = mLocalManager.getBluetoothState();
-        // This is the widget enabled state, not the preference toggled state
-        mCheckBoxPreference.setEnabled(state == BluetoothAdapter.STATE_ON ||
-                state == BluetoothAdapter.STATE_OFF);
-        // BT state is not a sticky broadcast, so set it manually
-        handleStateChanged(state);
+        // Bluetooth state is not sticky, so set it manually
+        handleStateChanged(mLocalManager.getBluetoothState());
 
-        mContext.registerReceiver(mReceiver,
-                new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
-        mCheckBoxPreference.setOnPreferenceChangeListener(this);
+        mContext.registerReceiver(mReceiver, mIntentFilter);
+        mCheckBox.setOnPreferenceChangeListener(this);
     }
 
     public void pause() {
@@ -91,72 +82,51 @@
         }
 
         mContext.unregisterReceiver(mReceiver);
-        mCheckBoxPreference.setOnPreferenceChangeListener(null);
+        mCheckBox.setOnPreferenceChangeListener(null);
     }
 
     public boolean onPreferenceChange(Preference preference, Object value) {
-        // Turn on/off BT
-        setEnabled((Boolean) value);
+        boolean enable = (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
         return false;
     }
 
-    private void setEnabled(final boolean enable) {
-        // Disable preference
-        mCheckBoxPreference.setEnabled(false);
-
-        mLocalManager.setBluetoothEnabled(enable);
-    }
-
     private void handleStateChanged(int state) {
-
-        if (state == BluetoothAdapter.STATE_OFF ||
-                state == BluetoothAdapter.STATE_ON) {
-            mCheckBoxPreference.setChecked(state == BluetoothAdapter.STATE_ON);
-            mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_OFF ?
-                                           mOriginalSummary :
-                                           null);
-
-            final boolean hasDependency = !TextUtils.isEmpty(mCheckBoxPreference.getDependency());
-            final boolean bluetoothAllowed = isBluetoothAllowed(mContext);
-
-            // Avoid disabling when dependencies have been manually set,
-            // workaround for framework bug http://b/2053751
-            if (bluetoothAllowed) {
-                mCheckBoxPreference.setEnabled(true);
-            } else if (!hasDependency) {
-                mCheckBoxPreference.setEnabled(false);
-            }
-
-        } else if (state == BluetoothAdapter.STATE_TURNING_ON ||
-                state == BluetoothAdapter.STATE_TURNING_OFF) {
-            mCheckBoxPreference.setSummary(state == BluetoothAdapter.STATE_TURNING_ON
-                    ? R.string.wifi_starting
-                    : R.string.wifi_stopping);
-
-        } else {
-            mCheckBoxPreference.setChecked(false);
-            mCheckBoxPreference.setSummary(R.string.wifi_error);
-            mCheckBoxPreference.setEnabled(true);
+        switch (state) {
+            case BluetoothAdapter.STATE_TURNING_ON:
+                mCheckBox.setSummary(R.string.wifi_starting);
+                mCheckBox.setEnabled(false);
+                break;
+            case BluetoothAdapter.STATE_ON:
+                mCheckBox.setChecked(true);
+                mCheckBox.setSummary(null);
+                mCheckBox.setEnabled(true);
+                break;
+            case BluetoothAdapter.STATE_TURNING_OFF:
+                mCheckBox.setSummary(R.string.wifi_stopping);
+                mCheckBox.setEnabled(false);
+                break;
+            case BluetoothAdapter.STATE_OFF:
+                mCheckBox.setChecked(false);
+                mCheckBox.setSummary(mOriginalSummary);
+                mCheckBox.setEnabled(true);
+                break;
+            default:
+                mCheckBox.setChecked(false);
+                mCheckBox.setSummary(R.string.wifi_error);
+                mCheckBox.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));
-    }
-
 }
diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java
index b6e758d..d5376de 100644
--- a/src/com/android/settings/wifi/WifiEnabler.java
+++ b/src/com/android/settings/wifi/WifiEnabler.java
@@ -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");
  * you may not use this file except in compliance with the License.
@@ -16,14 +16,8 @@
 
 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.AirplaneModeEnabler;
+import com.android.settings.WirelessSettings;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -35,169 +29,110 @@
 import android.preference.CheckBoxPreference;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.util.Config;
-import android.util.Log;
+import android.widget.Toast;
 
 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 WifiManager mWifiManager;
-    private final CheckBoxPreference mWifiCheckBoxPref;
+    private final CheckBoxPreference mCheckBox;
     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
         public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
-                handleWifiStateChanged(
-                        intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WIFI_STATE_UNKNOWN),
-                        intent.getIntExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE,
-                                WIFI_STATE_UNKNOWN));
-            } else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                handleNetworkStateChanged(
-                        (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO));
+            String action = intent.getAction();
+            if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
+                handleWifiStateChanged(intent.getIntExtra(
+                        WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN));
+            } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
+                handleNetworkStateChanged((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),
-                wifiCheckBoxPreference);
+                checkBox);
     }
     
     public WifiEnabler(Context context, WifiManager wifiManager,
-            CheckBoxPreference wifiCheckBoxPreference) {
+            CheckBoxPreference checkBox) {
         mContext = context;
-        mWifiCheckBoxPref = wifiCheckBoxPreference;
+        mCheckBox = checkBox;
         mWifiManager = wifiManager;
+        mOriginalSummary = checkBox.getSummary();
+        checkBox.setPersistent(false);
         
-        mOriginalSummary = wifiCheckBoxPreference.getSummary();
-        wifiCheckBoxPreference.setPersistent(false);
-        
-        mWifiStateFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
-        mWifiStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+        mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
+        mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
     }
 
     public void resume() {
-        int state = mWifiManager.getWifiState();
-        // This is the widget enabled state, not the preference toggled state
-        mWifiCheckBoxPref.setEnabled(state == WIFI_STATE_ENABLED || state == WIFI_STATE_DISABLED
-                || state == WIFI_STATE_UNKNOWN);
-
-        mContext.registerReceiver(mWifiStateReceiver, mWifiStateFilter);
-        mWifiCheckBoxPref.setOnPreferenceChangeListener(this);
+        // Wi-Fi state is sticky, so just let the receiver update UI
+        mContext.registerReceiver(mReceiver, mIntentFilter);
+        mCheckBox.setOnPreferenceChangeListener(this);
     }
     
     public void pause() {
-        mContext.unregisterReceiver(mWifiStateReceiver);
-        mWifiCheckBoxPref.setOnPreferenceChangeListener(null);
+        mContext.unregisterReceiver(mReceiver);
+        mCheckBox.setOnPreferenceChangeListener(null);
     }
     
     public boolean onPreferenceChange(Preference preference, Object value) {
-        // Turn on/off Wi-Fi
-        setWifiEnabled((Boolean) value);
-        
+        boolean enable = (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
         return false;
     }
     
-    private void setWifiEnabled(final boolean enable) {
-        // Disable button
-        mWifiCheckBoxPref.setEnabled(false);
-        
-        if (!mWifiManager.setWifiEnabled(enable)) {
-            mWifiCheckBoxPref.setSummary(enable ? R.string.error_starting : R.string.error_stopping);
-        }
-    }
-    
-    private void handleWifiStateChanged(int wifiState, int previousWifiState) {
-
-        if (LOCAL_LOGD) {
-            Log.d(TAG, "Received wifi state changed from "
-                    + getHumanReadableWifiState(previousWifiState) + " to "
-                    + getHumanReadableWifiState(wifiState));
-        }
-        
-        if (wifiState == WIFI_STATE_DISABLED || wifiState == WIFI_STATE_ENABLED) {
-            mWifiCheckBoxPref.setChecked(wifiState == WIFI_STATE_ENABLED);
-            mWifiCheckBoxPref
-                    .setSummary(wifiState == WIFI_STATE_DISABLED ? mOriginalSummary : null);
-
-            final boolean hasDependency = !TextUtils.isEmpty(mWifiCheckBoxPref.getDependency());
-            final boolean wifiAllowed = isWifiAllowed(mContext);
-
-            // 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 handleWifiStateChanged(int state) {
+        switch (state) {
+            case WifiManager.WIFI_STATE_ENABLING:
+                mCheckBox.setSummary(R.string.wifi_starting);
+                mCheckBox.setEnabled(false);
+                break;
+            case WifiManager.WIFI_STATE_ENABLED:
+                mCheckBox.setChecked(true);
+                mCheckBox.setSummary(null);
+                mCheckBox.setEnabled(true);
+                break;
+            case WifiManager.WIFI_STATE_DISABLING:
+                mCheckBox.setSummary(R.string.wifi_stopping);
+                mCheckBox.setEnabled(false);
+                break;
+            case WifiManager.WIFI_STATE_DISABLED:
+                mCheckBox.setChecked(false);
+                mCheckBox.setSummary(mOriginalSummary);
+                mCheckBox.setEnabled(true);
+                break;
+            default:
+                mCheckBox.setChecked(false);
+                mCheckBox.setSummary(R.string.wifi_error);
+                mCheckBox.setEnabled(true);
         }
     }
 
     private void handleNetworkStateChanged(NetworkInfo networkInfo) {
-
-        if (LOCAL_LOGD) {
-            Log.d(TAG, "Received network state changed to " + networkInfo);
-        }
-        
         if (mWifiManager.isWifiEnabled()) {
             String summary = WifiStatus.getStatus(mContext, 
                     mWifiManager.getConnectionInfo().getSSID(), networkInfo.getDetailedState());
-            mWifiCheckBoxPref.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!";    
+            mCheckBox.setSummary(summary);
         }
     }
 }