Settings refactoring

Wifi and bluetooth pane refactored, main toggles moved to left pane.

Change-Id: I42ea4cf3bdf24158f3c67e0dea311258206cd78a
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 6d314ac..1f54b17 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -16,18 +16,33 @@
 
 package com.android.settings;
 
+import android.bluetooth.BluetoothAdapter;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
+import android.os.ServiceManager;
 import android.preference.PreferenceActivity;
+import android.text.TextUtils;
 import android.util.Log;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
 import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.Switch;
+import android.widget.TextView;
 
+import com.android.settings.bluetooth.BluetoothEnabler;
+import com.android.settings.wifi.WifiEnabler;
+
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 
@@ -36,10 +51,11 @@
  */
 public class Settings extends PreferenceActivity implements ButtonBarHandler {
 
+    private static final String LOG_TAG = "Settings";
     private static final String META_DATA_KEY_HEADER_ID =
-            "com.android.settings.TOP_LEVEL_HEADER_ID";
+        "com.android.settings.TOP_LEVEL_HEADER_ID";
     private static final String META_DATA_KEY_FRAGMENT_CLASS =
-            "com.android.settings.FRAGMENT_CLASS";
+        "com.android.settings.FRAGMENT_CLASS";
     private static final String META_DATA_KEY_PARENT_TITLE =
         "com.android.settings.PARENT_FRAGMENT_TITLE";
     private static final String META_DATA_KEY_PARENT_FRAGMENT_CLASS =
@@ -58,6 +74,7 @@
     // TODO: Update Call Settings based on airplane mode state.
 
     protected HashMap<Integer, Integer> mHeaderIndexMap = new HashMap<Integer, Integer>();
+    private List<Header> mHeaders;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -107,6 +124,26 @@
         }
     }
 
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        ListAdapter listAdapter = getListAdapter();
+        if (listAdapter instanceof HeaderAdapter) {
+            ((HeaderAdapter) listAdapter).resume();
+        }
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        ListAdapter listAdapter = getListAdapter();
+        if (listAdapter instanceof HeaderAdapter) {
+            ((HeaderAdapter) listAdapter).pause();
+        }
+    }
+
     private void switchToHeaderLocal(Header header) {
         mInLocalHeaderSwitch = true;
         switchToHeader(header);
@@ -148,7 +185,7 @@
                 mParentHeader.title = parentInfo.metaData.getString(META_DATA_KEY_PARENT_TITLE);
             }
         } catch (NameNotFoundException nnfe) {
-            Log.w("Settings", "Could not find parent activity : " + className);
+            Log.w(LOG_TAG, "Could not find parent activity : " + className);
         }
     }
 
@@ -174,21 +211,22 @@
 
     @Override
     public Intent getIntent() {
-        String startingFragment = getStartingFragmentClass(super.getIntent());
+        Intent superIntent = super.getIntent();
+        String startingFragment = getStartingFragmentClass(superIntent);
         if (startingFragment != null && !onIsMultiPane()) {
-            Intent modIntent = new Intent(super.getIntent());
+            Intent modIntent = new Intent(superIntent);
             modIntent.putExtra(EXTRA_SHOW_FRAGMENT, startingFragment);
-            Bundle args = super.getIntent().getExtras();
+            Bundle args = superIntent.getExtras();
             if (args != null) {
                 args = new Bundle(args);
             } else {
                 args = new Bundle();
             }
-            args.putParcelable("intent", super.getIntent());
-            modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, super.getIntent().getExtras());
+            args.putParcelable("intent", superIntent);
+            modIntent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, superIntent.getExtras());
             return modIntent;
         }
