Changing preferences to PreferenceActivity.

Change-Id: I30f76e94c22828a9516cf2a72a2a772e0b4da44c
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d6b6bf2..334d97f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -301,10 +301,10 @@
             />
         </activity-alias>
 
-        <!-- Used to select display and sync groups -->
+        <!-- Used to set options -->
         <activity
-            android:name=".ui.ContactsPreferencesActivity"
-            android:label="@string/displayGroups"
+            android:name=".preference.ContactsPreferenceActivity"
+            android:label="@string/activity_title_settings"
             android:theme="@style/ContactsPreferencesTheme" />
 
         <!-- Used to select display and sync groups -->
diff --git a/res/menu/actions.xml b/res/menu/actions.xml
index 282f996..496b138 100644
--- a/res/menu/actions.xml
+++ b/res/menu/actions.xml
@@ -21,9 +21,9 @@
         android:showAsAction="always" />
 
     <item
-        android:id="@+id/menu_display_groups"
-        android:icon="@*android:drawable/ic_menu_allfriends"
-        android:title="@string/menu_displayGroup" />
+        android:id="@+id/menu_settings"
+        android:icon="@*android:drawable/ic_menu_preferences"
+        android:title="@string/menu_settings" />
 
     <item
         android:id="@+id/menu_accounts"
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
index 48923fe..439d68c 100644
--- a/res/values-xlarge/styles.xml
+++ b/res/values-xlarge/styles.xml
@@ -44,8 +44,9 @@
         <item name="list_item_photo_size">64dip</item>
     </style>
     
-    <style name="ContactsPreferencesTheme" parent="@android:Theme.Dialog">
+    <style name="ContactsPreferencesTheme" parent="@android:Theme.Light.Holo">
     </style>
+
     <style name="CallDetailActivityTheme" parent="@android:Theme.Dialog">
         <item name="android:windowContentOverlay">@null</item>
     </style>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0a88e78..fa712e1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -260,12 +260,6 @@
          For example, this may be used to set a phone number's label to "Vaction house" -->
     <string name="customLabelPickerTitle">Custom label name</string>
 
-    <!-- The menu item to open the list of groups to display -->
-    <string name="menu_displayGroup">Display options</string>
-
-    <!-- Title of activity that lets user pick which contact groups to display -->
-    <string name="displayGroups">Display options</string>
-
     <!-- Check box label that allows calls to the contact to be sent directly to voicemail -->
     <string name="send_to_voicemail_checkbox">Send calls directly to voicemail</string>
 
@@ -1329,4 +1323,14 @@
 
     <!-- Title of the activity that allows the user to customize filtering of contact list [CHAR LIMIT=128] -->
     <string name="custom_list_filter">Custom contact list</string>
+
+    <!-- Title of the settings activity [CHAR LIMIT=64] -->
+    <string name="activity_title_settings">Settings</string>
+
+    <!-- Menu item for the settings activity [CHAR LIMIT=64] -->
+    <string name="menu_settings">Settings</string>
+
+    <!-- The preference section title for contact display options [CHAR LIMIT=128] -->
+    <string name="preference_displayOptions">Display options</string>
+
 </resources>
diff --git a/res/xml/preference_display_options.xml b/res/xml/preference_display_options.xml
new file mode 100644
index 0000000..a662efa
--- /dev/null
+++ b/res/xml/preference_display_options.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    <PreferenceCategory
+        android:title="@string/preference_displayOptions">
+        <com.android.contacts.preference.SortOrderPreference
+            android:key="sortOrder"
+            android:title="@string/display_options_sort_list_by"
+            android:dialogTitle="@string/display_options_sort_list_by" />
+
+        <com.android.contacts.preference.DisplayOrderPreference
+            android:key="sortOrder"
+            android:title="@string/display_options_view_names_as"
+            android:dialogTitle="@string/display_options_view_names_as" />
+    </PreferenceCategory>
+</PreferenceScreen>
diff --git a/res/xml/preference_headers.xml b/res/xml/preference_headers.xml
new file mode 100644
index 0000000..ed709fc
--- /dev/null
+++ b/res/xml/preference_headers.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<preference-headers
+    xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <header
+        android:fragment="com.android.contacts.preference.DisplayOptionsPreferenceFragment"
+        android:title="@string/preference_displayOptions" />
+
+</preference-headers>
diff --git a/src/com/android/contacts/activities/ContactBrowserActivity.java b/src/com/android/contacts/activities/ContactBrowserActivity.java
index dd23455..09e19ff 100644
--- a/src/com/android/contacts/activities/ContactBrowserActivity.java
+++ b/src/com/android/contacts/activities/ContactBrowserActivity.java
@@ -28,7 +28,7 @@
 import com.android.contacts.list.DefaultContactBrowseListFragment;
 import com.android.contacts.list.OnContactBrowserActionListener;
 import com.android.contacts.list.StrequentContactListFragment;
-import com.android.contacts.ui.ContactsPreferencesActivity;
+import com.android.contacts.preference.ContactsPreferenceActivity;
 import com.android.contacts.util.DialogManager;
 import com.android.contacts.views.ContactSaveService;
 import com.android.contacts.views.detail.ContactDetailFragment;
@@ -74,7 +74,7 @@
     private static final String KEY_MODE = "mode";
 
     private static final int SUBACTIVITY_NEW_CONTACT = 2;
-    private static final int SUBACTIVITY_DISPLAY_GROUP = 3;
+    private static final int SUBACTIVITY_SETTINGS = 3;
     private static final int SUBACTIVITY_EDIT_CONTACT = 4;
 
     private DialogManager mDialogManager = new DialogManager(this);
@@ -643,9 +643,9 @@
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
-            case R.id.menu_display_groups: {
-                final Intent intent = new Intent(this, ContactsPreferencesActivity.class);
-                startActivityForResult(intent, SUBACTIVITY_DISPLAY_GROUP);
+            case R.id.menu_settings: {
+                final Intent intent = new Intent(this, ContactsPreferenceActivity.class);
+                startActivityForResult(intent, SUBACTIVITY_SETTINGS);
                 return true;
             }
             case R.id.menu_search: {
@@ -741,7 +741,7 @@
                 break;
             }
 
-            case SUBACTIVITY_DISPLAY_GROUP:
+            case SUBACTIVITY_SETTINGS:
                 // TODO: Force the ListFragment to reload its setting and update (don't lookup
                 // directories here)
                 break;
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index 49852a7..7b9142b 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -22,7 +22,7 @@
 import com.android.contacts.ContactPhotoLoader;
 import com.android.contacts.ContactsSearchManager;
 import com.android.contacts.R;
-import com.android.contacts.ui.ContactsPreferences;
+import com.android.contacts.preference.ContactsPreferences;
 import com.android.contacts.widget.ContextMenuAdapter;
 
 import android.accounts.Account;
diff --git a/src/com/android/contacts/list/CustomContactListFilterActivity.java b/src/com/android/contacts/list/CustomContactListFilterActivity.java
index b6c6f4c..4cb58af 100644
--- a/src/com/android/contacts/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/list/CustomContactListFilterActivity.java
@@ -22,6 +22,7 @@
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.model.GoogleSource;
 import com.android.contacts.model.Sources;
+import com.android.contacts.preference.ContactsPreferences;
 import com.android.contacts.util.EmptyService;
 import com.android.contacts.util.LocalizedNameResolver;
 import com.android.contacts.util.WeakAsyncTask;
@@ -81,9 +82,6 @@
 
     private static final String TAG = "CustomContactListFilterActivity";
 
-    public static final boolean PREF_DISPLAY_ONLY_PHONES_DEFAULT = false;
-    public static final String PREF_DISPLAY_ONLY_PHONES = "only_phones";
-
     private ExpandableListView mList;
     private DisplayAdapter mAdapter;
 
@@ -122,8 +120,8 @@
         mHeaderPhones = inflater.inflate(R.layout.display_options_phones_only, mList, false);
         mHeaderPhones.setId(R.id.header_phones);
         mDisplayPhones = (CheckBox) mHeaderPhones.findViewById(android.R.id.checkbox);
-        mDisplayPhones.setChecked(
-                mPrefs.getBoolean(PREF_DISPLAY_ONLY_PHONES, PREF_DISPLAY_ONLY_PHONES_DEFAULT));
+        mDisplayPhones.setChecked(mPrefs.getBoolean(ContactsPreferences.PREF_DISPLAY_ONLY_PHONES,
+                ContactsPreferences.PREF_DISPLAY_ONLY_PHONES_DEFAULT));
         {
             final TextView text1 = (TextView)mHeaderPhones.findViewById(android.R.id.text1);
             final TextView text2 = (TextView)mHeaderPhones.findViewById(android.R.id.text2);
@@ -681,14 +679,14 @@
     }
 
     /**
-     * Assign a specific value to {@link #PREF_DISPLAY_ONLY_PHONES}, refreshing
+     * Assign a specific value to {@link ContactsPreferences#PREF_DISPLAY_ONLY_PHONES}, refreshing
      * the visible list as needed.
      */
     protected void setDisplayOnlyPhones(boolean displayOnlyPhones) {
         mDisplayPhones.setChecked(displayOnlyPhones);
 
         Editor editor = mPrefs.edit();
-        editor.putBoolean(PREF_DISPLAY_ONLY_PHONES, displayOnlyPhones);
+        editor.putBoolean(ContactsPreferences.PREF_DISPLAY_ONLY_PHONES, displayOnlyPhones);
         editor.apply();
 
         mAdapter.setChildDescripWithPhones(displayOnlyPhones);
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 9f6fec0..0cc8901 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -16,7 +16,7 @@
 package com.android.contacts.list;
 
 import com.android.contacts.R;
-import com.android.contacts.ui.ContactsPreferencesActivity.Prefs;
+import com.android.contacts.preference.ContactsPreferences;
 import com.android.contacts.widget.NotifyingSpinner;
 
 import android.app.Activity;
@@ -134,8 +134,8 @@
             case ContactsRequest.DISPLAY_ONLY_WITH_PHONES_PREFERENCE:
                 SharedPreferences prefs = PreferenceManager
                         .getDefaultSharedPreferences(getContext());
-                return prefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
-                        Prefs.DISPLAY_ONLY_PHONES_DEFAULT);
+                return prefs.getBoolean(ContactsPreferences.PREF_DISPLAY_ONLY_PHONES,
+                        ContactsPreferences.PREF_DISPLAY_ONLY_PHONES_DEFAULT);
         }
         return false;
     }