-        return super.getIntent();
+        return superIntent;
     }
 
     /**
@@ -204,7 +242,7 @@
         if ("com.android.settings.ManageApplications".equals(intentClass)
                 || "com.android.settings.RunningServices".equals(intentClass)
                 || "com.android.settings.applications.StorageUse".equals(intentClass)) {
-            // Old name of manage apps.
+            // Old names of manage apps.
             intentClass = com.android.settings.applications.ManageApplications.class.getName();
         }
 
@@ -226,7 +264,18 @@
             mCurrentHeader = header;
             return header;
         }
-        return super.onGetInitialHeader();
+
+        // Find first non-category header
+        int position = 0;
+        while (position < mHeaders.size()) {
+            Header header = mHeaders.get(position);
+            if (HeaderAdapter.getHeaderType(header) != HeaderAdapter.HEADER_TYPE_CATEGORY)
+                return header;
+            position++;
+        }
+
+        Log.e(LOG_TAG, "Unable to find a non-category header");
+        return null;
     }
 
     @Override
@@ -242,10 +291,12 @@
      * Populate the activity with the top-level headers.
      */
     @Override
-    public void onBuildHeaders(List<Header> target) {
-        loadHeadersFromResource(R.xml.settings_headers, target);
+    public void onBuildHeaders(List<Header> headers) {
+        loadHeadersFromResource(R.xml.settings_headers, headers);
 
-        updateHeaderList(target);
+        updateHeaderList(headers);
+
+        mHeaders = headers;
     }
 
     private void updateHeaderList(List<Header> target) {
@@ -262,7 +313,13 @@
             } else if (id == R.id.call_settings) {
                 if (!Utils.isVoiceCapable(this))
                     target.remove(header);
+            } else if (id == R.id.bluetooth_settings) {
+                // Remove Bluetooth Settings if Bluetooth service is not available.
+                if (ServiceManager.getService(BluetoothAdapter.BLUETOOTH_SERVICE) == null) {
+                    target.remove(header);
+                }
             }
+
             // Increment if the current one wasn't removed by the Utils code.
             if (target.get(i) == header) {
                 // Hold on to the first header, when we need to reset to the top-level
@@ -296,6 +353,7 @@
                 }
             }
         } catch (NameNotFoundException nnfe) {
+            // No recovery
         }
     }
 
@@ -309,39 +367,197 @@
         return super.getNextButton();
     }
 