diff --git a/src/com/android/contacts/preference/ContactsPreferenceActivity.java b/src/com/android/contacts/preference/ContactsPreferenceActivity.java
new file mode 100644
index 0000000..0828abe
--- /dev/null
+++ b/src/com/android/contacts/preference/ContactsPreferenceActivity.java
@@ -0,0 +1,1100 @@
+/*
+ * Copyright (C) 2009 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.preference;
+
+import com.android.contacts.ContactsSearchManager;
+import com.android.contacts.R;
+import com.android.contacts.model.ContactsSource;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.GoogleSource;
+import com.android.contacts.model.Sources;
+import com.android.contacts.util.EmptyService;
+import com.android.contacts.util.LocalizedNameResolver;
+import com.android.contacts.util.WeakAsyncTask;
+import com.google.android.collect.Lists;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ExpandableListActivity;
+import android.app.ProgressDialog;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderOperation.Builder;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.EntityIterator;
+import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceActivity.Header;
+import android.preference.PreferenceManager;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Groups;
+import android.provider.ContactsContract.Settings;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.CheckBox;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Contacts settings.
+ */
+public final class ContactsPreferenceActivity extends PreferenceActivity
+//implements
+//        AdapterView.OnItemClickListener, View.OnClickListener
+        {
+    private static final String TAG = "ContactsSettingsActivity";
+
+    /**
+     * Populate the activity with the top-level headers.
+     */
+    @Override
+    public void onBuildHeaders(List<Header> target) {
+        loadHeadersFromResource(R.xml.preference_headers, target);
+    }
+
+
+//    public interface Prefs {
+//        public static final String DISPLAY_ONLY_PHONES = "only_phones";
+//        public static final boolean DISPLAY_ONLY_PHONES_DEFAULT = false;
+//
+//    }
+//
+//    private static final int DIALOG_SORT_ORDER = 1;
+//    private static final int DIALOG_DISPLAY_ORDER = 2;
+//
+//    private ExpandableListView mList;
+//    private DisplayAdapter mAdapter;
+//
+//    private SharedPreferences mPrefs;
+//    private ContactsPreferences mContactsPrefs;
+//
+//    private CheckBox mDisplayPhones;
+//
+//    private View mHeaderPhones;
+//    private View mHeaderSeparator;
+//
+//    private View mSortOrderView;
+//    private TextView mSortOrderTextView;
+//    private int mSortOrder;
+//
+//    private View mDisplayOrderView;
+//    private TextView mDisplayOrderTextView;
+//    private int mDisplayOrder;
+//
+//    @Override
+//    protected void onCreate(Bundle icicle) {
+//        super.onCreate(icicle);
+//        setContentView(R.layout.contacts_preferences);
+//
+//        mList = getExpandableListView();
+//        mList.setHeaderDividersEnabled(true);
+//        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+//        mContactsPrefs = new ContactsPreferences(this);
+//        mAdapter = new DisplayAdapter(this);
+//
+//        final LayoutInflater inflater = getLayoutInflater();
+//
+//        createWithPhonesOnlyPreferenceView(inflater);
+//        createSortOrderPreferenceView(inflater);
+//        createDisplayOrderPreferenceView(inflater);
+//        createDisplayGroupHeader(inflater);
+//
+//        findViewById(R.id.btn_done).setOnClickListener(this);
+//        findViewById(R.id.btn_discard).setOnClickListener(this);
+//
+//        // Catch clicks on the header views
+//        mList.setOnItemClickListener(this);
+//        mList.setOnCreateContextMenuListener(this);
+//
+//        mSortOrder = mContactsPrefs.getSortOrder();
+//        mDisplayOrder = mContactsPrefs.getDisplayOrder();
+//    }
+//
+//    private void createWithPhonesOnlyPreferenceView(LayoutInflater inflater) {
+//        // Add the "Only contacts with phones" header modifier.
+//        mHeaderPhones = inflater.inflate(R.layout.display_options_phones_only, mList, false);
+//        mHeaderPhones.setId(R.id.header_phones);
+//        mDisplayPhones = (CheckBox) mHeaderPhones.findViewById(android.R.id.checkbox);
+//        mDisplayPhones.setChecked(mPrefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
+//                Prefs.DISPLAY_ONLY_PHONES_DEFAULT));
+//        {
+//            final TextView text1 = (TextView)mHeaderPhones.findViewById(android.R.id.text1);
+//            final TextView text2 = (TextView)mHeaderPhones.findViewById(android.R.id.text2);
+//            text1.setText(R.string.showFilterPhones);
+//            text2.setText(R.string.showFilterPhonesDescrip);
+//        }
+//    }
+//
+//    private void createSortOrderPreferenceView(LayoutInflater inflater) {
+//        mSortOrderView = inflater.inflate(R.layout.preference_with_more_button, mList, false);
+//
+//        View preferenceLayout = mSortOrderView.findViewById(R.id.preference);
+//
+//        TextView label = (TextView)preferenceLayout.findViewById(R.id.label);
+//        label.setText(getString(R.string.display_options_sort_list_by));
+//
+//        mSortOrderTextView = (TextView)preferenceLayout.findViewById(R.id.data);
+//    }
+//
+//    private void createDisplayOrderPreferenceView(LayoutInflater inflater) {
+//        mDisplayOrderView = inflater.inflate(R.layout.preference_with_more_button, mList, false);
+//        View preferenceLayout = mDisplayOrderView.findViewById(R.id.preference);
+//
+//        TextView label = (TextView)preferenceLayout.findViewById(R.id.label);
+//        label.setText(getString(R.string.display_options_view_names_as));
+//
+//        mDisplayOrderTextView = (TextView)preferenceLayout.findViewById(R.id.data);
+//    }
+//
+//    private void createDisplayGroupHeader(LayoutInflater inflater) {
+//        // Add the separator before showing the detailed group list.
+//        mHeaderSeparator = inflater.inflate(R.layout.list_separator, mList, false);
+//        {
+//            final TextView text1 = (TextView)mHeaderSeparator;
+//            text1.setText(R.string.headerContactGroups);
+//        }
+//    }
+//
+//    @Override
+//    protected void onResume() {
+//        super.onResume();
+//        mList.removeHeaderView(mHeaderPhones);
+//        mList.removeHeaderView(mSortOrderView);
+//        mList.removeHeaderView(mDisplayOrderView);
+//        mList.removeHeaderView(mHeaderSeparator);
+//
+//        // List adapter needs to be reset, because header views cannot be added
+//        // to a list with an existing adapter.
+//        setListAdapter(null);
+//
+//        mList.addHeaderView(mHeaderPhones, null, true);
+//        if (mContactsPrefs.isSortOrderUserChangeable()) {
+//            mList.addHeaderView(mSortOrderView, null, true);
+//        }
+//
+//        if (mContactsPrefs.isSortOrderUserChangeable()) {
+//            mList.addHeaderView(mDisplayOrderView, null, true);
+//        }
+//
+//        mList.addHeaderView(mHeaderSeparator, null, false);
+//
+//        setListAdapter(mAdapter);
+//
+//        bindView();
+//
+//        // Start background query to find account details
+//        new QueryGroupsTask(this).execute();
+//    }
+//
+//    private void bindView() {
+//        mSortOrderTextView.setText(
+//                mSortOrder == ContactsContract.Preferences.SORT_ORDER_PRIMARY
+//                        ? getString(R.string.display_options_sort_by_given_name)
+//                        : getString(R.string.display_options_sort_by_family_name));
+//
+//        mDisplayOrderTextView.setText(
+//                mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY
+//                        ? getString(R.string.display_options_view_given_name_first)
+//                        : getString(R.string.display_options_view_family_name_first));
+//    }
+//
+//    @Override
+//    protected Dialog onCreateDialog(int id, Bundle args) {
+//        switch (id) {
+//            case DIALOG_SORT_ORDER:
+//                return createSortOrderDialog();
+//            case DIALOG_DISPLAY_ORDER:
+//                return createDisplayOrderDialog();
+//        }
+//
+//        return null;
+//    }
+//
+//    private Dialog createSortOrderDialog() {
+//        String[] items = new String[] {
+//                getString(R.string.display_options_sort_by_given_name),
+//                getString(R.string.display_options_sort_by_family_name),
+//        };
+//
+//        return new AlertDialog.Builder(this)
+//            .setIcon(com.android.internal.R.drawable.ic_dialog_menu_generic)
+//            .setTitle(R.string.display_options_sort_list_by)
+//            .setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
+//                    public void onClick(DialogInterface dialog, int whichButton) {
+//                        setSortOrder(dialog);
+//                        dialog.dismiss();
+//                    }
+//                })
+//            .setNegativeButton(android.R.string.cancel, null)
+//            .create();
+//    }
+//
+//    private Dialog createDisplayOrderDialog() {
+//        String[] items = new String[] {
+//                getString(R.string.display_options_view_given_name_first),
+//                getString(R.string.display_options_view_family_name_first),
+//        };
+//
+//        return new AlertDialog.Builder(this)
+//            .setIcon(com.android.internal.R.drawable.ic_dialog_menu_generic)
+//            .setTitle(R.string.display_options_view_names_as)
+//            .setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
+//                    public void onClick(DialogInterface dialog, int whichButton) {
+//                        setDisplayOrder(dialog);
+//                        dialog.dismiss();
+//                    }
+//                })
+//            .setNegativeButton(android.R.string.cancel, null)
+//            .create();
+//    }
+//
+//    @Override
+//    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
+//        switch (id) {
+//            case DIALOG_SORT_ORDER:
+//                setCheckedItem(dialog,
+//                        mSortOrder == ContactsContract.Preferences.SORT_ORDER_PRIMARY ? 0 : 1);
+//                break;
+//            case DIALOG_DISPLAY_ORDER:
+//                setCheckedItem(dialog,
+//                        mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY
+//                                ? 0 : 1);
+//                break;
+//        }
+//    }
+//
+//    private void setCheckedItem(Dialog dialog, int position) {
+//        ListView listView = ((AlertDialog)dialog).getListView();
+//        listView.setItemChecked(position, true);
+//        listView.setSelection(position);
+//    }
+//
+//    protected void setSortOrder(DialogInterface dialog) {
+//        ListView listView = ((AlertDialog)dialog).getListView();
+//        int checked = listView.getCheckedItemPosition();
+//        mSortOrder = checked == 0
+//                ? ContactsContract.Preferences.SORT_ORDER_PRIMARY
+//                : ContactsContract.Preferences.SORT_ORDER_ALTERNATIVE;
+//
+//        bindView();
+//    }
+//
+//    protected void setDisplayOrder(DialogInterface dialog) {
+//        ListView listView = ((AlertDialog)dialog).getListView();
+//        int checked = listView.getCheckedItemPosition();
+//        mDisplayOrder = checked == 0
+//                ? ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY
+//                : ContactsContract.Preferences.DISPLAY_ORDER_ALTERNATIVE;
+//
+//        bindView();
+//    }
+//
+//    /**
+//     * Background operation to build set of {@link AccountDisplay} for each
+//     * {@link Sources#getAccounts(boolean)} that provides groups.
+//     */
+//    private static class QueryGroupsTask extends
+//            WeakAsyncTask<Void, Void, AccountSet, ContactsPreferenceActivity> {
+//        public QueryGroupsTask(ContactsPreferenceActivity target) {
+//            super(target);
+//        }
+//
+//        @Override
+//        protected AccountSet doInBackground(ContactsPreferenceActivity target,
+//                Void... params) {
+//            final Context context = target;
+//            final Sources sources = Sources.getInstance(context);
+//            final ContentResolver resolver = context.getContentResolver();
+//
+//            // Inflate groups entry for each account
+//            final AccountSet accounts = new AccountSet();
+//            for (Account account : sources.getAccounts(false)) {
+//                accounts.add(new AccountDisplay(resolver, account.name, account.type));
+//            }
+//
+//            return accounts;
+//        }
+//
+//        @Override
+//        protected void onPostExecute(ContactsPreferenceActivity target, AccountSet result) {
+//            target.mAdapter.setAccounts(result);
+//        }
+//    }
+//
+//    private static final int DEFAULT_SHOULD_SYNC = 1;
+//    private static final int DEFAULT_VISIBLE = 0;
+//
+//    /**
+//     * Entry holding any changes to {@link Groups} or {@link Settings} rows,
+//     * such as {@link Groups#SHOULD_SYNC} or {@link Groups#GROUP_VISIBLE}.
+//     */
+//    protected static class GroupDelta extends ValuesDelta {
+//        private boolean mUngrouped = false;
+//        private boolean mAccountHasGroups;
+//
+//        private GroupDelta() {
+//            super();
+//        }
+//
+//        /**
+//         * Build {@link GroupDelta} from the {@link Settings} row for the given
+//         * {@link Settings#ACCOUNT_NAME} and {@link Settings#ACCOUNT_TYPE}.
+//         */
+//        public static GroupDelta fromSettings(ContentResolver resolver, String accountName,
+//                String accountType, boolean accountHasGroups) {
+//            final Uri settingsUri = Settings.CONTENT_URI.buildUpon()
+//                    .appendQueryParameter(Settings.ACCOUNT_NAME, accountName)
+//                    .appendQueryParameter(Settings.ACCOUNT_TYPE, accountType).build();
+//            final Cursor cursor = resolver.query(settingsUri, new String[] {
+//                    Settings.SHOULD_SYNC, Settings.UNGROUPED_VISIBLE
+//            }, null, null, null);
+//
+//            try {
+//                final ContentValues values = new ContentValues();
+//                values.put(Settings.ACCOUNT_NAME, accountName);
+//                values.put(Settings.ACCOUNT_TYPE, accountType);
+//
+//                if (cursor != null && cursor.moveToFirst()) {
+//                    // Read existing values when present
+//                    values.put(Settings.SHOULD_SYNC, cursor.getInt(0));
+//                    values.put(Settings.UNGROUPED_VISIBLE, cursor.getInt(1));
+//                    return fromBefore(values).setUngrouped(accountHasGroups);
+//                } else {
+//                    // Nothing found, so treat as create
+//                    values.put(Settings.SHOULD_SYNC, DEFAULT_SHOULD_SYNC);
+//                    values.put(Settings.UNGROUPED_VISIBLE, DEFAULT_VISIBLE);
+//                    return fromAfter(values).setUngrouped(accountHasGroups);
+//                }
+//            } finally {
+//                if (cursor != null) cursor.close();
+//            }
+//        }
+//
+//        public static GroupDelta fromBefore(ContentValues before) {
+//            final GroupDelta entry = new GroupDelta();
+//            entry.mBefore = before;
+//            entry.mAfter = new ContentValues();
+//            return entry;
+//        }
+//
+//        public static GroupDelta fromAfter(ContentValues after) {
+//            final GroupDelta entry = new GroupDelta();
+//            entry.mBefore = null;
+//            entry.mAfter = after;
+//            return entry;
+//        }
+//
+//        protected GroupDelta setUngrouped(boolean accountHasGroups) {
+//            mUngrouped = true;
+//            mAccountHasGroups = accountHasGroups;
+//            return this;
+//        }
+//
+//        @Override
+//        public boolean beforeExists() {
+//            return mBefore != null;
+//        }
+//
+//        public boolean getShouldSync() {
+//            return getAsInteger(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC,
+//                    DEFAULT_SHOULD_SYNC) != 0;
+//        }
+//
+//        public boolean getVisible() {
+//            return getAsInteger(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE,
+//                    DEFAULT_VISIBLE) != 0;
+//        }
+//
+//        public void putShouldSync(boolean shouldSync) {
+//            put(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
+//        }
+//
+//        public void putVisible(boolean visible) {
+//            put(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE, visible ? 1 : 0);
+//        }
+//
+//        private String getAccountType() {
+//            return (mBefore == null ? mAfter : mBefore).getAsString(Settings.ACCOUNT_TYPE);
+//        }
+//
+//        public CharSequence getTitle(Context context) {
+//            if (mUngrouped) {
+//                final String customAllContactsName =
+//                        LocalizedNameResolver.getAllContactsName(context, getAccountType());
+//                if (customAllContactsName != null) {
+//                    return customAllContactsName;
+//                }
+//                if (mAccountHasGroups) {
+//                    return context.getText(R.string.display_ungrouped);
+//                } else {
+//                    return context.getText(R.string.display_all_contacts);
+//                }
+//            } else {
+//                final Integer titleRes = getAsInteger(Groups.TITLE_RES);
+//                if (titleRes != null) {
+//                    final String packageName = getAsString(Groups.RES_PACKAGE);
+//                    return context.getPackageManager().getText(packageName, titleRes, null);
+//                } else {
+//                    return getAsString(Groups.TITLE);
+//                }
+//            }
+//        }
+//
+//        /**
+//         * Build a possible {@link ContentProviderOperation} to persist any
+//         * changes to the {@link Groups} or {@link Settings} row described by
+//         * this {@link GroupDelta}.
+//         */
+//        public ContentProviderOperation buildDiff() {
+//            if (isNoop()) {
+//                return null;
+//            } else if (isUpdate()) {
+//                // When has changes and "before" exists, then "update"
+//                final Builder builder = ContentProviderOperation
+//                        .newUpdate(mUngrouped ? Settings.CONTENT_URI : addCallerIsSyncAdapterParameter(Groups.CONTENT_URI));
+//                if (mUngrouped) {
+//                    builder.withSelection(Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE
+//                            + "=?", new String[] {
+//                            this.getAsString(Settings.ACCOUNT_NAME),
+//                            this.getAsString(Settings.ACCOUNT_TYPE)
+//                    });
+//                } else {
+//                    builder.withSelection(Groups._ID + "=" + this.getId(), null);
+//                }
+//                builder.withValues(mAfter);
+//                return builder.build();
+//            } else if (isInsert() && mUngrouped) {
+//                // Only allow inserts for Settings
+//                mAfter.remove(mIdColumn);
+//                final Builder builder = ContentProviderOperation.newInsert(Settings.CONTENT_URI);
+//                builder.withValues(mAfter);
+//                return builder.build();
+//            } else {
+//                throw new IllegalStateException("Unexpected delete or insert");
+//            }
+//        }
+//    }
+//
+//    private static Uri addCallerIsSyncAdapterParameter(Uri uri) {
+//        return uri.buildUpon()
+//	        .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
+//	        .build();
+//    }
+//
+//    /**
+//     * {@link Comparator} to sort by {@link Groups#_ID}.
+//     */
+//    private static Comparator<GroupDelta> sIdComparator = new Comparator<GroupDelta>() {
+//        public int compare(GroupDelta object1, GroupDelta object2) {
+//            final Long id1 = object1.getId();
+//            final Long id2 = object2.getId();
+//            if (id1 == null && id2 == null) {
+//                return 0;
+//            } else if (id1 == null) {
+//                return -1;
+//            } else if (id2 == null) {
+//                return 1;
+//            } else if (id1 < id2) {
+//                return -1;
+//            } else if (id1 > id2) {
+//                return 1;
+//            } else {
+//                return 0;
+//            }
+//        }
+//    };
+//
+//    /**
+//     * Set of all {@link AccountDisplay} entries, one for each source.
+//     */
+//    protected static class AccountSet extends ArrayList<AccountDisplay> {
+//        public ArrayList<ContentProviderOperation> buildDiff() {
+//            final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
+//            for (AccountDisplay account : this) {
+//                account.buildDiff(diff);
+//            }
+//            return diff;
+//        }
+//    }
+//
+//    /**
+//     * {@link GroupDelta} details for a single {@link Account}, usually shown as
+//     * children under a single expandable group.
+//     */
+//    protected static class AccountDisplay {
+//        public String mName;
+//        public String mType;
+//
+//        public GroupDelta mUngrouped;
+//        public ArrayList<GroupDelta> mSyncedGroups = Lists.newArrayList();
+//        public ArrayList<GroupDelta> mUnsyncedGroups = Lists.newArrayList();
+//
+//        /**
+//         * Build an {@link AccountDisplay} covering all {@link Groups} under the
+//         * given {@link Account}.
+//         */
+//        public AccountDisplay(ContentResolver resolver, String accountName, String accountType) {
+//            mName = accountName;
+//            mType = accountType;
+//
+//            final Uri groupsUri = Groups.CONTENT_URI.buildUpon()
+//                    .appendQueryParameter(Groups.ACCOUNT_NAME, accountName)
+//                    .appendQueryParameter(Groups.ACCOUNT_TYPE, accountType).build();
+//            EntityIterator iterator = ContactsContract.Groups.newEntityIterator(resolver.query(
+//                    groupsUri, null, null, null, null));
+//            try {
+//                boolean hasGroups = false;
+//
+//                // Create entries for each known group
+//                while (iterator.hasNext()) {
+//                    final ContentValues values = iterator.next().getEntityValues();
+//                    final GroupDelta group = GroupDelta.fromBefore(values);
+//                    addGroup(group);
+//                    hasGroups = true;
+//                }
+//                // Create single entry handling ungrouped status
+//                mUngrouped = GroupDelta.fromSettings(resolver, accountName, accountType, hasGroups);
+//                addGroup(mUngrouped);
+//            } finally {
+//                iterator.close();
+//            }
+//        }
+//
+//        /**
+//         * Add the given {@link GroupDelta} internally, filing based on its
+//         * {@link GroupDelta#getShouldSync()} status.
+//         */
+//        private void addGroup(GroupDelta group) {
+//            if (group.getShouldSync()) {
+//                mSyncedGroups.add(group);
+//            } else {
+//                mUnsyncedGroups.add(group);
+//            }
+//        }
+//
+//        /**
+//         * Set the {@link GroupDelta#putShouldSync(boolean)} value for all
+//         * children {@link GroupDelta} rows.
+//         */
+//        public void setShouldSync(boolean shouldSync) {
+//            final Iterator<GroupDelta> oppositeChildren = shouldSync ?
+//                    mUnsyncedGroups.iterator() : mSyncedGroups.iterator();
+//            while (oppositeChildren.hasNext()) {
+//                final GroupDelta child = oppositeChildren.next();
+//                setShouldSync(child, shouldSync, false);
+//                oppositeChildren.remove();
+//            }
+//        }
+//
+//        public void setShouldSync(GroupDelta child, boolean shouldSync) {
+//            setShouldSync(child, shouldSync, true);
+//        }
+//
+//        /**
+//         * Set {@link GroupDelta#putShouldSync(boolean)}, and file internally
+//         * based on updated state.
+//         */
+//        public void setShouldSync(GroupDelta child, boolean shouldSync, boolean attemptRemove) {
+//            child.putShouldSync(shouldSync);
+//            if (shouldSync) {
+//                if (attemptRemove) {
+//                    mUnsyncedGroups.remove(child);
+//                }
+//                mSyncedGroups.add(child);
+//                Collections.sort(mSyncedGroups, sIdComparator);
+//            } else {
+//                if (attemptRemove) {
+//                    mSyncedGroups.remove(child);
+//                }
+//                mUnsyncedGroups.add(child);
+//            }
+//        }
+//
+//        /**
+//         * Build set of {@link ContentProviderOperation} to persist any user
+//         * changes to {@link GroupDelta} rows under this {@link Account}.
+//         */
+//        public void buildDiff(ArrayList<ContentProviderOperation> diff) {
+//            for (GroupDelta group : mSyncedGroups) {
+//                final ContentProviderOperation oper = group.buildDiff();
+//                if (oper != null) diff.add(oper);
+//            }
+//            for (GroupDelta group : mUnsyncedGroups) {
+//                final ContentProviderOperation oper = group.buildDiff();
+//                if (oper != null) diff.add(oper);
+//            }
+//        }
+//    }
+//
+//    /**
+//     * {@link ExpandableListAdapter} that shows {@link GroupDelta} settings,
+//     * grouped by {@link Account} source. Shows footer row when any groups are
+//     * unsynced, as determined through {@link AccountDisplay#mUnsyncedGroups}.
+//     */
+//    protected static class DisplayAdapter extends BaseExpandableListAdapter {
+//        private Context mContext;
+//        private LayoutInflater mInflater;
+//        private Sources mSources;
+//        private AccountSet mAccounts;
+//
+//        private boolean mChildWithPhones = false;
+//
+//        public DisplayAdapter(Context context) {
+//            mContext = context;
+//            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+//            mSources = Sources.getInstance(context);
+//        }
+//
+//        public void setAccounts(AccountSet accounts) {
+//            mAccounts = accounts;
+//            notifyDataSetChanged();
+//        }
+//
+//        /**
+//         * In group descriptions, show the number of contacts with phone
+//         * numbers, in addition to the total contacts.
+//         */
+//        public void setChildDescripWithPhones(boolean withPhones) {
+//            mChildWithPhones = withPhones;
+//        }
+//
+//        /** {@inheritDoc} */
+//        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+//                View convertView, ViewGroup parent) {
+//            if (convertView == null) {
+//                convertView = mInflater.inflate(R.layout.display_child, parent, false);
+//            }
+//
+//            final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
+//            final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
+//            final CheckBox checkbox = (CheckBox)convertView.findViewById(android.R.id.checkbox);
+//
+//            final AccountDisplay account = mAccounts.get(groupPosition);
+//            final GroupDelta child = (GroupDelta)this.getChild(groupPosition, childPosition);
+//            if (child != null) {
+//                // Handle normal group, with title and checkbox
+//                final boolean groupVisible = child.getVisible();
+//                checkbox.setVisibility(View.VISIBLE);
+//                checkbox.setChecked(groupVisible);
+//
+//                final CharSequence groupTitle = child.getTitle(mContext);
+//                text1.setText(groupTitle);
+//
+////              final int count = cursor.getInt(GroupsQuery.SUMMARY_COUNT);
+////              final int withPhones = cursor.getInt(GroupsQuery.SUMMARY_WITH_PHONES);
+//
+////              final CharSequence descrip = mContext.getResources().getQuantityString(
+////                      mChildWithPhones ? R.plurals.groupDescripPhones : R.plurals.groupDescrip,
+////                      count, count, withPhones);
+//
+////              text2.setText(descrip);
+//                text2.setVisibility(View.GONE);
+//            } else {
+//                // When unknown child, this is "more" footer view
+//                checkbox.setVisibility(View.GONE);
+//                text1.setText(R.string.display_more_groups);
+//                text2.setVisibility(View.GONE);
+//            }
+//
+//            return convertView;
+//        }
+//
+//        /** {@inheritDoc} */
+//        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+//                ViewGroup parent) {
+//            if (convertView == null) {
+//                convertView = mInflater.inflate(R.layout.display_group, parent, false);
+//            }
+//
+//            final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
+//            final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
+//
+//            final AccountDisplay account = (AccountDisplay)this.getGroup(groupPosition);
+//
+//            final ContactsSource source = mSources.getInflatedSource(account.mType,
+//                    ContactsSource.LEVEL_SUMMARY);
+//
+//            text1.setText(account.mName);
+//            text2.setText(source.getDisplayLabel(mContext));
+//            text2.setVisibility(account.mName == null ? View.GONE : View.VISIBLE);
+//
+//            return convertView;
+//        }
+//
+//        /** {@inheritDoc} */
+//        public Object getChild(int groupPosition, int childPosition) {
+//            final AccountDisplay account = mAccounts.get(groupPosition);
+//            final boolean validChild = childPosition >= 0
+//                    && childPosition < account.mSyncedGroups.size();
+//            if (validChild) {
+//                return account.mSyncedGroups.get(childPosition);
+//            } else {
+//                return null;
+//            }
+//        }
+//
+//        /** {@inheritDoc} */
+//        public long getChildId(int groupPosition, int childPosition) {
+//            final GroupDelta child = (GroupDelta)getChild(groupPosition, childPosition);
+//            if (child != null) {
+//                final Long childId = child.getId();
+//                return childId != null ? childId : Long.MIN_VALUE;
+//            } else {
+//                return Long.MIN_VALUE;
+//            }
+//        }
+//
+//        /** {@inheritDoc} */
+//        public int getChildrenCount(int groupPosition) {
+//            // Count is any synced groups, plus possible footer
+//            final AccountDisplay account = mAccounts.get(groupPosition);
+//            final boolean anyHidden = account.mUnsyncedGroups.size() > 0;
+//            return account.mSyncedGroups.size() + (anyHidden ? 1 : 0);
+//        }
+//
+//        /** {@inheritDoc} */
+//        public Object getGroup(int groupPosition) {
+//            return mAccounts.get(groupPosition);
+//        }
+//
+//        /** {@inheritDoc} */
+//        public int getGroupCount() {
+//            if (mAccounts == null) {
+//                return 0;
+//            }
+//            return mAccounts.size();
+//        }
+//
+//        /** {@inheritDoc} */
+//        public long getGroupId(int groupPosition) {
+//            return groupPosition;
+//        }
+//
+//        /** {@inheritDoc} */
+//        public boolean hasStableIds() {
+//            return true;
+//        }
+//
+//        /** {@inheritDoc} */
+//        public boolean isChildSelectable(int groupPosition, int childPosition) {
+//            return true;
+//        }
+//    }
+//
+//    /**
+//     * Handle any clicks on header views added to our {@link #mAdapter}, which
+//     * are usually the global modifier checkboxes.
+//     */
+//    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+//        Log.d(TAG, "OnItemClick, position=" + position + ", id=" + id);
+//        if (view == mHeaderPhones) {
+//            mDisplayPhones.toggle();
+//            return;
+//        }
+//        if (view == mDisplayOrderView) {
+//            Log.d(TAG, "Showing Display Order dialog");
+//            showDialog(DIALOG_DISPLAY_ORDER);
+//            return;
+//        }
+//        if (view == mSortOrderView) {
+//            Log.d(TAG, "Showing Sort Order dialog");
+//            showDialog(DIALOG_SORT_ORDER);
+//            return;
+//        }
+//    }
+//
+//    /** {@inheritDoc} */
+//    public void onClick(View view) {
+//        switch (view.getId()) {
+//            case R.id.btn_done: {
+//                this.doSaveAction();
+//                break;
+//            }
+//            case R.id.btn_discard: {
+//                this.finish();
+//                break;
+//            }
+//        }
+//    }
+//
+//    /**
+//     * Assign a specific value to {@link Prefs#DISPLAY_ONLY_PHONES}, refreshing
+//     * the visible list as needed.
+//     */
+//    protected void setDisplayOnlyPhones(boolean displayOnlyPhones) {
+//        mDisplayPhones.setChecked(displayOnlyPhones);
+//
+//        Editor editor = mPrefs.edit();
+//        editor.putBoolean(Prefs.DISPLAY_ONLY_PHONES, displayOnlyPhones);
+//        editor.apply();
+//
+//        mAdapter.setChildDescripWithPhones(displayOnlyPhones);
+//        mAdapter.notifyDataSetChanged();
+//    }
+//
+//    /**
+//     * Handle any clicks on {@link ExpandableListAdapter} children, which
+//     * usually mean toggling its visible state.
+//     */
+//    @Override
+//    public boolean onChildClick(ExpandableListView parent, View view, int groupPosition,
+//            int childPosition, long id) {
+//        final CheckBox checkbox = (CheckBox)view.findViewById(android.R.id.checkbox);
+//
+//        final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
+//        final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
+//        if (child != null) {
+//            checkbox.toggle();
+//            child.putVisible(checkbox.isChecked());
+//        } else {
+//            // Open context menu for bringing back unsynced
+//            this.openContextMenu(view);
+//        }
+//        return true;
+//    }
+//
+//    // TODO: move these definitions to framework constants when we begin
+//    // defining this mode through <sync-adapter> tags
+//    private static final int SYNC_MODE_UNSUPPORTED = 0;
+//    private static final int SYNC_MODE_UNGROUPED = 1;
+//    private static final int SYNC_MODE_EVERYTHING = 2;
+//
+//    protected int getSyncMode(AccountDisplay account) {
+//        // TODO: read sync mode through <sync-adapter> definition
+//        if (GoogleSource.ACCOUNT_TYPE.equals(account.mType)) {
+//            return SYNC_MODE_EVERYTHING;
+//        } else {
+//            return SYNC_MODE_UNSUPPORTED;
+//        }
+//    }
+//
+//    @Override
+//    public void onCreateContextMenu(ContextMenu menu, View view,
+//            ContextMenu.ContextMenuInfo menuInfo) {
+//        super.onCreateContextMenu(menu, view, menuInfo);
+//
+//        // Bail if not working with expandable long-press, or if not child
+//        if (!(menuInfo instanceof ExpandableListContextMenuInfo)) return;
+//
+//        final ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo;
+//        final int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
+//        final int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
+//
+//        // Skip long-press on expandable parents
+//        if (childPosition == -1) return;
+//
+//        final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
+//        final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
+//
+//        // Ignore when selective syncing unsupported
+//        final int syncMode = getSyncMode(account);
+//        if (syncMode == SYNC_MODE_UNSUPPORTED) return;
+//
+//        if (child != null) {
+//            showRemoveSync(menu, account, child, syncMode);
+//        } else {
+//            showAddSync(menu, account, syncMode);
+//        }
+//    }
+//
+//    protected void showRemoveSync(ContextMenu menu, final AccountDisplay account,
+//            final GroupDelta child, final int syncMode) {
+//        final CharSequence title = child.getTitle(this);
+//
+//        menu.setHeaderTitle(title);
+//        menu.add(R.string.menu_sync_remove).setOnMenuItemClickListener(
+//                new OnMenuItemClickListener() {
+//                    public boolean onMenuItemClick(MenuItem item) {
+//                        handleRemoveSync(account, child, syncMode, title);
+//                        return true;
+//                    }
+//                });
+//    }
+//
+//    protected void handleRemoveSync(final AccountDisplay account, final GroupDelta child,
+//            final int syncMode, CharSequence title) {
+//        final boolean shouldSyncUngrouped = account.mUngrouped.getShouldSync();
+//        if (syncMode == SYNC_MODE_EVERYTHING && shouldSyncUngrouped
+//                && !child.equals(account.mUngrouped)) {
+//            // Warn before removing this group when it would cause ungrouped to stop syncing
+//            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
+//            final CharSequence removeMessage = this.getString(
+//                    R.string.display_warn_remove_ungrouped, title);
+//            builder.setTitle(R.string.menu_sync_remove);
+//            builder.setMessage(removeMessage);
+//            builder.setNegativeButton(android.R.string.cancel, null);
+//            builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+//                public void onClick(DialogInterface dialog, int which) {
+//                    // Mark both this group and ungrouped to stop syncing
+//                    account.setShouldSync(account.mUngrouped, false);
+//                    account.setShouldSync(child, false);
+//                    mAdapter.notifyDataSetChanged();
+//                }
+//            });
+//            builder.show();
+//        } else {
+//            // Mark this group to not sync
+//            account.setShouldSync(child, false);
+//            mAdapter.notifyDataSetChanged();
+//        }
+//    }
+//
+//    protected void showAddSync(ContextMenu menu, final AccountDisplay account, final int syncMode) {
+//        menu.setHeaderTitle(R.string.dialog_sync_add);
+//
+//        // Create item for each available, unsynced group
+//        for (final GroupDelta child : account.mUnsyncedGroups) {
+//            if (!child.getShouldSync()) {
+//                final CharSequence title = child.getTitle(this);
+//                menu.add(title).setOnMenuItemClickListener(new OnMenuItemClickListener() {
+//                    public boolean onMenuItemClick(MenuItem item) {
+//                        // Adding specific group for syncing
+//                        if (child.mUngrouped && syncMode == SYNC_MODE_EVERYTHING) {
+//                            account.setShouldSync(true);
+//                        } else {
+//                            account.setShouldSync(child, true);
+//                        }
+//                        mAdapter.notifyDataSetChanged();
+//                        return true;
+//                    }
+//                });
+//            }
+//        }
+//    }
+//
+//    /** {@inheritDoc} */
+//    @Override
+//    public void onBackPressed() {
+//        doSaveAction();
+//    }
+//
+//    private void doSaveAction() {
+//        mContactsPrefs.setSortOrder(mSortOrder);
+//        mContactsPrefs.setDisplayOrder(mDisplayOrder);
+//
+//        if (mAdapter == null || mAdapter.mAccounts == null) {
+//            return;
+//        }
+//        setDisplayOnlyPhones(mDisplayPhones.isChecked());
+//        new UpdateTask(this).execute(mAdapter.mAccounts);
+//    }
+//
+//    /**
+//     * Background task that persists changes to {@link Groups#GROUP_VISIBLE},
+//     * showing spinner dialog to user while updating.
+//     */
+//    public static class UpdateTask extends
+//            WeakAsyncTask<AccountSet, Void, Void, Activity> {
+//        private WeakReference<ProgressDialog> mProgress;
+//
+//        public UpdateTask(Activity target) {
+//            super(target);
+//        }
+//
+//        /** {@inheritDoc} */
+//        @Override
+//        protected void onPreExecute(Activity target) {
+//            final Context context = target;
+//
+//            mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(context, null,
+//                    context.getText(R.string.savingDisplayGroups)));
+//
+//            // Before starting this task, start an empty service to protect our
+//            // process from being reclaimed by the system.
+//            context.startService(new Intent(context, EmptyService.class));
+//        }
+//
+//        /** {@inheritDoc} */
+//        @Override
+//        protected Void doInBackground(Activity target, AccountSet... params) {
+//            final Context context = target;
+//            final ContentValues values = new ContentValues();
+//            final ContentResolver resolver = context.getContentResolver();
+//
+//            try {
+//                // Build changes and persist in transaction
+//                final AccountSet set = params[0];
+//                final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+//                resolver.applyBatch(ContactsContract.AUTHORITY, diff);
+//            } catch (RemoteException e) {
+//                Log.e(TAG, "Problem saving display groups", e);
+//            } catch (OperationApplicationException e) {
+//                Log.e(TAG, "Problem saving display groups", e);
+//            }
+//
+//            return null;
+//        }
+//
+//        /** {@inheritDoc} */
+//        @Override
+//        protected void onPostExecute(Activity target, Void result) {
+//            final Context context = target;
+//
+//            final ProgressDialog dialog = mProgress.get();
+//            if (dialog != null) {
+//                try {
+//                    dialog.dismiss();
+//                } catch (Exception e) {
+//                    Log.e(TAG, "Error dismissing progress dialog", e);
+//                }
+//            }
+//
+//            target.finish();
+//
+//            // Stop the service that was protecting us
+//            context.stopService(new Intent(context, EmptyService.class));
+//        }
+//    }
+//
+//    @Override
+//    public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+//            boolean globalSearch) {
+//        if (globalSearch) {
+//            super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+//        } else {
+//            ContactsSearchManager.startSearch(this, initialQuery);
+//        }
+//    }
+}
diff --git a/src/com/android/contacts/ui/ContactsPreferences.java b/src/com/android/contacts/preference/ContactsPreferences.java
similarity index 94%
rename from src/com/android/contacts/ui/ContactsPreferences.java
rename to src/com/android/contacts/preference/ContactsPreferences.java
index 89f71fc..bfe7743 100644
--- a/src/com/android/contacts/ui/ContactsPreferences.java
+++ b/src/com/android/contacts/preference/ContactsPreferences.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.contacts.ui;
+package com.android.contacts.preference;
 
 import com.android.contacts.R;
 