+    private static class HeaderAdapter extends ArrayAdapter<Header> {
+        static final int HEADER_TYPE_CATEGORY = 0;
+        static final int HEADER_TYPE_NORMAL = 1;
+        static final int HEADER_TYPE_SWITCH = 2;
+        private static final int HEADER_TYPE_COUNT = HEADER_TYPE_SWITCH + 1;
+
+        private final WifiEnabler mWifiEnabler;
+        private final BluetoothEnabler mBluetoothEnabler;
+
+        private static class HeaderViewHolder {
+            ImageView icon;
+            TextView title;
+            TextView summary;
+            Switch switch_;
+        }
+
+        private LayoutInflater mInflater;
+
+        static int getHeaderType(Header header) {
+            if (header.fragment == null && header.intent == null) {
+                return HEADER_TYPE_CATEGORY;
+            } else if (header.id == R.id.wifi_settings || header.id == R.id.bluetooth_settings) {
+                return HEADER_TYPE_SWITCH;
+            } else {
+                return HEADER_TYPE_NORMAL;
+            }
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            Header header = getItem(position);
+            return getHeaderType(header);
+        }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false; // because of categories
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            return getItemViewType(position) != HEADER_TYPE_CATEGORY;
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return HEADER_TYPE_COUNT;
+        }
+
+        @Override
+        public boolean hasStableIds() {
+            return true;
+        }
+
+        public HeaderAdapter(Context context, List<Header> objects) {
+            super(context, 0, objects);
+            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+            
+            // These Switches are provided as placeholder until the adapter replaces these with actual
+            // Switches inflated from their layouts. Must be done before adapter is set in super
+            mWifiEnabler = new WifiEnabler(context, new Switch(context));
+            mBluetoothEnabler = new BluetoothEnabler(context, new Switch(context));
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            HeaderViewHolder holder;
+            Header header = getItem(position);
+            int headerType = getHeaderType(header);
+            View view = null;
+
+            if (convertView == null) {
+                holder = new HeaderViewHolder();
+                switch (headerType) {
+                    case HEADER_TYPE_CATEGORY:
+                        view = new TextView(getContext(), null, android.R.attr.listSeparatorTextViewStyle);
+                        holder.title = (TextView) view;
+                        break;
+
+                    case HEADER_TYPE_SWITCH:
+                        view = mInflater.inflate(R.layout.preference_header_switch_item, parent, false);
+                        holder.icon = (ImageView) view.findViewById(R.id.icon);
+                        holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
+                        holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
+                        holder.switch_ = (Switch) view.findViewById(R.id.switchWidget);
+                        break;
+
+                    case HEADER_TYPE_NORMAL:
+                        view = mInflater.inflate(com.android.internal.R.layout.preference_header_item, parent, false);
+                        holder.icon = (ImageView) view.findViewById(com.android.internal.R.id.icon);
+                        holder.title = (TextView) view.findViewById(com.android.internal.R.id.title);
+                        holder.summary = (TextView) view.findViewById(com.android.internal.R.id.summary);
+                        break;
+                }
+                view.setTag(holder);
+            } else {
+                view = convertView;
+                holder = (HeaderViewHolder) view.getTag();
+            }
+
+            // All view fields must be updated every time, because the view may be recycled
+            switch (headerType) {
+                case HEADER_TYPE_CATEGORY:
+                    holder.title.setText(header.getTitle(getContext().getResources()));
+                    break;
+
+                case HEADER_TYPE_SWITCH:
+                    // Would need a different treatment if the main menu had more switches
+                    if (header.id == R.id.wifi_settings) {
+                        mWifiEnabler.setSwitch(holder.switch_);
+                    } else {
+                        mBluetoothEnabler.setSwitch(holder.switch_);
+                    }
+                    // No break, fall through on purpose to update common fields
+
+                    //$FALL-THROUGH$
+                case HEADER_TYPE_NORMAL:
+                    holder.icon.setImageResource(header.iconRes);
+                    holder.title.setText(header.getTitle(getContext().getResources()));
+                    CharSequence summary = header.getSummary(getContext().getResources());
+                    if (!TextUtils.isEmpty(summary)) {
+                        holder.summary.setVisibility(View.VISIBLE);
+                        holder.summary.setText(summary);
+                    } else {
+                        holder.summary.setVisibility(View.GONE);
+                    }
+                    break;
+            }
+
+            return view;
+        }
+
+        public void resume() {
+            mWifiEnabler.resume();
+            mBluetoothEnabler.resume();
+        }
+        
+        public void pause() {
+            mWifiEnabler.pause();
+            mBluetoothEnabler.pause();
+        }
+    }
+
+    @Override
+    public void setListAdapter(ListAdapter adapter) {
+        if (mHeaders == null) {
+            mHeaders = new ArrayList<Header>();
+            // When the saved state provides the list of headers, onBuildHeaders is not called
+            // Copy the list of Headers from the adapter, preserving their order
+            for (int i = 0; i < adapter.getCount(); i++) {
+                mHeaders.add((Header) adapter.getItem(i));
+            }
+        }
+
+        // Ignore the adapter provided by PreferenceActivity and substitute ours instead
+        super.setListAdapter(new HeaderAdapter(this, mHeaders));
+    }
+
     /*
      * Settings subclasses for launching independently.
      */
 