@@ -30,6 +30,10 @@
  * Manages user preferences for contacts.
  */
 public final class ContactsPreferences extends ContentObserver {
+
+    public static final String PREF_DISPLAY_ONLY_PHONES = "only_phones";
+    public static final boolean PREF_DISPLAY_ONLY_PHONES_DEFAULT = false;
+
     private Context mContext;
     private int mSortOrder = -1;
     private int mDisplayOrder = -1;
@@ -46,7 +50,7 @@
         return mContext.getResources().getBoolean(R.bool.config_sort_order_user_changeable);
     }
 
-    private int getDefaultSortOrder() {
+    public int getDefaultSortOrder() {
         if (mContext.getResources().getBoolean(R.bool.config_default_sort_order_primary)) {
             return ContactsContract.Preferences.SORT_ORDER_PRIMARY;
         } else {
@@ -80,7 +84,7 @@
         return mContext.getResources().getBoolean(R.bool.config_display_order_user_changeable);
     }
 
-    private int getDefaultDisplayOrder() {
+    public int getDefaultDisplayOrder() {
         if (mContext.getResources().getBoolean(R.bool.config_default_display_order_primary)) {
             return ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY;
         } else {
diff --git a/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java b/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java
new file mode 100644
index 0000000..db4a94e
--- /dev/null
+++ b/src/com/android/contacts/preference/DisplayOptionsPreferenceFragment.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.preference;
+
+import com.android.contacts.R;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+/**
+ * This fragment shows the preferences for the first header.
+ */
+public class DisplayOptionsPreferenceFragment extends PreferenceFragment {
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // Load the preferences from an XML resource
+        addPreferencesFromResource(R.xml.preference_display_options);
+    }
+}
+
diff --git a/src/com/android/contacts/preference/DisplayOrderPreference.java b/src/com/android/contacts/preference/DisplayOrderPreference.java
new file mode 100644
index 0000000..b804660
--- /dev/null
+++ b/src/com/android/contacts/preference/DisplayOrderPreference.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.preference;
+
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.preference.ListPreference;
+import android.provider.ContactsContract;
+import android.util.AttributeSet;
+
+/**
+ * Custom preference: view-name-as (first name first or last name first).
+ */
+public final class DisplayOrderPreference extends ListPreference {
+
+    private ContactsPreferences mPreferences;
+    private Context mContext;
+
+    public DisplayOrderPreference(Context context) {
+        super(context);
+        prepare();
+    }
+
+    public DisplayOrderPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        prepare();
+    }
+
+    private void prepare() {
+        mContext = getContext();
+        mPreferences = new ContactsPreferences(mContext);
+        setEntries(new String[]{
+                mContext.getString(R.string.display_options_view_given_name_first),
+                mContext.getString(R.string.display_options_view_family_name_first),
+        });
+        setEntryValues(new String[]{
+                String.valueOf(ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY),
+                String.valueOf(ContactsContract.Preferences.DISPLAY_ORDER_ALTERNATIVE),
+        });
+        setValue(String.valueOf(mPreferences.getDisplayOrder()));
+    }
+
+    @Override
+    protected boolean shouldPersist() {
+        return false;   // This preference takes care of its own storage
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        switch (mPreferences.getSortOrder()) {
+            case ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY:
+                return mContext.getString(R.string.display_options_view_given_name_first);
+            case ContactsContract.Preferences.DISPLAY_ORDER_ALTERNATIVE:
+                return mContext.getString(R.string.display_options_view_family_name_first);
+        }
+        return null;
+    }
+
+    @Override
+    protected boolean persistString(String value) {
+        int newValue = Integer.parseInt(value);
+        if (newValue != mPreferences.getSortOrder()) {
+            mPreferences.setDisplayOrder(newValue);
+            notifyChanged();
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/contacts/preference/SortOrderPreference.java b/src/com/android/contacts/preference/SortOrderPreference.java
new file mode 100644
index 0000000..81b034c
--- /dev/null
+++ b/src/com/android/contacts/preference/SortOrderPreference.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.preference;
+
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.preference.ListPreference;
+import android.provider.ContactsContract;
+import android.util.AttributeSet;
+
+/**
+ * Custom preference: sort-by.
+ */
+public final class SortOrderPreference extends ListPreference {
+
+    private ContactsPreferences mPreferences;
+    private Context mContext;
+
+    public SortOrderPreference(Context context) {
+        super(context);
+        prepare();
+    }
+
+    public SortOrderPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        prepare();
+    }
+
+    private void prepare() {
+        mContext = getContext();
+        mPreferences = new ContactsPreferences(mContext);
+        setEntries(new String[]{
+                mContext.getString(R.string.display_options_sort_by_given_name),
+                mContext.getString(R.string.display_options_sort_by_family_name),
+        });
+        setEntryValues(new String[]{
+                String.valueOf(ContactsContract.Preferences.SORT_ORDER_PRIMARY),
+                String.valueOf(ContactsContract.Preferences.SORT_ORDER_ALTERNATIVE),
+        });
+        setValue(String.valueOf(mPreferences.getSortOrder()));
+    }
+
+    @Override
+    protected boolean shouldPersist() {
+        return false;   // This preference takes care of its own storage
+    }
+
+    @Override
+    public CharSequence getSummary() {
+        switch (mPreferences.getSortOrder()) {
+            case ContactsContract.Preferences.SORT_ORDER_PRIMARY:
+                return mContext.getString(R.string.display_options_sort_by_given_name);
+            case ContactsContract.Preferences.SORT_ORDER_ALTERNATIVE:
+                return mContext.getString(R.string.display_options_sort_by_family_name);
+        }
+        return null;
+    }
+
+    @Override
+    protected boolean persistString(String value) {
+        int newValue = Integer.parseInt(value);
+        if (newValue != mPreferences.getSortOrder()) {
+            mPreferences.setSortOrder(newValue);
+            notifyChanged();
+        }
+        return true;
+    }
+}
diff --git a/src/com/android/contacts/ui/ContactsPreferencesActivity.java b/src/com/android/contacts/ui/ContactsPreferencesActivity.java
deleted file mode 100644
index e32eb2a..0000000
--- a/src/com/android/contacts/ui/ContactsPreferencesActivity.java
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.ui;
-
-import com.android.contacts.ContactsSearchManager;
-import com.android.contacts.R;
-import com.android.contacts.model.ContactsSource;
-import com.android.contacts.model.GoogleSource;
-import com.android.contacts.model.Sources;
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.util.EmptyService;
-import com.android.contacts.util.LocalizedNameResolver;
-import com.android.contacts.util.WeakAsyncTask;
-import com.google.android.collect.Lists;
-
-import android.accounts.Account;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.ExpandableListActivity;
-import android.app.ProgressDialog;
-import android.content.ContentProviderOperation;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.EntityIterator;
-import android.content.Intent;
-import android.content.OperationApplicationException;
-import android.content.SharedPreferences;
-import android.content.ContentProviderOperation.Builder;
-import android.content.SharedPreferences.Editor;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.preference.PreferenceManager;
-import android.provider.ContactsContract;
-import android.provider.ContactsContract.Groups;
-import android.provider.ContactsContract.Settings;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.MenuItem.OnMenuItemClickListener;
-import android.widget.AdapterView;
-import android.widget.BaseExpandableListAdapter;
-import android.widget.CheckBox;
-import android.widget.ExpandableListAdapter;
-import android.widget.ExpandableListView;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-
-/**
- * Shows a list of all available {@link Groups} available, letting the user
- * select which ones they want to be visible.
- */
-public final class ContactsPreferencesActivity extends ExpandableListActivity implements
-        AdapterView.OnItemClickListener, View.OnClickListener {
-    private static final String TAG = "DisplayGroupsActivity";
-
-    public interface Prefs {
-        public static final String DISPLAY_ONLY_PHONES = "only_phones";
-        public static final boolean DISPLAY_ONLY_PHONES_DEFAULT = false;
-
-    }
-
-    private static final int DIALOG_SORT_ORDER = 1;
-    private static final int DIALOG_DISPLAY_ORDER = 2;
-
-    private ExpandableListView mList;
-    private DisplayAdapter mAdapter;
-
-    private SharedPreferences mPrefs;
-    private ContactsPreferences mContactsPrefs;
-
-    private CheckBox mDisplayPhones;
-
-    private View mHeaderPhones;
-    private View mHeaderSeparator;
-
-    private View mSortOrderView;
-    private TextView mSortOrderTextView;
-    private int mSortOrder;
-
-    private View mDisplayOrderView;
-    private TextView mDisplayOrderTextView;
-    private int mDisplayOrder;
-
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        setContentView(R.layout.contacts_preferences);
-
-        mList = getExpandableListView();
-        mList.setHeaderDividersEnabled(true);
-        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
-        mContactsPrefs = new ContactsPreferences(this);
-        mAdapter = new DisplayAdapter(this);
-
-        final LayoutInflater inflater = getLayoutInflater();
-
-        createWithPhonesOnlyPreferenceView(inflater);
-        createSortOrderPreferenceView(inflater);
-        createDisplayOrderPreferenceView(inflater);
-        createDisplayGroupHeader(inflater);
-
-        findViewById(R.id.btn_done).setOnClickListener(this);
-        findViewById(R.id.btn_discard).setOnClickListener(this);
-
-        // Catch clicks on the header views
-        mList.setOnItemClickListener(this);
-        mList.setOnCreateContextMenuListener(this);
-
-        mSortOrder = mContactsPrefs.getSortOrder();
-        mDisplayOrder = mContactsPrefs.getDisplayOrder();
-    }
-
-    private void createWithPhonesOnlyPreferenceView(LayoutInflater inflater) {
-        // Add the "Only contacts with phones" header modifier.
-        mHeaderPhones = inflater.inflate(R.layout.display_options_phones_only, mList, false);
-        mHeaderPhones.setId(R.id.header_phones);
-        mDisplayPhones = (CheckBox) mHeaderPhones.findViewById(android.R.id.checkbox);
-        mDisplayPhones.setChecked(mPrefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
-                Prefs.DISPLAY_ONLY_PHONES_DEFAULT));
-        {
-            final TextView text1 = (TextView)mHeaderPhones.findViewById(android.R.id.text1);
-            final TextView text2 = (TextView)mHeaderPhones.findViewById(android.R.id.text2);
-            text1.setText(R.string.showFilterPhones);
-            text2.setText(R.string.showFilterPhonesDescrip);
-        }
-    }
-
-    private void createSortOrderPreferenceView(LayoutInflater inflater) {
-        mSortOrderView = inflater.inflate(R.layout.preference_with_more_button, mList, false);
-
-        View preferenceLayout = mSortOrderView.findViewById(R.id.preference);
-
-        TextView label = (TextView)preferenceLayout.findViewById(R.id.label);
-        label.setText(getString(R.string.display_options_sort_list_by));
-
-        mSortOrderTextView = (TextView)preferenceLayout.findViewById(R.id.data);
-    }
-
-    private void createDisplayOrderPreferenceView(LayoutInflater inflater) {
-        mDisplayOrderView = inflater.inflate(R.layout.preference_with_more_button, mList, false);
-        View preferenceLayout = mDisplayOrderView.findViewById(R.id.preference);
-
-        TextView label = (TextView)preferenceLayout.findViewById(R.id.label);
-        label.setText(getString(R.string.display_options_view_names_as));
-
-        mDisplayOrderTextView = (TextView)preferenceLayout.findViewById(R.id.data);
-    }
-
-    private void createDisplayGroupHeader(LayoutInflater inflater) {
-        // Add the separator before showing the detailed group list.
-        mHeaderSeparator = inflater.inflate(R.layout.list_separator, mList, false);
-        {
-            final TextView text1 = (TextView)mHeaderSeparator;
-            text1.setText(R.string.headerContactGroups);
-        }
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mList.removeHeaderView(mHeaderPhones);
-        mList.removeHeaderView(mSortOrderView);
-        mList.removeHeaderView(mDisplayOrderView);
-        mList.removeHeaderView(mHeaderSeparator);
-
-        // List adapter needs to be reset, because header views cannot be added
-        // to a list with an existing adapter.
-        setListAdapter(null);
-
-        mList.addHeaderView(mHeaderPhones, null, true);
-        if (mContactsPrefs.isSortOrderUserChangeable()) {
-            mList.addHeaderView(mSortOrderView, null, true);
-        }
-
-        if (mContactsPrefs.isSortOrderUserChangeable()) {
-            mList.addHeaderView(mDisplayOrderView, null, true);
-        }
-
-        mList.addHeaderView(mHeaderSeparator, null, false);
-
-        setListAdapter(mAdapter);
-
-        bindView();
-
-        // Start background query to find account details
-        new QueryGroupsTask(this).execute();
-    }
-
-    private void bindView() {
-        mSortOrderTextView.setText(
-                mSortOrder == ContactsContract.Preferences.SORT_ORDER_PRIMARY
-                        ? getString(R.string.display_options_sort_by_given_name)
-                        : getString(R.string.display_options_sort_by_family_name));
-
-        mDisplayOrderTextView.setText(
-                mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY
-                        ? getString(R.string.display_options_view_given_name_first)
-                        : getString(R.string.display_options_view_family_name_first));
-    }
-
-    @Override
-    protected Dialog onCreateDialog(int id, Bundle args) {
-        switch (id) {
-            case DIALOG_SORT_ORDER:
-                return createSortOrderDialog();
-            case DIALOG_DISPLAY_ORDER:
-                return createDisplayOrderDialog();
-        }
-
-        return null;
-    }
-
-    private Dialog createSortOrderDialog() {
-        String[] items = new String[] {
-                getString(R.string.display_options_sort_by_given_name),
-                getString(R.string.display_options_sort_by_family_name),
-        };
-
-        return new AlertDialog.Builder(this)
-            .setIcon(com.android.internal.R.drawable.ic_dialog_menu_generic)
-            .setTitle(R.string.display_options_sort_list_by)
-            .setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
-                    public void onClick(DialogInterface dialog, int whichButton) {
-                        setSortOrder(dialog);
-                        dialog.dismiss();
-                    }
-                })
-            .setNegativeButton(android.R.string.cancel, null)
-            .create();
-    }
-
-    private Dialog createDisplayOrderDialog() {
-        String[] items = new String[] {
-                getString(R.string.display_options_view_given_name_first),
-                getString(R.string.display_options_view_family_name_first),
-        };
-
-        return new AlertDialog.Builder(this)
-            .setIcon(com.android.internal.R.drawable.ic_dialog_menu_generic)
-            .setTitle(R.string.display_options_view_names_as)
-            .setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
-                    public void onClick(DialogInterface dialog, int whichButton) {
-                        setDisplayOrder(dialog);
-                        dialog.dismiss();
-                    }
-                })
-            .setNegativeButton(android.R.string.cancel, null)
-            .create();
-    }
-
-    @Override
-    protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
-        switch (id) {
-            case DIALOG_SORT_ORDER:
-                setCheckedItem(dialog,
-                        mSortOrder == ContactsContract.Preferences.SORT_ORDER_PRIMARY ? 0 : 1);
-                break;
-            case DIALOG_DISPLAY_ORDER:
-                setCheckedItem(dialog,
-                        mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY
-                                ? 0 : 1);
-                break;
-        }
-    }
-
-    private void setCheckedItem(Dialog dialog, int position) {
-        ListView listView = ((AlertDialog)dialog).getListView();
-        listView.setItemChecked(position, true);
-        listView.setSelection(position);
-    }
-
-    protected void setSortOrder(DialogInterface dialog) {
-        ListView listView = ((AlertDialog)dialog).getListView();
-        int checked = listView.getCheckedItemPosition();
-        mSortOrder = checked == 0
-                ? ContactsContract.Preferences.SORT_ORDER_PRIMARY
-                : ContactsContract.Preferences.SORT_ORDER_ALTERNATIVE;
-
-        bindView();
-    }
-
-    protected void setDisplayOrder(DialogInterface dialog) {
-        ListView listView = ((AlertDialog)dialog).getListView();
-        int checked = listView.getCheckedItemPosition();
-        mDisplayOrder = checked == 0
-                ? ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY
-                : ContactsContract.Preferences.DISPLAY_ORDER_ALTERNATIVE;
-
-        bindView();
-    }
-
-    /**
-     * Background operation to build set of {@link AccountDisplay} for each
-     * {@link Sources#getAccounts(boolean)} that provides groups.
-     */
-    private static class QueryGroupsTask extends
-            WeakAsyncTask<Void, Void, AccountSet, ContactsPreferencesActivity> {
-        public QueryGroupsTask(ContactsPreferencesActivity target) {
-            super(target);
-        }
-
-        @Override
-        protected AccountSet doInBackground(ContactsPreferencesActivity target,
-                Void... params) {
-            final Context context = target;
-            final Sources sources = Sources.getInstance(context);
-            final ContentResolver resolver = context.getContentResolver();
-
-            // Inflate groups entry for each account
-            final AccountSet accounts = new AccountSet();
-            for (Account account : sources.getAccounts(false)) {
-                accounts.add(new AccountDisplay(resolver, account.name, account.type));
-            }
-
-            return accounts;
-        }
-
-        @Override
-        protected void onPostExecute(ContactsPreferencesActivity target, AccountSet result) {
-            target.mAdapter.setAccounts(result);
-        }
-    }
-
-    private static final int DEFAULT_SHOULD_SYNC = 1;
-    private static final int DEFAULT_VISIBLE = 0;
-
-    /**
-     * Entry holding any changes to {@link Groups} or {@link Settings} rows,
-     * such as {@link Groups#SHOULD_SYNC} or {@link Groups#GROUP_VISIBLE}.
-     */
-    protected static class GroupDelta extends ValuesDelta {
-        private boolean mUngrouped = false;
-        private boolean mAccountHasGroups;
-
-        private GroupDelta() {
-            super();
-        }
-
-        /**
-         * Build {@link GroupDelta} from the {@link Settings} row for the given
-         * {@link Settings#ACCOUNT_NAME} and {@link Settings#ACCOUNT_TYPE}.
-         */
-        public static GroupDelta fromSettings(ContentResolver resolver, String accountName,
-                String accountType, boolean accountHasGroups) {
-            final Uri settingsUri = Settings.CONTENT_URI.buildUpon()
-                    .appendQueryParameter(Settings.ACCOUNT_NAME, accountName)
-                    .appendQueryParameter(Settings.ACCOUNT_TYPE, accountType).build();
-            final Cursor cursor = resolver.query(settingsUri, new String[] {
-                    Settings.SHOULD_SYNC, Settings.UNGROUPED_VISIBLE
-            }, null, null, null);
-
-            try {
-                final ContentValues values = new ContentValues();
-                values.put(Settings.ACCOUNT_NAME, accountName);
-                values.put(Settings.ACCOUNT_TYPE, accountType);
-
-                if (cursor != null && cursor.moveToFirst()) {
-                    // Read existing values when present
-                    values.put(Settings.SHOULD_SYNC, cursor.getInt(0));
-                    values.put(Settings.UNGROUPED_VISIBLE, cursor.getInt(1));
-                    return fromBefore(values).setUngrouped(accountHasGroups);
-                } else {
-                    // Nothing found, so treat as create
-                    values.put(Settings.SHOULD_SYNC, DEFAULT_SHOULD_SYNC);
-                    values.put(Settings.UNGROUPED_VISIBLE, DEFAULT_VISIBLE);
-                    return fromAfter(values).setUngrouped(accountHasGroups);
-                }
-            } finally {
-                if (cursor != null) cursor.close();
-            }
-        }
-
-        public static GroupDelta fromBefore(ContentValues before) {
-            final GroupDelta entry = new GroupDelta();
-            entry.mBefore = before;
-            entry.mAfter = new ContentValues();
-            return entry;
-        }
-
-        public static GroupDelta fromAfter(ContentValues after) {
-            final GroupDelta entry = new GroupDelta();
-            entry.mBefore = null;
-            entry.mAfter = after;
-            return entry;
-        }
-
-        protected GroupDelta setUngrouped(boolean accountHasGroups) {
-            mUngrouped = true;
-            mAccountHasGroups = accountHasGroups;
-            return this;
-        }
-
-        @Override
-        public boolean beforeExists() {
-            return mBefore != null;
-        }
-
-        public boolean getShouldSync() {
-            return getAsInteger(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC,
-                    DEFAULT_SHOULD_SYNC) != 0;
-        }
-
-        public boolean getVisible() {
-            return getAsInteger(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE,
-                    DEFAULT_VISIBLE) != 0;
-        }
-
-        public void putShouldSync(boolean shouldSync) {
-            put(mUngrouped ? Settings.SHOULD_SYNC : Groups.SHOULD_SYNC, shouldSync ? 1 : 0);
-        }
-
-        public void putVisible(boolean visible) {
-            put(mUngrouped ? Settings.UNGROUPED_VISIBLE : Groups.GROUP_VISIBLE, visible ? 1 : 0);
-        }
-
-        private String getAccountType() {
-            return (mBefore == null ? mAfter : mBefore).getAsString(Settings.ACCOUNT_TYPE);
-        }
-
-        public CharSequence getTitle(Context context) {
-            if (mUngrouped) {
-                final String customAllContactsName =
-                        LocalizedNameResolver.getAllContactsName(context, getAccountType());
-                if (customAllContactsName != null) {
-                    return customAllContactsName;
-                }
-                if (mAccountHasGroups) {
-                    return context.getText(R.string.display_ungrouped);
-                } else {
-                    return context.getText(R.string.display_all_contacts);
-                }
-            } else {
-                final Integer titleRes = getAsInteger(Groups.TITLE_RES);
-                if (titleRes != null) {
-                    final String packageName = getAsString(Groups.RES_PACKAGE);
-                    return context.getPackageManager().getText(packageName, titleRes, null);
-                } else {
-                    return getAsString(Groups.TITLE);
-                }
-            }
-        }
-
-        /**
-         * Build a possible {@link ContentProviderOperation} to persist any
-         * changes to the {@link Groups} or {@link Settings} row described by
-         * this {@link GroupDelta}.
-         */
-        public ContentProviderOperation buildDiff() {
-            if (isNoop()) {
-                return null;
-            } else if (isUpdate()) {
-                // When has changes and "before" exists, then "update"
-                final Builder builder = ContentProviderOperation
-                        .newUpdate(mUngrouped ? Settings.CONTENT_URI : addCallerIsSyncAdapterParameter(Groups.CONTENT_URI));
-                if (mUngrouped) {
-                    builder.withSelection(Settings.ACCOUNT_NAME + "=? AND " + Settings.ACCOUNT_TYPE
-                            + "=?", new String[] {
-                            this.getAsString(Settings.ACCOUNT_NAME),
-                            this.getAsString(Settings.ACCOUNT_TYPE)
-                    });
-                } else {
-                    builder.withSelection(Groups._ID + "=" + this.getId(), null);
-                }
-                builder.withValues(mAfter);
-                return builder.build();
-            } else if (isInsert() && mUngrouped) {
-                // Only allow inserts for Settings
-                mAfter.remove(mIdColumn);
-                final Builder builder = ContentProviderOperation.newInsert(Settings.CONTENT_URI);
-                builder.withValues(mAfter);
-                return builder.build();
-            } else {
-                throw new IllegalStateException("Unexpected delete or insert");
-            }
-        }
-    }
-
-    private static Uri addCallerIsSyncAdapterParameter(Uri uri) {
-        return uri.buildUpon()
-	        .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true")
-	        .build();
-    }
-
-    /**
-     * {@link Comparator} to sort by {@link Groups#_ID}.
-     */
-    private static Comparator<GroupDelta> sIdComparator = new Comparator<GroupDelta>() {
-        public int compare(GroupDelta object1, GroupDelta object2) {
-            final Long id1 = object1.getId();
-            final Long id2 = object2.getId();
-            if (id1 == null && id2 == null) {
-                return 0;
-            } else if (id1 == null) {
-                return -1;
-            } else if (id2 == null) {
-                return 1;
-            } else if (id1 < id2) {
-                return -1;
-            } else if (id1 > id2) {
-                return 1;
-            } else {
-                return 0;
-            }
-        }
-    };
-
-    /**
-     * Set of all {@link AccountDisplay} entries, one for each source.
-     */
-    protected static class AccountSet extends ArrayList<AccountDisplay> {
-        public ArrayList<ContentProviderOperation> buildDiff() {
-            final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
-            for (AccountDisplay account : this) {
-                account.buildDiff(diff);
-            }
-            return diff;
-        }
-    }
-
-    /**
-     * {@link GroupDelta} details for a single {@link Account}, usually shown as
-     * children under a single expandable group.
-     */
-    protected static class AccountDisplay {
-        public String mName;
-        public String mType;
-
-        public GroupDelta mUngrouped;
-        public ArrayList<GroupDelta> mSyncedGroups = Lists.newArrayList();
-        public ArrayList<GroupDelta> mUnsyncedGroups = Lists.newArrayList();
-
-        /**
-         * Build an {@link AccountDisplay} covering all {@link Groups} under the
-         * given {@link Account}.
-         */
-        public AccountDisplay(ContentResolver resolver, String accountName, String accountType) {
-            mName = accountName;
-            mType = accountType;
-
-            final Uri groupsUri = Groups.CONTENT_URI.buildUpon()
-                    .appendQueryParameter(Groups.ACCOUNT_NAME, accountName)
-                    .appendQueryParameter(Groups.ACCOUNT_TYPE, accountType).build();
-            EntityIterator iterator = ContactsContract.Groups.newEntityIterator(resolver.query(
-                    groupsUri, null, null, null, null));
-            try {
-                boolean hasGroups = false;
-
-                // Create entries for each known group
-                while (iterator.hasNext()) {
-                    final ContentValues values = iterator.next().getEntityValues();
-                    final GroupDelta group = GroupDelta.fromBefore(values);
-                    addGroup(group);
-                    hasGroups = true;
-                }
-                // Create single entry handling ungrouped status
-                mUngrouped = GroupDelta.fromSettings(resolver, accountName, accountType, hasGroups);
-                addGroup(mUngrouped);
-            } finally {
-                iterator.close();
-            }
-        }
-
-        /**
-         * Add the given {@link GroupDelta} internally, filing based on its
-         * {@link GroupDelta#getShouldSync()} status.
-         */
-        private void addGroup(GroupDelta group) {
-            if (group.getShouldSync()) {
-                mSyncedGroups.add(group);
-            } else {
-                mUnsyncedGroups.add(group);
-            }
-        }
-
-        /**
-         * Set the {@link GroupDelta#putShouldSync(boolean)} value for all
-         * children {@link GroupDelta} rows.
-         */
-        public void setShouldSync(boolean shouldSync) {
-            final Iterator<GroupDelta> oppositeChildren = shouldSync ?
-                    mUnsyncedGroups.iterator() : mSyncedGroups.iterator();
-            while (oppositeChildren.hasNext()) {
-                final GroupDelta child = oppositeChildren.next();
-                setShouldSync(child, shouldSync, false);
-                oppositeChildren.remove();
-            }
-        }
-
-        public void setShouldSync(GroupDelta child, boolean shouldSync) {
-            setShouldSync(child, shouldSync, true);
-        }
-
-        /**
-         * Set {@link GroupDelta#putShouldSync(boolean)}, and file internally
-         * based on updated state.
-         */
-        public void setShouldSync(GroupDelta child, boolean shouldSync, boolean attemptRemove) {
-            child.putShouldSync(shouldSync);
-            if (shouldSync) {
-                if (attemptRemove) {
-                    mUnsyncedGroups.remove(child);
-                }
-                mSyncedGroups.add(child);
-                Collections.sort(mSyncedGroups, sIdComparator);
-            } else {
-                if (attemptRemove) {
-                    mSyncedGroups.remove(child);
-                }
-                mUnsyncedGroups.add(child);
-            }
-        }
-
-        /**
-         * Build set of {@link ContentProviderOperation} to persist any user
-         * changes to {@link GroupDelta} rows under this {@link Account}.
-         */
-        public void buildDiff(ArrayList<ContentProviderOperation> diff) {
-            for (GroupDelta group : mSyncedGroups) {
-                final ContentProviderOperation oper = group.buildDiff();
-                if (oper != null) diff.add(oper);
-            }
-            for (GroupDelta group : mUnsyncedGroups) {
-                final ContentProviderOperation oper = group.buildDiff();
-                if (oper != null) diff.add(oper);
-            }
-        }
-    }
-
-    /**
-     * {@link ExpandableListAdapter} that shows {@link GroupDelta} settings,
-     * grouped by {@link Account} source. Shows footer row when any groups are
-     * unsynced, as determined through {@link AccountDisplay#mUnsyncedGroups}.
-     */
-    protected static class DisplayAdapter extends BaseExpandableListAdapter {
-        private Context mContext;
-        private LayoutInflater mInflater;
-        private Sources mSources;
-        private AccountSet mAccounts;
-
-        private boolean mChildWithPhones = false;
-
-        public DisplayAdapter(Context context) {
-            mContext = context;
-            mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            mSources = Sources.getInstance(context);
-        }
-
-        public void setAccounts(AccountSet accounts) {
-            mAccounts = accounts;
-            notifyDataSetChanged();
-        }
-
-        /**
-         * In group descriptions, show the number of contacts with phone
-         * numbers, in addition to the total contacts.
-         */
-        public void setChildDescripWithPhones(boolean withPhones) {
-            mChildWithPhones = withPhones;
-        }
-
-        /** {@inheritDoc} */
-        public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
-                View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                convertView = mInflater.inflate(R.layout.display_child, parent, false);
-            }
-
-            final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
-            final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
-            final CheckBox checkbox = (CheckBox)convertView.findViewById(android.R.id.checkbox);
-
-            final AccountDisplay account = mAccounts.get(groupPosition);
-            final GroupDelta child = (GroupDelta)this.getChild(groupPosition, childPosition);
-            if (child != null) {
-                // Handle normal group, with title and checkbox
-                final boolean groupVisible = child.getVisible();
-                checkbox.setVisibility(View.VISIBLE);
-                checkbox.setChecked(groupVisible);
-
-                final CharSequence groupTitle = child.getTitle(mContext);
-                text1.setText(groupTitle);
-
-//              final int count = cursor.getInt(GroupsQuery.SUMMARY_COUNT);
-//              final int withPhones = cursor.getInt(GroupsQuery.SUMMARY_WITH_PHONES);
-
-//              final CharSequence descrip = mContext.getResources().getQuantityString(
-//                      mChildWithPhones ? R.plurals.groupDescripPhones : R.plurals.groupDescrip,
-//                      count, count, withPhones);
-
-//              text2.setText(descrip);
-                text2.setVisibility(View.GONE);
-            } else {
-                // When unknown child, this is "more" footer view
-                checkbox.setVisibility(View.GONE);
-                text1.setText(R.string.display_more_groups);
-                text2.setVisibility(View.GONE);
-            }
-
-            return convertView;
-        }
-
-        /** {@inheritDoc} */
-        public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
-                ViewGroup parent) {
-            if (convertView == null) {
-                convertView = mInflater.inflate(R.layout.display_group, parent, false);
-            }
-
-            final TextView text1 = (TextView)convertView.findViewById(android.R.id.text1);
-            final TextView text2 = (TextView)convertView.findViewById(android.R.id.text2);
-
-            final AccountDisplay account = (AccountDisplay)this.getGroup(groupPosition);
-
-            final ContactsSource source = mSources.getInflatedSource(account.mType,
-                    ContactsSource.LEVEL_SUMMARY);
-
-            text1.setText(account.mName);
-            text2.setText(source.getDisplayLabel(mContext));
-            text2.setVisibility(account.mName == null ? View.GONE : View.VISIBLE);
-
-            return convertView;
-        }
-
-        /** {@inheritDoc} */
-        public Object getChild(int groupPosition, int childPosition) {
-            final AccountDisplay account = mAccounts.get(groupPosition);
-            final boolean validChild = childPosition >= 0
-                    && childPosition < account.mSyncedGroups.size();
-            if (validChild) {
-                return account.mSyncedGroups.get(childPosition);
-            } else {
-                return null;
-            }
-        }
-
-        /** {@inheritDoc} */
-        public long getChildId(int groupPosition, int childPosition) {
-            final GroupDelta child = (GroupDelta)getChild(groupPosition, childPosition);
-            if (child != null) {
-                final Long childId = child.getId();
-                return childId != null ? childId : Long.MIN_VALUE;
-            } else {
-                return Long.MIN_VALUE;
-            }
-        }
-
-        /** {@inheritDoc} */
-        public int getChildrenCount(int groupPosition) {
-            // Count is any synced groups, plus possible footer
-            final AccountDisplay account = mAccounts.get(groupPosition);
-            final boolean anyHidden = account.mUnsyncedGroups.size() > 0;
-            return account.mSyncedGroups.size() + (anyHidden ? 1 : 0);
-        }
-
-        /** {@inheritDoc} */
-        public Object getGroup(int groupPosition) {
-            return mAccounts.get(groupPosition);
-        }
-
-        /** {@inheritDoc} */
-        public int getGroupCount() {
-            if (mAccounts == null) {
-                return 0;
-            }
-            return mAccounts.size();
-        }
-
-        /** {@inheritDoc} */
-        public long getGroupId(int groupPosition) {
-            return groupPosition;
-        }
-
-        /** {@inheritDoc} */
-        public boolean hasStableIds() {
-            return true;
-        }
-
-        /** {@inheritDoc} */
-        public boolean isChildSelectable(int groupPosition, int childPosition) {
-            return true;
-        }
-    }
-
-    /**
-     * Handle any clicks on header views added to our {@link #mAdapter}, which
-     * are usually the global modifier checkboxes.
-     */
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        Log.d(TAG, "OnItemClick, position=" + position + ", id=" + id);
-        if (view == mHeaderPhones) {
-            mDisplayPhones.toggle();
-            return;
-        }
-        if (view == mDisplayOrderView) {
-            Log.d(TAG, "Showing Display Order dialog");
-            showDialog(DIALOG_DISPLAY_ORDER);
-            return;
-        }
-        if (view == mSortOrderView) {
-            Log.d(TAG, "Showing Sort Order dialog");
-            showDialog(DIALOG_SORT_ORDER);
-            return;
-        }
-    }
-
-    /** {@inheritDoc} */
-    public void onClick(View view) {
-        switch (view.getId()) {
-            case R.id.btn_done: {
-                this.doSaveAction();
-                break;
-            }
-            case R.id.btn_discard: {
-                this.finish();
-                break;
-            }
-        }
-    }
-
-    /**
-     * Assign a specific value to {@link Prefs#DISPLAY_ONLY_PHONES}, refreshing
-     * the visible list as needed.
-     */
-    protected void setDisplayOnlyPhones(boolean displayOnlyPhones) {
-        mDisplayPhones.setChecked(displayOnlyPhones);
-
-        Editor editor = mPrefs.edit();
-        editor.putBoolean(Prefs.DISPLAY_ONLY_PHONES, displayOnlyPhones);
-        editor.apply();
-
-        mAdapter.setChildDescripWithPhones(displayOnlyPhones);
-        mAdapter.notifyDataSetChanged();
-    }
-
-    /**
-     * Handle any clicks on {@link ExpandableListAdapter} children, which
-     * usually mean toggling its visible state.
-     */
-    @Override
-    public boolean onChildClick(ExpandableListView parent, View view, int groupPosition,
-            int childPosition, long id) {
-        final CheckBox checkbox = (CheckBox)view.findViewById(android.R.id.checkbox);
-
-        final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
-        final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
-        if (child != null) {
-            checkbox.toggle();
-            child.putVisible(checkbox.isChecked());
-        } else {
-            // Open context menu for bringing back unsynced
-            this.openContextMenu(view);
-        }
-        return true;
-    }
-
-    // TODO: move these definitions to framework constants when we begin
-    // defining this mode through <sync-adapter> tags
-    private static final int SYNC_MODE_UNSUPPORTED = 0;
-    private static final int SYNC_MODE_UNGROUPED = 1;
-    private static final int SYNC_MODE_EVERYTHING = 2;
-
-    protected int getSyncMode(AccountDisplay account) {
-        // TODO: read sync mode through <sync-adapter> definition
-        if (GoogleSource.ACCOUNT_TYPE.equals(account.mType)) {
-            return SYNC_MODE_EVERYTHING;
-        } else {
-            return SYNC_MODE_UNSUPPORTED;
-        }
-    }
-
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View view,
-            ContextMenu.ContextMenuInfo menuInfo) {
-        super.onCreateContextMenu(menu, view, menuInfo);
-
-        // Bail if not working with expandable long-press, or if not child
-        if (!(menuInfo instanceof ExpandableListContextMenuInfo)) return;
-
-        final ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuInfo;
-        final int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
-        final int childPosition = ExpandableListView.getPackedPositionChild(info.packedPosition);
-
-        // Skip long-press on expandable parents
-        if (childPosition == -1) return;
-
-        final AccountDisplay account = (AccountDisplay)mAdapter.getGroup(groupPosition);
-        final GroupDelta child = (GroupDelta)mAdapter.getChild(groupPosition, childPosition);
-
-        // Ignore when selective syncing unsupported
-        final int syncMode = getSyncMode(account);
-        if (syncMode == SYNC_MODE_UNSUPPORTED) return;
-
-        if (child != null) {
-            showRemoveSync(menu, account, child, syncMode);
-        } else {
-            showAddSync(menu, account, syncMode);
-        }
-    }
-
-    protected void showRemoveSync(ContextMenu menu, final AccountDisplay account,
-            final GroupDelta child, final int syncMode) {
-        final CharSequence title = child.getTitle(this);
-
-        menu.setHeaderTitle(title);
-        menu.add(R.string.menu_sync_remove).setOnMenuItemClickListener(
-                new OnMenuItemClickListener() {
-                    public boolean onMenuItemClick(MenuItem item) {
-                        handleRemoveSync(account, child, syncMode, title);
-                        return true;
-                    }
-                });
-    }
-
-    protected void handleRemoveSync(final AccountDisplay account, final GroupDelta child,
-            final int syncMode, CharSequence title) {
-        final boolean shouldSyncUngrouped = account.mUngrouped.getShouldSync();
-        if (syncMode == SYNC_MODE_EVERYTHING && shouldSyncUngrouped
-                && !child.equals(account.mUngrouped)) {
-            // Warn before removing this group when it would cause ungrouped to stop syncing
-            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
-            final CharSequence removeMessage = this.getString(
-                    R.string.display_warn_remove_ungrouped, title);
-            builder.setTitle(R.string.menu_sync_remove);
-            builder.setMessage(removeMessage);
-            builder.setNegativeButton(android.R.string.cancel, null);
-            builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-                public void onClick(DialogInterface dialog, int which) {
-                    // Mark both this group and ungrouped to stop syncing
-                    account.setShouldSync(account.mUngrouped, false);
-                    account.setShouldSync(child, false);
-                    mAdapter.notifyDataSetChanged();
-                }
-            });
-            builder.show();
-        } else {
-            // Mark this group to not sync
-            account.setShouldSync(child, false);
-            mAdapter.notifyDataSetChanged();
-        }
-    }
-
-    protected void showAddSync(ContextMenu menu, final AccountDisplay account, final int syncMode) {
-        menu.setHeaderTitle(R.string.dialog_sync_add);
-
-        // Create item for each available, unsynced group
-        for (final GroupDelta child : account.mUnsyncedGroups) {
-            if (!child.getShouldSync()) {
-                final CharSequence title = child.getTitle(this);
-                menu.add(title).setOnMenuItemClickListener(new OnMenuItemClickListener() {
-                    public boolean onMenuItemClick(MenuItem item) {
-                        // Adding specific group for syncing
-                        if (child.mUngrouped && syncMode == SYNC_MODE_EVERYTHING) {
-                            account.setShouldSync(true);
-                        } else {
-                            account.setShouldSync(child, true);
-                        }
-                        mAdapter.notifyDataSetChanged();
-                        return true;
-                    }
-                });
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onBackPressed() {
-        doSaveAction();
-    }
-
-    private void doSaveAction() {
-        mContactsPrefs.setSortOrder(mSortOrder);
-        mContactsPrefs.setDisplayOrder(mDisplayOrder);
-
-        if (mAdapter == null || mAdapter.mAccounts == null) {
-            return;
-        }
-        setDisplayOnlyPhones(mDisplayPhones.isChecked());
-        new UpdateTask(this).execute(mAdapter.mAccounts);
-    }
-
-    /**
-     * Background task that persists changes to {@link Groups#GROUP_VISIBLE},
-     * showing spinner dialog to user while updating.
-     */
-    public static class UpdateTask extends
-            WeakAsyncTask<AccountSet, Void, Void, Activity> {
-        private WeakReference<ProgressDialog> mProgress;
-
-        public UpdateTask(Activity target) {
-            super(target);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        protected void onPreExecute(Activity target) {
-            final Context context = target;
-
-            mProgress = new WeakReference<ProgressDialog>(ProgressDialog.show(context, null,
-                    context.getText(R.string.savingDisplayGroups)));
-
-            // Before starting this task, start an empty service to protect our
-            // process from being reclaimed by the system.
-            context.startService(new Intent(context, EmptyService.class));
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        protected Void doInBackground(Activity target, AccountSet... params) {
-            final Context context = target;
-            final ContentValues values = new ContentValues();
-            final ContentResolver resolver = context.getContentResolver();
-
-            try {
-                // Build changes and persist in transaction
-                final AccountSet set = params[0];
-                final ArrayList<ContentProviderOperation> diff = set.buildDiff();
-                resolver.applyBatch(ContactsContract.AUTHORITY, diff);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Problem saving display groups", e);
-            } catch (OperationApplicationException e) {
-                Log.e(TAG, "Problem saving display groups", e);
-            }
-
-            return null;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        protected void onPostExecute(Activity target, Void result) {
-            final Context context = target;
-
-            final ProgressDialog dialog = mProgress.get();
-            if (dialog != null) {
-                try {
-                    dialog.dismiss();
-                } catch (Exception e) {
-                    Log.e(TAG, "Error dismissing progress dialog", e);
-                }
-            }
-
-            target.finish();
-
-            // Stop the service that was protecting us
-            context.stopService(new Intent(context, EmptyService.class));
-        }
-    }
-
-    @Override
-    public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
-            boolean globalSearch) {
-        if (globalSearch) {
-            super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
-        } else {
-            ContactsSearchManager.startSearch(this, initialQuery);
-        }
-    }
-}