-    public static class BluetoothSettingsActivity extends Settings { }
-    public static class WirelessSettingsActivity extends Settings { }
-    public static class TetherSettingsActivity extends Settings { }
-    public static class VpnSettingsActivity extends Settings { }
-    public static class DateTimeSettingsActivity extends Settings { }
-    public static class StorageSettingsActivity extends Settings { }
-    public static class WifiSettingsActivity extends Settings { }
-    public static class InputMethodAndLanguageSettingsActivity extends Settings { }
-    public static class InputMethodConfigActivity extends Settings { }
-    public static class InputMethodAndSubtypeEnablerActivity extends Settings { }
-    public static class LocalePickerActivity extends Settings { }
-    public static class UserDictionarySettingsActivity extends Settings { }
-    public static class SoundSettingsActivity extends Settings { }
-    public static class DisplaySettingsActivity extends Settings { }
-    public static class DeviceInfoSettingsActivity extends Settings { }
-    public static class ApplicationSettingsActivity extends Settings { }
-    public static class ManageApplicationsActivity extends Settings { }
-    public static class StorageUseActivity extends Settings { }
-    public static class DevelopmentSettingsActivity extends Settings { }
-    public static class AccessibilitySettingsActivity extends Settings { }
-    public static class SecuritySettingsActivity extends Settings { }
-    public static class PrivacySettingsActivity extends Settings { }
-    public static class DockSettingsActivity extends Settings { }
-    public static class RunningServicesActivity extends Settings { }
-    public static class ManageAccountsSettingsActivity extends Settings { }
-    public static class PowerUsageSummaryActivity extends Settings { }
-    public static class AccountSyncSettingsActivity extends Settings { }
-    public static class AccountSyncSettingsInAddAccountActivity extends Settings { }
-    public static class CryptKeeperSettingsActivity extends Settings { }
-    public static class DeviceAdminSettingsActivity extends Settings { }
-    public static class DataUsageSummaryActivity extends Settings { }
+    public static class BluetoothSettingsActivity extends Settings { /* empty */ }
+    public static class WirelessSettingsActivity extends Settings { /* empty */ }
+    public static class TetherSettingsActivity extends Settings { /* empty */ }
+    public static class VpnSettingsActivity extends Settings { /* empty */ }
+    public static class DateTimeSettingsActivity extends Settings { /* empty */ }
+    public static class StorageSettingsActivity extends Settings { /* empty */ }
+    public static class WifiSettingsActivity extends Settings { /* empty */ }
+    public static class InputMethodAndLanguageSettingsActivity extends Settings { /* empty */ }
+    public static class InputMethodConfigActivity extends Settings { /* empty */ }
+    public static class InputMethodAndSubtypeEnablerActivity extends Settings { /* empty */ }
+    public static class LocalePickerActivity extends Settings { /* empty */ }
+    public static class UserDictionarySettingsActivity extends Settings { /* empty */ }
+    public static class SoundSettingsActivity extends Settings { /* empty */ }
+    public static class DisplaySettingsActivity extends Settings { /* empty */ }
+    public static class DeviceInfoSettingsActivity extends Settings { /* empty */ }
+    public static class ApplicationSettingsActivity extends Settings { /* empty */ }
+    public static class ManageApplicationsActivity extends Settings { /* empty */ }
+    public static class StorageUseActivity extends Settings { /* empty */ }
+    public static class DevelopmentSettingsActivity extends Settings { /* empty */ }
+    public static class AccessibilitySettingsActivity extends Settings { /* empty */ }
+    public static class SecuritySettingsActivity extends Settings { /* empty */ }
+    public static class PrivacySettingsActivity extends Settings { /* empty */ }
+    public static class DockSettingsActivity extends Settings { /* empty */ }
+    public static class RunningServicesActivity extends Settings { /* empty */ }
+    public static class ManageAccountsSettingsActivity extends Settings { /* empty */ }
+    public static class PowerUsageSummaryActivity extends Settings { /* empty */ }
+    public static class AccountSyncSettingsActivity extends Settings { /* empty */ }
+    public static class AccountSyncSettingsInAddAccountActivity extends Settings { /* empty */ }
+    public static class CryptKeeperSettingsActivity extends Settings { /* empty */ }
+    public static class DeviceAdminSettingsActivity extends Settings { /* empty */ }
+    public static class DataUsageSummaryActivity extends Settings { /* empty */ }
 }