Merge "Make photo loader low-memory device friendly" into ics-mr1
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2877820..11b9cde 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -44,6 +44,7 @@
     <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
     <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
     <uses-permission android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL" />
+    <uses-permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK" />
     <!-- allow broadcasting secret code intents that reboot the phone -->
     <uses-permission android:name="android.permission.REBOOT" />
     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
diff --git a/res/layout-sw580dp/contact_picker.xml b/res/layout-sw580dp/contact_picker.xml
index c6582e0..127021c 100644
--- a/res/layout-sw580dp/contact_picker.xml
+++ b/res/layout-sw580dp/contact_picker.xml
@@ -20,19 +20,32 @@
     android:orientation="vertical"
     android:layout_height="match_parent">
     <!-- Right bound should be aligned to ListView's right edge. -->
+    <!--
+      The SearchView should have a max width to prevent the dialog from resizing to the
+      full screen width of the device. The precise value of the max width is not as important
+      because the SearchView can take on a smaller width than the max width, so in some cases it
+      will take on the automatically computed width of a dialog (based on the dialog contents)
+      from the framework.
+    -->
     <view
         class="android.widget.SearchView"
         android:id="@+id/search_view"
         android:layout_width="match_parent"
+        android:maxWidth="@dimen/contact_picker_search_view_max_width"
         android:layout_height="wrap_content"
         android:layout_marginLeft="0dip"
         android:layout_marginRight="@dimen/list_visible_scrollbar_padding"
         android:paddingRight="0dip"
         android:iconifiedByDefault="false" />
-    <!-- will contain an appropriate contacts list -->
+    <!--
+      This will contain an appropriate contacts list. Add a min height to prevent
+      the dialog from resizing too much when the search results change. The activity dialog
+      is wrap content for height in the framework, so there is no way around this.
+    -->
     <FrameLayout
         android:id="@+id/list_container"
         android:layout_width="match_parent"
+        android:minHeight="@dimen/contact_picker_contact_list_min_height"
         android:layout_height="0dip"
         android:layout_weight="1" />
 
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index 4735d03..f87e981 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -33,7 +33,7 @@
     </FrameLayout>
     <FrameLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
     >
         <ListView android:id="@android:id/list"
             android:layout_width="match_parent"
diff --git a/res/layout/dialtacts_activity.xml b/res/layout/dialtacts_activity.xml
index af85bba..d1af632 100644
--- a/res/layout/dialtacts_activity.xml
+++ b/res/layout/dialtacts_activity.xml
@@ -17,18 +17,11 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:layout_marginTop="?android:attr/actionBarSize">
-
+    android:layout_marginTop="?android:attr/actionBarSize"
+    android:id="@+id/dialtacts_frame"
+    >
     <com.android.contacts.activities.DialtactsViewPager
         android:id="@+id/pager"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
-
-    <!-- For phone search UI -->
-    <fragment
-        android:id="@+id/phone_number_picker_fragment"
-        class="com.android.contacts.list.PhoneNumberPickerFragment"
-        android:layout_height="match_parent"
-        android:layout_width="match_parent" />
-
 </FrameLayout>
diff --git a/res/values-sw680dp/dimens.xml b/res/values-sw680dp/dimens.xml
index 0876995..0bed1ae 100644
--- a/res/values-sw680dp/dimens.xml
+++ b/res/values-sw680dp/dimens.xml
@@ -19,4 +19,5 @@
     <dimen name="editor_round_button_padding_right">8dip</dimen>
     <dimen name="group_editor_side_padding">16dip</dimen>
     <dimen name="quick_contact_photo_container_height">400dip</dimen>
+    <dimen name="contact_picker_contact_list_min_height">650dip</dimen>
 </resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9f5766e..e856d67 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -234,4 +234,12 @@
          Right now the drawable has implicit 32dip minimal height, which is confusing.
          This value is for making the hidden configuration explicit in xml. -->
     <dimen name="list_section_divider_min_height">32dip</dimen>
+
+    <!-- Max width of the SearchView when the contact picker is a dialog (on wide
+         screen devices). -->
+    <dimen name="contact_picker_search_view_max_width">550dip</dimen>
+
+    <!-- Min height of the list of contacts when the contact picker is a dialog (on
+        wide screen devices). -->
+    <dimen name="contact_picker_contact_list_min_height">550dip</dimen>
 </resources>
diff --git a/src/com/android/contacts/activities/ActionBarAdapter.java b/src/com/android/contacts/activities/ActionBarAdapter.java
index 77caaf7..b90d4c6 100644
--- a/src/com/android/contacts/activities/ActionBarAdapter.java
+++ b/src/com/android/contacts/activities/ActionBarAdapter.java
@@ -374,6 +374,18 @@
         outState.putInt(EXTRA_KEY_SELECTED_TAB, mCurrentTab.ordinal());
     }
 
+    /**
+     * Clears the focus from the {@link SearchView} if we are in search mode.
+     * This will suppress the IME if it is visible.
+     */
+    public void clearFocusOnSearchView() {
+        if (isSearchMode()) {
+            if (mSearchView != null) {
+                mSearchView.clearFocus();
+            }
+        }
+    }
+
     private void setFocusOnSearchView() {
         mSearchView.requestFocus();
         mSearchView.setIconified(false); // Workaround for the "IME not popping up" issue.
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index 1a8e383..b949176 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -57,15 +57,16 @@
     private static final String TAG = "ContactDetailActivity";
 
     /**
-     * Intent key for a boolean that specifies whether the "up" afforance in this activity should
-     * behave as default (return user back to {@link PeopleActivity}) or whether the activity should
-     * instead be finished.
+     * Boolean intent key that specifies whether pressing the "up" affordance in this activity
+     * should cause it to finish itself or launch an intent to bring the user back to a specific
+     * parent activity - the {@link PeopleActivity}.
      */
-    public static final String INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR = "ignoreDefaultUpBehavior";
+    public static final String INTENT_KEY_FINISH_ACTIVITY_ON_UP_SELECTED =
+            "finishActivityOnUpSelected";
 
     private ContactLoader.Result mContactData;
     private Uri mLookupUri;
-    private boolean mIgnoreDefaultUpBehavior;
+    private boolean mFinishActivityOnUpSelected;
 
     private ContactDetailLayoutController mContactDetailLayoutController;
     private ContactLoaderFragment mLoaderFragment;
@@ -92,8 +93,8 @@
             return;
         }
 
-        mIgnoreDefaultUpBehavior = getIntent().getBooleanExtra(
-                INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR, false);
+        mFinishActivityOnUpSelected = getIntent().getBooleanExtra(
+                INTENT_KEY_FINISH_ACTIVITY_ON_UP_SELECTED, false);
 
         setContentView(R.layout.contact_detail_activity);
 
@@ -211,8 +212,13 @@
 
         @Override
         public void onEditRequested(Uri contactLookupUri) {
-            startActivity(new Intent(Intent.ACTION_EDIT, contactLookupUri));
-            finish();
+            Intent intent = new Intent(Intent.ACTION_EDIT, contactLookupUri);
+            intent.putExtra(
+                    ContactEditorActivity.INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, true);
+            // Don't finish the detail activity after launching the editor because when the
+            // editor is done, we will still want to show the updated contact details using
+            // this activity.
+            startActivity(intent);
         }
 
         @Override
@@ -285,7 +291,7 @@
 
         switch (item.getItemId()) {
             case android.R.id.home:
-                if (mIgnoreDefaultUpBehavior) {
+                if (mFinishActivityOnUpSelected) {
                     finish();
                     return true;
                 }
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index 07f340e..d591b42 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -50,14 +50,31 @@
     public static final String ACTION_JOIN_COMPLETED = "joinCompleted";
     public static final String ACTION_SAVE_COMPLETED = "saveCompleted";
 
+    /**
+     * Boolean intent key that specifies that this activity should finish itself
+     * (instead of launching a new view intent) after the editor changes have been
+     * saved.
+     */
+    public static final String INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED =
+            "finishActivityOnSaveCompleted";
+
     private ContactEditorFragment mFragment;
+    private boolean mFinishActivityOnSaveCompleted;
 
     private DialogManager mDialogManager = new DialogManager(this);
 
     @Override
     public void onCreate(Bundle savedState) {
         super.onCreate(savedState);
-        String action = getIntent().getAction();
+
+        final Intent intent = getIntent();
+        final String action = intent.getAction();
+
+        // Determine whether or not this activity should be finished after the user is done
+        // editing the contact or if this activity should launch another activity to view the
+        // contact's details.
+        mFinishActivityOnSaveCompleted = intent.getBooleanExtra(
+                INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, false);
 
         // The only situation where action could be ACTION_JOIN_COMPLETED is if the
         // user joined the contact with another and closed the activity before
@@ -146,7 +163,9 @@
 
         @Override
         public void onSaveFinished(Intent resultIntent) {
-            if (resultIntent != null) {
+            if (mFinishActivityOnSaveCompleted) {
+                setResult(resultIntent == null ? RESULT_CANCELED : RESULT_OK, resultIntent);
+            } else if (resultIntent != null) {
                 startActivity(resultIntent);
             }
             finish();
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index ac13ba3..b5b6c1d 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -153,8 +153,10 @@
     }
 
     private void prepareSearchViewAndActionBar() {
-        // Postal address picker doesn't support search, so just show "HomeAsUp" button and title.
-        if (mRequest.getActionCode() == ContactsRequest.ACTION_PICK_POSTAL) {
+        // Postal address pickers (and legacy pickers) don't support search, so just show
+        // "HomeAsUp" button and title.
+        if (mRequest.getActionCode() == ContactsRequest.ACTION_PICK_POSTAL ||
+                mRequest.isLegacyCompatibilityMode()) {
             findViewById(R.id.search_view).setVisibility(View.GONE);
             final ActionBar actionBar = getActionBar();
             if (actionBar != null) {
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index 2268743..7e95fed 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -120,10 +120,6 @@
     }
 
     public class ViewPagerAdapter extends FragmentPagerAdapter {
-        private DialpadFragment mDialpadFragment;
-        private CallLogFragment mCallLogFragment;
-        private PhoneFavoriteFragment mPhoneFavoriteFragment;
-
         public ViewPagerAdapter(FragmentManager fm) {
             super(fm);
         }
@@ -132,20 +128,11 @@
         public Fragment getItem(int position) {
             switch (position) {
                 case TAB_INDEX_DIALER:
-                    if (mDialpadFragment == null) {
-                        mDialpadFragment = new DialpadFragment();
-                    }
-                    return mDialpadFragment;
+                    return new DialpadFragment();
                 case TAB_INDEX_CALL_LOG:
-                    if (mCallLogFragment == null) {
-                        mCallLogFragment = new CallLogFragment();
-                    }
-                    return mCallLogFragment;
+                    return new CallLogFragment();
                 case TAB_INDEX_FAVORITES:
-                    if (mPhoneFavoriteFragment == null) {
-                        mPhoneFavoriteFragment = new PhoneFavoriteFragment();
-                    }
-                    return mPhoneFavoriteFragment;
+                    return new PhoneFavoriteFragment();
             }
             throw new IllegalStateException("No fragment at position " + position);
         }
@@ -362,7 +349,9 @@
                 @Override
                 public boolean onQueryTextChange(String newText) {
                     // Show search result with non-empty text. Show a bare list otherwise.
-                    mSearchFragment.setQueryString(newText, true);
+                    if (mSearchFragment != null) {
+                        mSearchFragment.setQueryString(newText, true);
+                    }
                     return true;
                 }
     };
@@ -385,6 +374,16 @@
                 }
     };
 
+    private final View.OnLayoutChangeListener mFirstLayoutListener
+            = new View.OnLayoutChangeListener() {
+        @Override
+        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+                int oldTop, int oldRight, int oldBottom) {
+            v.removeOnLayoutChangeListener(this); // Unregister self.
+            addSearchFragment();
+        }
+    };
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -397,6 +396,8 @@
         mContactListFilterController = ContactListFilterController.getInstance(this);
         mContactListFilterController.addListener(mContactListFilterListener);
 
+        findViewById(R.id.dialtacts_frame).addOnLayoutChangeListener(mFirstLayoutListener);
+
         mViewPager = (ViewPager) findViewById(R.id.pager);
         mViewPager.setAdapter(new ViewPagerAdapter(getFragmentManager()));
         mViewPager.setOnPageChangeListener(mPageChangeListener);
@@ -443,6 +444,29 @@
         mContactListFilterController.removeListener(mContactListFilterListener);
     }
 
+    /**
+     * Add search fragment.  Note this is called during onLayout, so there's some restrictions,
+     * such as executePendingTransaction can't be used in it.
+     */
+    private void addSearchFragment() {
+        // In order to take full advantage of "fragment deferred start", we need to create the
+        // search fragment after all other fragments are created.
+        // The other fragments are created by the ViewPager on the first onMeasure().
+        // We use the first onLayout call, which is after onMeasure().
+
+        // Just return if the fragment is already created, which happens after configuration
+        // changes.
+        if (mSearchFragment != null) return;
+
+        final FragmentTransaction ft = getFragmentManager().beginTransaction();
+        final Fragment searchFragment = new PhoneNumberPickerFragment();
+
+        searchFragment.setUserVisibleHint(false);
+        ft.add(R.id.dialtacts_frame, searchFragment);
+        ft.hide(searchFragment);
+        ft.commitAllowingStateLoss();
+    }
+
     private void prepareSearchView() {
         final View searchViewLayout =
                 getLayoutInflater().inflate(R.layout.dialtacts_custom_action_bar, null);
@@ -508,14 +532,25 @@
             mSearchFragment.setQuickContactEnabled(true);
             mSearchFragment.setDarkTheme(true);
             mSearchFragment.setPhotoPosition(ContactListItemView.PhotoPosition.LEFT);
-            mSearchFragment.setUserVisibleHint(false);
-            final FragmentTransaction transaction = getFragmentManager().beginTransaction();
-            if (mInSearchUi) {
-                transaction.show(mSearchFragment);
-            } else {
-                transaction.hide(mSearchFragment);
+            if (mContactListFilterController != null
+                    && mContactListFilterController.getFilter() != null) {
+                mSearchFragment.setFilter(mContactListFilterController.getFilter());
             }
-            transaction.commitAllowingStateLoss();
+            // Here we assume that we're not on the search mode, so let's hide the fragment.
+            //
+            // We get here either when the fragment is created (normal case), or after configuration
+            // changes.  In the former case, we're not in search mode because we can only
+            // enter search mode if the fragment is created.  (see enterSearchUi())
+            // In the latter case we're not in search mode either because we don't retain
+            // mInSearchUi -- ideally we should but at this point it's not supported.
+            mSearchFragment.setUserVisibleHint(false);
+            // After configuration changes fragments will forget their "hidden" state, so make
+            // sure to hide it.
+            if (!mSearchFragment.isHidden()) {
+                final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+                transaction.hide(mSearchFragment);
+                transaction.commitAllowingStateLoss();
+            }
         }
     }
 
@@ -635,7 +670,7 @@
         if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
             setupFilterText(newIntent);
         }
-        if (mInSearchUi || mSearchFragment.isVisible()) {
+        if (mInSearchUi || (mSearchFragment != null && mSearchFragment.isVisible())) {
             exitSearchUi();
         }
 
@@ -814,6 +849,15 @@
      * Hides every tab and shows search UI for phone lookup.
      */
     private void enterSearchUi() {
+        if (mSearchFragment == null) {
+            // We add the search fragment dynamically in the first onLayoutChange() and
+            // mSearchFragment is set sometime later when the fragment transaction is actually
+            // executed, which means there's a window when users are able to hit the (physical)
+            // search key but mSearchFragment is still null.
+            // It's quite hard to handle this case right, so let's just ignore the search key
+            // in this case.  Users can just hit it again and it will work this time.
+            return;
+        }
         if (mSearchView == null) {
             prepareSearchView();
         }
@@ -837,6 +881,7 @@
         sendFragmentVisibilityChange(mViewPager.getCurrentItem(), false);
 
         // Show the search fragment and hide everything else.
+        mSearchFragment.setUserVisibleHint(true);
         final FragmentTransaction transaction = getFragmentManager().beginTransaction();
         transaction.show(mSearchFragment);
         transaction.commitAllowingStateLoss();
@@ -846,7 +891,6 @@
         // layout instead of asking the search menu item to take care of SearchView.
         mSearchView.onActionViewExpanded();
         mInSearchUi = true;
-        mSearchFragment.setUserVisibleHint(true);
     }
 
     private void showInputMethod(View view) {
@@ -872,9 +916,14 @@
     private void exitSearchUi() {
         final ActionBar actionBar = getActionBar();
 
-        final FragmentTransaction transaction = getFragmentManager().beginTransaction();
-        transaction.hide(mSearchFragment);
-        transaction.commitAllowingStateLoss();
+        // Hide the search fragment, if exists.
+        if (mSearchFragment != null) {
+            mSearchFragment.setUserVisibleHint(false);
+
+            final FragmentTransaction transaction = getFragmentManager().beginTransaction();
+            transaction.hide(mSearchFragment);
+            transaction.commitAllowingStateLoss();
+        }
 
         // We want to hide SearchView and show Tabs. Also focus on previously selected one.
         actionBar.setDisplayShowCustomEnabled(false);
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index b0355fc..6c36b5d 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -106,7 +106,7 @@
         @Override
         public void onContactSelected(Uri contactUri) {
             Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
-            intent.putExtra(ContactDetailActivity.INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR, true);
+            intent.putExtra(ContactDetailActivity.INTENT_KEY_FINISH_ACTIVITY_ON_UP_SELECTED, true);
             startActivity(intent);
         }
 
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 3ba5957..1c873ff 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -110,9 +110,12 @@
 
     private static final String TAG = "PeopleActivity";
 
-    private static final int SUBACTIVITY_NEW_GROUP = 2;
-    private static final int SUBACTIVITY_EDIT_GROUP = 3;
-    private static final int SUBACTIVITY_ACCOUNT_FILTER = 4;
+    // These values needs to start at 2. See {@link ContactEntryListFragment}.
+    private static final int SUBACTIVITY_NEW_CONTACT = 2;
+    private static final int SUBACTIVITY_EDIT_CONTACT = 3;
+    private static final int SUBACTIVITY_NEW_GROUP = 4;
+    private static final int SUBACTIVITY_EDIT_GROUP = 5;
+    private static final int SUBACTIVITY_ACCOUNT_FILTER = 6;
 
     private final DialogManager mDialogManager = new DialogManager(this);
 
@@ -989,11 +992,10 @@
             } else {
                 Intent intent = new Intent(Intent.ACTION_VIEW, contactLookupUri);
                 // In search mode, the "up" affordance in the contact detail page should return the
-                // user to the search results, so suppress the normal behavior which would re-launch
-                // {@link PeopleActivity} when the "up" affordance is clicked.
+                // user to the search results, so finish the activity when that button is selected.
                 if (mActionBarAdapter.isSearchMode()) {
-                    intent.putExtra(ContactDetailActivity.INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR,
-                            true);
+                    intent.putExtra(
+                            ContactDetailActivity.INTENT_KEY_FINISH_ACTIVITY_ON_UP_SELECTED, true);
                 }
                 startActivity(intent);
             }
@@ -1016,7 +1018,9 @@
             if (extras != null) {
                 intent.putExtras(extras);
             }
-            startActivity(intent);
+            intent.putExtra(
+                    ContactEditorActivity.INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, true);
+            startActivityForResult(intent, SUBACTIVITY_EDIT_CONTACT);
         }
 
         @Override
@@ -1101,7 +1105,10 @@
 
         @Override
         public void onEditRequested(Uri contactLookupUri) {
-            startActivity(new Intent(Intent.ACTION_EDIT, contactLookupUri));
+            Intent intent = new Intent(Intent.ACTION_EDIT, contactLookupUri);
+            intent.putExtra(
+                    ContactEditorActivity.INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, true);
+            startActivityForResult(intent, SUBACTIVITY_EDIT_CONTACT);
         }
 
         @Override
@@ -1390,7 +1397,17 @@
             }
             case R.id.menu_add_contact: {
                 final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
-                startActivity(intent);
+                // On 2-pane UI, we can let the editor activity finish itself and return
+                // to this activity to display the new contact.
+                if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
+                    intent.putExtra(
+                        ContactEditorActivity.INTENT_KEY_FINISH_ACTIVITY_ON_SAVE_COMPLETED, true);
+                    startActivityForResult(intent, SUBACTIVITY_NEW_CONTACT);
+                } else {
+                    // Otherwise, on 1-pane UI, we need the editor to launch the view contact
+                    // intent itself.
+                    startActivity(intent);
+                }
                 return true;
             }
             case R.id.menu_add_group: {
@@ -1465,6 +1482,19 @@
                 break;
             }
 
+            case SUBACTIVITY_NEW_CONTACT:
+            case SUBACTIVITY_EDIT_CONTACT: {
+                if (resultCode == RESULT_OK && PhoneCapabilityTester.isUsingTwoPanes(this)) {
+                    mRequest.setActionCode(ContactsRequest.ACTION_VIEW_CONTACT);
+                    mAllFragment.reloadDataAndSetSelectedUri(data.getData());
+                    // Suppress IME if in search mode
+                    if (mActionBarAdapter != null) {
+                        mActionBarAdapter.clearFocusOnSearchView();
+                    }
+                }
+                break;
+            }
+
             case SUBACTIVITY_NEW_GROUP:
             case SUBACTIVITY_EDIT_GROUP: {
                 if (resultCode == RESULT_OK && PhoneCapabilityTester.isUsingTwoPanes(this)) {
diff --git a/src/com/android/contacts/format/FormatUtils.java b/src/com/android/contacts/format/FormatUtils.java
index 8e2bb63..4b076cf 100644
--- a/src/com/android/contacts/format/FormatUtils.java
+++ b/src/com/android/contacts/format/FormatUtils.java
@@ -125,6 +125,7 @@
     }
 
     /** Returns a String that represents the content of the given {@link CharArrayBuffer}. */
+    @NeededForTesting
     public static String charArrayBufferToString(CharArrayBuffer buffer) {
         return new String(buffer.data, 0, buffer.sizeCopied);
     }
diff --git a/src/com/android/contacts/list/AccountFilterActivity.java b/src/com/android/contacts/list/AccountFilterActivity.java
index 0b4c6e0..14db634 100644
--- a/src/com/android/contacts/list/AccountFilterActivity.java
+++ b/src/com/android/contacts/list/AccountFilterActivity.java
@@ -118,8 +118,8 @@
                 continue;
             }
             Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
-            accountFilters.add(ContactListFilter.createAccountFilter(account.type, account.name,
-                    account.dataSet, icon, account.name));
+            accountFilters.add(ContactListFilter.createAccountFilter(
+                    account.type, account.name, account.dataSet, icon));
         }
 
         // Always show "All", even when there's no accounts.  (We may have local contacts)
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index 061646e..b63b402 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -142,12 +142,13 @@
         @Override
         protected void onPostExecute(Uri uri) {
             // Make sure the {@link Fragment} is at least still attached to the {@link Activity}
-            // before continuing.
-            if (mIsCancelled || !isAdded() || uri == null) {
+            // before continuing. Null URIs should still be allowed so that the list can be
+            // refreshed and a default contact can be selected (i.e. the case of deleted
+            // contacts).
+            if (mIsCancelled || !isAdded()) {
                 return;
             }
-            mSelectedContactUri = uri;
-            onContactUriQueryFinished(mSelectedContactUri);
+            onContactUriQueryFinished(uri);
         }
     }
 
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index 1592004..a8caf3b 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -39,56 +39,64 @@
 public abstract class ContactListAdapter extends ContactEntryListAdapter {
 
     protected static class ContactQuery {
-        public static final String[] PROJECTION_CONTACT = new String[] {
+        private static final String[] CONTACT_PROJECTION_PRIMARY = new String[] {
             Contacts._ID,                           // 0
             Contacts.DISPLAY_NAME_PRIMARY,          // 1
-            Contacts.DISPLAY_NAME_ALTERNATIVE,      // 2
-            Contacts.CONTACT_PRESENCE,              // 3
-            Contacts.CONTACT_STATUS,                // 4
-            Contacts.PHOTO_ID,                      // 5
-            Contacts.PHOTO_THUMBNAIL_URI,           // 6
-            Contacts.LOOKUP_KEY,                    // 7
-            Contacts.IS_USER_PROFILE,               // 8
+            Contacts.CONTACT_PRESENCE,              // 2
+            Contacts.CONTACT_STATUS,                // 3
+            Contacts.PHOTO_ID,                      // 4
+            Contacts.PHOTO_THUMBNAIL_URI,           // 5
+            Contacts.LOOKUP_KEY,                    // 6
+            Contacts.IS_USER_PROFILE,               // 7
         };
 
-        public static final String[] PROJECTION_DATA = new String[] {
-            Data.CONTACT_ID,                        // 0
-            Data.DISPLAY_NAME_PRIMARY,              // 1
-            Data.DISPLAY_NAME_ALTERNATIVE,          // 2
-            Data.CONTACT_PRESENCE,                  // 3
-            Data.CONTACT_STATUS,                    // 4
-            Data.PHOTO_ID,                          // 5
-            Data.PHOTO_THUMBNAIL_URI,               // 6
-            Data.LOOKUP_KEY,                        // 7
+        private static final String[] CONTACT_PROJECTION_ALTERNATIVE = new String[] {
+            Contacts._ID,                           // 0
+            Contacts.DISPLAY_NAME_ALTERNATIVE,      // 1
+            Contacts.CONTACT_PRESENCE,              // 2
+            Contacts.CONTACT_STATUS,                // 3
+            Contacts.PHOTO_ID,                      // 4
+            Contacts.PHOTO_THUMBNAIL_URI,           // 5
+            Contacts.LOOKUP_KEY,                    // 6
+            Contacts.IS_USER_PROFILE,               // 7
         };
 
-        public static final String[] FILTER_PROJECTION = new String[] {
+        private static final String[] FILTER_PROJECTION_PRIMARY = new String[] {
             Contacts._ID,                           // 0
             Contacts.DISPLAY_NAME_PRIMARY,          // 1
-            Contacts.DISPLAY_NAME_ALTERNATIVE,      // 2
-            Contacts.CONTACT_PRESENCE,              // 3
-            Contacts.CONTACT_STATUS,                // 4
-            Contacts.PHOTO_ID,                      // 5
-            Contacts.PHOTO_THUMBNAIL_URI,           // 6
-            Contacts.LOOKUP_KEY,                    // 7
-            Contacts.IS_USER_PROFILE,               // 8
-            SearchSnippetColumns.SNIPPET,           // 9
+            Contacts.CONTACT_PRESENCE,              // 2
+            Contacts.CONTACT_STATUS,                // 3
+            Contacts.PHOTO_ID,                      // 4
+            Contacts.PHOTO_THUMBNAIL_URI,           // 5
+            Contacts.LOOKUP_KEY,                    // 6
+            Contacts.IS_USER_PROFILE,               // 7
+            SearchSnippetColumns.SNIPPET,           // 8
         };
 
-        public static final int CONTACT_ID                       = 0;
-        public static final int CONTACT_DISPLAY_NAME_PRIMARY     = 1;
-        public static final int CONTACT_DISPLAY_NAME_ALTERNATIVE = 2;
-        public static final int CONTACT_PRESENCE_STATUS          = 3;
-        public static final int CONTACT_CONTACT_STATUS           = 4;
-        public static final int CONTACT_PHOTO_ID                 = 5;
-        public static final int CONTACT_PHOTO_URI                = 6;
-        public static final int CONTACT_LOOKUP_KEY               = 7;
-        public static final int CONTACT_IS_USER_PROFILE          = 8;
-        public static final int CONTACT_SNIPPET                  = 9;
+        private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] {
+            Contacts._ID,                           // 0
+            Contacts.DISPLAY_NAME_ALTERNATIVE,      // 1
+            Contacts.CONTACT_PRESENCE,              // 2
+            Contacts.CONTACT_STATUS,                // 3
+            Contacts.PHOTO_ID,                      // 4
+            Contacts.PHOTO_THUMBNAIL_URI,           // 5
+            Contacts.LOOKUP_KEY,                    // 6
+            Contacts.IS_USER_PROFILE,               // 7
+            SearchSnippetColumns.SNIPPET,           // 8
+        };
+
+        public static final int CONTACT_ID               = 0;
+        public static final int CONTACT_DISPLAY_NAME     = 1;
+        public static final int CONTACT_PRESENCE_STATUS  = 2;
+        public static final int CONTACT_CONTACT_STATUS   = 3;
+        public static final int CONTACT_PHOTO_ID         = 4;
+        public static final int CONTACT_PHOTO_URI        = 5;
+        public static final int CONTACT_LOOKUP_KEY       = 6;
+        public static final int CONTACT_IS_USER_PROFILE  = 7;
+        public static final int CONTACT_SNIPPET          = 8;
     }
 
     private CharSequence mUnknownNameText;
-    private int mDisplayNameColumnIndex;
 
     private long mSelectedContactDirectoryId;
     private String mSelectedContactLookupKey;
@@ -129,17 +137,7 @@
 
     @Override
     public String getContactDisplayName(int position) {
-        return ((Cursor)getItem(position)).getString(mDisplayNameColumnIndex);
-    }
-
-    @Override
-    public void setContactNameDisplayOrder(int displayOrder) {
-        super.setContactNameDisplayOrder(displayOrder);
-        if (getContactNameDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
-            mDisplayNameColumnIndex = ContactQuery.CONTACT_DISPLAY_NAME_PRIMARY;
-        } else {
-            mDisplayNameColumnIndex = ContactQuery.CONTACT_DISPLAY_NAME_ALTERNATIVE;
-        }
+        return ((Cursor) getItem(position)).getString(ContactQuery.CONTACT_DISPLAY_NAME);
     }
 
     /**
@@ -237,7 +235,8 @@
     }
 
     protected void bindName(final ContactListItemView view, Cursor cursor) {
-        view.showDisplayName(cursor, mDisplayNameColumnIndex, getContactNameDisplayOrder());
+        view.showDisplayName(
+                cursor, ContactQuery.CONTACT_DISPLAY_NAME, getContactNameDisplayOrder());
         // Note: we don't show phonetic any more (See issue 5265330)
     }
 
@@ -341,4 +340,24 @@
             setProfileExists(cursor.getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1);
         }
     }
+
+    /**
+     * @return Projection useful for children.
+     */
+    protected final String[] getProjection(boolean forSearch) {
+        final int sortOrder = getContactNameDisplayOrder();
+        if (forSearch) {
+            if (sortOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+                return ContactQuery.FILTER_PROJECTION_PRIMARY;
+            } else {
+                return ContactQuery.FILTER_PROJECTION_ALTERNATIVE;
+            }
+        } else {
+            if (sortOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+                return ContactQuery.CONTACT_PROJECTION_PRIMARY;
+            } else {
+                return ContactQuery.CONTACT_PROJECTION_ALTERNATIVE;
+            }
+        }
+    }
 }
diff --git a/src/com/android/contacts/list/ContactListFilter.java b/src/com/android/contacts/list/ContactListFilter.java
index 152b152..6e4e949 100644
--- a/src/com/android/contacts/list/ContactListFilter.java
+++ b/src/com/android/contacts/list/ContactListFilter.java
@@ -35,69 +35,51 @@
     public static final int FILTER_TYPE_SINGLE_CONTACT = -6;
 
     public static final int FILTER_TYPE_ACCOUNT = 0;
-    public static final int FILTER_TYPE_GROUP = 1;
+
+    /**
+     * Obsolete filter which had been used in Honeycomb. This may be stored in
+     * {@link SharedPreferences}, but should be replaced with ALL filter when it is found.
+     *
+     * TODO: "group" filter and relevant variables are all obsolete. Remove them.
+     */
+    private static final int FILTER_TYPE_GROUP = 1;
 
     private static final String KEY_FILTER_TYPE = "filter.type";
     private static final String KEY_ACCOUNT_NAME = "filter.accountName";
     private static final String KEY_ACCOUNT_TYPE = "filter.accountType";
     private static final String KEY_DATA_SET = "filter.dataSet";
-    private static final String KEY_GROUP_ID = "filter.groupId";
-    private static final String KEY_GROUP_SOURCE_ID = "filter.groupSourceId";
-    private static final String KEY_GROUP_READ_ONLY = "filter.groupReadOnly";
-    private static final String KEY_GROUP_TITLE = "filter.groupTitle";
 
     public final int filterType;
     public final String accountType;
     public final String accountName;
     public final String dataSet;
     public final Drawable icon;
-    public long groupId;
-    public String groupSourceId;
-    public final boolean groupReadOnly;
-    public final String title;
     private String mId;
 
     public ContactListFilter(int filterType, String accountType, String accountName, String dataSet,
-            Drawable icon, long groupId, String groupSourceId, boolean groupReadOnly,
-            String title) {
+            Drawable icon) {
         this.filterType = filterType;
         this.accountType = accountType;
         this.accountName = accountName;
         this.dataSet = dataSet;
         this.icon = icon;
-        this.groupId = groupId;
-        this.groupSourceId = groupSourceId;
-        this.groupReadOnly = groupReadOnly;
-        this.title = title;
     }
 
     public static ContactListFilter createFilterWithType(int filterType) {
-        return new ContactListFilter(filterType, null, null, null, null, 0, null, false, null);
-    }
-
-    public static ContactListFilter createGroupFilter(long groupId) {
-        return new ContactListFilter(ContactListFilter.FILTER_TYPE_GROUP, null, null, null, null,
-                groupId, null, false, null);
-    }
-
-    public static ContactListFilter createGroupFilter(String accountType, String accountName,
-            String dataSet, long groupId, String groupSourceId, boolean groupReadOnly,
-            String title) {
-        return new ContactListFilter(ContactListFilter.FILTER_TYPE_GROUP, accountType, accountName,
-                dataSet, null, groupId, groupSourceId, groupReadOnly, title);
+        return new ContactListFilter(filterType, null, null, null, null);
     }
 
     public static ContactListFilter createAccountFilter(String accountType, String accountName,
-            String dataSet, Drawable icon, String title) {
+            String dataSet, Drawable icon) {
         return new ContactListFilter(ContactListFilter.FILTER_TYPE_ACCOUNT, accountType,
-                accountName, dataSet, icon, 0, null, false, title);
+                accountName, dataSet, icon);
     }
 
     /**
      * Returns true if this filter is based on data and may become invalid over time.
      */
     public boolean isValidationRequired() {
-        return filterType == FILTER_TYPE_ACCOUNT || filterType == FILTER_TYPE_GROUP;
+        return filterType == FILTER_TYPE_ACCOUNT;
     }
 
     @Override
@@ -118,9 +100,6 @@
             case FILTER_TYPE_ACCOUNT:
                 return "account: " + accountType + (dataSet != null ? "/" + dataSet : "")
                         + " " + accountName;
-            case FILTER_TYPE_GROUP:
-                return "group: " + accountType + (dataSet != null ? "/" + dataSet : "")
-                        + " " + accountName + " " + title + "(" + groupId + ")";
         }
         return super.toString();
     }
@@ -137,13 +116,7 @@
             return res;
         }
 
-        if (filterType != another.filterType) {
-            return filterType - another.filterType;
-        }
-
-        String title1 = title != null ? title : "";
-        String title2 = another.title != null ? another.title : "";
-        return title1.compareTo(title2);
+        return filterType - another.filterType;
     }
 
     @Override
@@ -156,11 +129,6 @@
         if (dataSet != null) {
             code = code * 31 + dataSet.hashCode();
         }
-        if (groupSourceId != null) {
-            code = code * 31 + groupSourceId.hashCode();
-        } else if (groupId != 0) {
-            code = code * 31 + (int) groupId;
-        }
         return code;
     }
 
@@ -182,11 +150,7 @@
             return false;
         }
 
-        if (groupSourceId != null && otherFilter.groupSourceId != null) {
-            return groupSourceId.equals(otherFilter.groupSourceId);
-        }
-
-        return groupId == otherFilter.groupId;
+        return true;
     }
 
     public static void storeToPreferences(SharedPreferences prefs, ContactListFilter filter) {
@@ -195,10 +159,6 @@
             .putString(KEY_ACCOUNT_NAME, filter == null ? null : filter.accountName)
             .putString(KEY_ACCOUNT_TYPE, filter == null ? null : filter.accountType)
             .putString(KEY_DATA_SET, filter == null ? null : filter.dataSet)
-            .putLong(KEY_GROUP_ID, filter == null ? -1 : filter.groupId)
-            .putString(KEY_GROUP_SOURCE_ID, filter == null ? null : filter.groupSourceId)
-            .putBoolean(KEY_GROUP_READ_ONLY, filter == null ? false : filter.groupReadOnly)
-            .putString(KEY_GROUP_TITLE, filter == null ? null : filter.title)
             .apply();
     }
 
@@ -209,13 +169,16 @@
     public static ContactListFilter restoreDefaultPreferences(SharedPreferences prefs) {
         ContactListFilter filter = restoreFromPreferences(prefs);
         if (filter == null) {
-            filter = ContactListFilter.createFilterWithType(
-                    ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS);
+            filter = ContactListFilter.createFilterWithType(FILTER_TYPE_ALL_ACCOUNTS);
+        }
+        // "Group" filter is obsolete and thus is not exposed anymore.
+        if (filter.filterType == FILTER_TYPE_GROUP) {
+            filter = ContactListFilter.createFilterWithType(FILTER_TYPE_ALL_ACCOUNTS);
         }
         return filter;
     }
 
-    public static ContactListFilter restoreFromPreferences(SharedPreferences prefs) {
+    private static ContactListFilter restoreFromPreferences(SharedPreferences prefs) {
         int filterType = prefs.getInt(KEY_FILTER_TYPE, FILTER_TYPE_DEFAULT);
         if (filterType == FILTER_TYPE_DEFAULT) {
             return null;
@@ -224,12 +187,7 @@
         String accountName = prefs.getString(KEY_ACCOUNT_NAME, null);
         String accountType = prefs.getString(KEY_ACCOUNT_TYPE, null);
         String dataSet = prefs.getString(KEY_DATA_SET, null);
-        long groupId = prefs.getLong(KEY_GROUP_ID, -1);
-        String groupSourceId = prefs.getString(KEY_GROUP_SOURCE_ID, null);
-        boolean groupReadOnly = prefs.getBoolean(KEY_GROUP_READ_ONLY, false);
-        String title = prefs.getString(KEY_GROUP_TITLE, "group");
-        return new ContactListFilter(filterType, accountType, accountName, dataSet, null, groupId,
-                groupSourceId, groupReadOnly, title);
+        return new ContactListFilter(filterType, accountType, accountName, dataSet, null);
     }
 
 
@@ -239,9 +197,6 @@
         dest.writeString(accountName);
         dest.writeString(accountType);
         dest.writeString(dataSet);
-        dest.writeLong(groupId);
-        dest.writeString(groupSourceId);
-        dest.writeInt(groupReadOnly ? 1 : 0);
     }
 
     public static final Parcelable.Creator<ContactListFilter> CREATOR =
@@ -252,11 +207,7 @@
             String accountName = source.readString();
             String accountType = source.readString();
             String dataSet = source.readString();
-            long groupId = source.readLong();
-            String groupSourceId = source.readString();
-            boolean groupReadOnly = source.readInt() != 0;
-            return new ContactListFilter(filterType, accountType, accountName, dataSet, null,
-                    groupId, groupSourceId, groupReadOnly, null);
+            return new ContactListFilter(filterType, accountType, accountName, dataSet, null);
         }
 
         @Override
@@ -286,11 +237,6 @@
             if (accountName != null) {
                 sb.append('-').append(accountName.replace('-', '_'));
             }
-            if (groupSourceId != null) {
-                sb.append('-').append(groupSourceId);
-            } else if (groupId != 0) {
-                sb.append('-').append(groupId);
-            }
             mId = sb.toString();
         }
         return mId;
@@ -304,12 +250,6 @@
                     .append(", accountName: " + accountName)
                     .append(", dataSet: " + dataSet);
         }
-        if (filterType == FILTER_TYPE_GROUP) {
-            builder.append(", groupId: " + groupId)
-                    .append(", groupSourceId: " + groupSourceId)
-                    .append(", groupReadOnly: " + groupReadOnly)
-                    .append("title: " + title);
-        }
         builder.append(", icon: " + icon + "]");
         return builder.toString();
     }
@@ -330,8 +270,6 @@
                 return "FILTER_TYPE_SINGLE_CONTACT";
             case FILTER_TYPE_ACCOUNT:
                 return "FILTER_TYPE_ACCOUNT";
-            case FILTER_TYPE_GROUP:
-                return "FILTER_TYPE_GROUP";
             default:
                 return "(unknown)";
         }
diff --git a/src/com/android/contacts/list/ContactListFilterView.java b/src/com/android/contacts/list/ContactListFilterView.java
index 6dc9bc3..398a864 100644
--- a/src/com/android/contacts/list/ContactListFilterView.java
+++ b/src/com/android/contacts/list/ContactListFilterView.java
@@ -115,15 +115,6 @@
                 }
                 break;
             }
-            case ContactListFilter.FILTER_TYPE_GROUP: {
-                mIcon.setVisibility(View.VISIBLE);
-                mIcon.setImageResource(R.drawable.ic_menu_display_all_holo_light);
-                mLabel.setText(mFilter.title);
-                if (dropdown) {
-                    mIndent.setVisibility(mSingleAccount ? View.GONE : View.VISIBLE);
-                }
-                break;
-            }
         }
     }
 
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 0cc211a..4bf1a04 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -177,10 +177,6 @@
                         mCounterHeaderView.setText(getString(
                                 R.string.listTotalAllContactsZeroGroup, filter.accountName));
                         break;
-                    case ContactListFilter.FILTER_TYPE_GROUP:
-                        mCounterHeaderView.setText(
-                                getString(R.string.listTotalAllContactsZeroGroup, filter.title));
-                        break;
                     case ContactListFilter.FILTER_TYPE_WITH_PHONE_NUMBERS_ONLY:
                         mCounterHeaderView.setText(R.string.listTotalPhoneContactsZero);
                         break;
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index deab8ab..348abb9 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -72,7 +72,7 @@
                 // Regardless of the directory, we don't want anything returned,
                 // so let's just send a "nothing" query to the local directory.
                 loader.setUri(Contacts.CONTENT_URI);
-                loader.setProjection(ContactQuery.PROJECTION_CONTACT);
+                loader.setProjection(getProjection(false));
                 loader.setSelection("0");
             } else {
                 Builder builder = Contacts.CONTENT_FILTER_URI.buildUpon();
@@ -87,11 +87,11 @@
                         SNIPPET_ARGS);
                 builder.appendQueryParameter(SearchSnippetColumns.DEFERRED_SNIPPETING_KEY,"1");
                 loader.setUri(builder.build());
-                loader.setProjection(ContactQuery.FILTER_PROJECTION);
+                loader.setProjection(getProjection(true));
             }
         } else {
             configureUri(loader, directoryId, filter);
-            configureProjection(loader, directoryId, filter);
+            loader.setProjection(getProjection(false));
             configureSelection(loader, directoryId, filter);
         }
 
@@ -107,16 +107,12 @@
 
     protected void configureUri(CursorLoader loader, long directoryId, ContactListFilter filter) {
         Uri uri = Contacts.CONTENT_URI;
-        if (filter != null) {
-            if (filter.filterType == ContactListFilter.FILTER_TYPE_GROUP) {
-                uri = Data.CONTENT_URI;
-            } else if (filter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
-                String lookupKey = getSelectedContactLookupKey();
-                if (lookupKey != null) {
-                    uri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey);
-                } else {
-                    uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, getSelectedContactId());
-                }
+        if (filter != null && filter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
+            String lookupKey = getSelectedContactLookupKey();
+            if (lookupKey != null) {
+                uri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey);
+            } else {
+                uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, getSelectedContactId());
             }
         }
 
@@ -136,15 +132,6 @@
         loader.setUri(uri);
     }
 
-    protected void configureProjection(
-            CursorLoader loader, long directoryId, ContactListFilter filter) {
-        if (filter != null && filter.filterType == ContactListFilter.FILTER_TYPE_GROUP) {
-            loader.setProjection(ContactQuery.PROJECTION_DATA);
-        } else {
-            loader.setProjection(ContactQuery.PROJECTION_CONTACT);
-        }
-    }
-
     private void configureSelection(
             CursorLoader loader, long directoryId, ContactListFilter filter) {
         if (filter == null) {
@@ -203,13 +190,6 @@
                 selection.append(")");
                 break;
             }
-            case ContactListFilter.FILTER_TYPE_GROUP: {
-                selection.append(Data.MIMETYPE + "=?"
-                        + " AND " + GroupMembership.GROUP_ROW_ID + "=?");
-                selectionArgs.add(GroupMembership.CONTENT_ITEM_TYPE);
-                selectionArgs.add(String.valueOf(filter.groupId));
-                break;
-            }
         }
         loader.setSelection(selection.toString());
         loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
diff --git a/src/com/android/contacts/list/JoinContactListAdapter.java b/src/com/android/contacts/list/JoinContactListAdapter.java
index b81dd3b..bfe8c53 100644
--- a/src/com/android/contacts/list/JoinContactListAdapter.java
+++ b/src/com/android/contacts/list/JoinContactListAdapter.java
@@ -67,7 +67,7 @@
 
     @Override
     public void configureLoader(CursorLoader cursorLoader, long directoryId) {
-        JoinContactLoader loader = (JoinContactLoader)cursorLoader;
+        JoinContactLoader loader = (JoinContactLoader) cursorLoader;
 
         Builder builder = Contacts.CONTENT_URI.buildUpon();
         builder.appendEncodedPath(String.valueOf(mTargetContactId));
@@ -83,7 +83,7 @@
         loader.setSuggestionUri(builder.build());
 
         // TODO simplify projection
-        loader.setProjection(ContactQuery.PROJECTION_CONTACT);
+        loader.setProjection(getProjection(false));
         Uri allContactsUri = buildSectionIndexerUri(Contacts.CONTENT_URI).buildUpon()
                 .appendQueryParameter(
                         ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(Directory.DEFAULT))
@@ -189,13 +189,6 @@
         }
     }
 
-    public Cursor getShowAllContactsLabelCursor() {
-        MatrixCursor matrixCursor = new MatrixCursor(ContactQuery.PROJECTION_CONTACT);
-        Object[] row = new Object[ContactQuery.PROJECTION_CONTACT.length];
-        matrixCursor.addRow(row);
-        return matrixCursor;
-    }
-
     @Override
     public Uri getContactUri(int partitionIndex, Cursor cursor) {
         long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
diff --git a/src/com/android/contacts/list/PhoneNumberPickerFragment.java b/src/com/android/contacts/list/PhoneNumberPickerFragment.java
index 052c32f..c96956b 100644
--- a/src/com/android/contacts/list/PhoneNumberPickerFragment.java
+++ b/src/com/android/contacts/list/PhoneNumberPickerFragment.java
@@ -70,7 +70,6 @@
     public PhoneNumberPickerFragment() {
         setQuickContactEnabled(false);
         setPhotoLoaderEnabled(true);
-        setVisibleScrollbarEnabled(true);
         setSectionHeaderDisplayEnabled(true);
         setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DATA_SHORTCUT);
 
@@ -93,6 +92,8 @@
         mAccountFilterHeader = getView().findViewById(R.id.account_filter_header_container);
         mAccountFilterHeader.setOnClickListener(mFilterHeaderClickListener);
         updateFilterHeaderView();
+
+        setVisibleScrollbarEnabled(!isLegacyCompatibilityMode());
     }
 
     @Override
diff --git a/src/com/android/contacts/model/AccountType.java b/src/com/android/contacts/model/AccountType.java
index 23d39d3..22ea884 100644
--- a/src/com/android/contacts/model/AccountType.java
+++ b/src/com/android/contacts/model/AccountType.java
@@ -298,6 +298,9 @@
      * Add given {@link DataKind} to list of those provided by this source.
      */
     public DataKind addKind(DataKind kind) throws DefinitionException {
+        if (kind.mimeType == null) {
+            throw new DefinitionException("null is not a valid mime type");
+        }
         if (mMimeKinds.get(kind.mimeType) != null) {
             throw new DefinitionException(
                     "mime type '" + kind.mimeType + "' is already registered");
diff --git a/src/com/android/contacts/model/BaseAccountType.java b/src/com/android/contacts/model/BaseAccountType.java
index 109a7c5..cd113eb 100644
--- a/src/com/android/contacts/model/BaseAccountType.java
+++ b/src/com/android/contacts/model/BaseAccountType.java
@@ -497,6 +497,10 @@
                     + " mStringRes=" + mStringRes
                     + " mColumnName" + mColumnName;
         }
+
+        public String getColumnNameForTest() {
+            return mColumnName;
+        }
     }
 
     public static abstract class CommonInflater implements StringInflater {
@@ -699,8 +703,7 @@
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
             final int depth = parser.getDepth();
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT
-                    || depth != outerDepth + 1) {
+            if (type != XmlPullParser.START_TAG || depth != outerDepth + 1) {
                 continue; // Not direct child tag
             }
 
@@ -845,8 +848,7 @@
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                     && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                 final int depth = parser.getDepth();
-                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT
-                        || depth != outerDepth + 1) {
+                if (type != XmlPullParser.START_TAG || depth != outerDepth + 1) {
                     continue; // Not direct child tag
                 }
 
diff --git a/src/com/android/contacts/model/ExternalAccountType.java b/src/com/android/contacts/model/ExternalAccountType.java
index 1870992..f36e9e0 100644
--- a/src/com/android/contacts/model/ExternalAccountType.java
+++ b/src/com/android/contacts/model/ExternalAccountType.java
@@ -140,11 +140,16 @@
                 addDataKindPhoto(context);
             }
         } catch (DefinitionException e) {
-            String message = "Problem reading XML";
+            final StringBuilder error = new StringBuilder();
+            error.append("Problem reading XML");
             if (needLineNumberInErrorLog && (parser != null)) {
-                message = message + " in line " + parser.getLineNumber();
+                error.append(" in line ");
+                error.append(parser.getLineNumber());
             }
-            Log.e(TAG, message, e);
+            error.append(" for external package ");
+            error.append(resPackageName);
+
+            Log.e(TAG, error.toString(), e);
             return;
         } finally {
             if (parser != null) {
@@ -341,10 +346,15 @@
             }
 
             // Parse all children kinds
-            final int depth = parser.getDepth();
-            while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
+            final int startDepth = parser.getDepth();
+            while (((type = parser.next()) != XmlPullParser.END_TAG
+                        || parser.getDepth() > startDepth)
                     && type != XmlPullParser.END_DOCUMENT) {
 
+                if (type != XmlPullParser.START_TAG || parser.getDepth() != startDepth + 1) {
+                    continue; // Not a direct child tag
+                }
+
                 String tag = parser.getName();
                 if (TAG_EDIT_SCHEMA.equals(tag)) {
                     mHasEditSchema = true;
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index 2ce15ff..593c4b2 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -209,6 +209,9 @@
             // TODO: Rotate between all the stream items?
             StreamItemEntry streamItem = streamItems.get(0);
             CharSequence status = HtmlUtils.fromHtml(context, streamItem.getText());
+            if (status == null) {
+              status = "";
+            }
             if (status.length() <= SHORT_SNIPPET_LENGTH) {
                 sb.append("\n");
             } else {
diff --git a/src/com/android/contacts/util/AccountPromptUtils.java b/src/com/android/contacts/util/AccountPromptUtils.java
index 58865d0..111c52e 100644
--- a/src/com/android/contacts/util/AccountPromptUtils.java
+++ b/src/com/android/contacts/util/AccountPromptUtils.java
@@ -22,6 +22,7 @@
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerCallback;
 import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorDescription;
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.app.Activity;
@@ -57,10 +58,23 @@
 
     /**
      * Returns true if the "no account" prompt should be shown
-     * (according to {@link SharedPreferences}), otherwise return false.
+     * (according to {@link SharedPreferences}), otherwise return false. Since this prompt is
+     * Google-specific for the time being, this method will also return false if the Google
+     * account type is not available from the {@link AccountManager}.
      */
     public static boolean shouldShowAccountPrompt(Context context) {
-        return getSharedPreferences(context).getBoolean(KEY_SHOW_ACCOUNT_PROMPT, true);
+        // TODO: Remove the filtering of account types once there is an API in
+        // {@link AccountManager} to show a similar account prompt
+        // (see {@link AccountManager#addAccount()} in {@link #launchAccountPrompt()}
+        // for any type of account. Bug: 5375902
+        AuthenticatorDescription[] allTypes =
+                AccountManager.get(context).getAuthenticatorTypes();
+        for (AuthenticatorDescription authenticatorType : allTypes) {
+            if (GoogleAccountType.ACCOUNT_TYPE.equals(authenticatorType.type)) {
+                return getSharedPreferences(context).getBoolean(KEY_SHOW_ACCOUNT_PROMPT, true);
+            }
+        }
+        return false;
     }
 
     /**
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
index 9a84f7c..7aecf08 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
@@ -37,7 +37,6 @@
 import android.view.View;
 import android.widget.SeekBar;
 
-import java.io.IOException;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
@@ -101,6 +100,7 @@
         CHECK_FOR_CONTENT,
         CHECK_CONTENT_AFTER_CHANGE,
         PREPARE_MEDIA_PLAYER,
+        RESET_PREPARE_START_MEDIA_PLAYER,
     }
 
     /** Update rate for the slider, 30fps. */
@@ -169,6 +169,7 @@
      */
     private FetchResultHandler mFetchResultHandler;
     private PowerManager.WakeLock mWakeLock;
+    private AsyncTask<Void, ?, ?> mPrepareTask;
 
     public VoicemailPlaybackPresenter(PlaybackView view, MediaPlayerProxy player,
             Uri voicemailUri, ScheduledExecutorService executorService,
@@ -431,29 +432,49 @@
         }
     }
 
-    private void resetPrepareStartPlaying(int clipPositionInMillis) {
-        try {
-            mPlayer.reset();
-            mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri);
-            mPlayer.setAudioStreamType(PLAYBACK_STREAM);
-            mPlayer.prepare();
-            mDuration.set(mPlayer.getDuration());
-            int startPosition = constrain(clipPositionInMillis, 0, mDuration.get());
-            mView.setClipPosition(startPosition, mDuration.get());
-            mPlayer.seekTo(startPosition);
-            mPlayer.start();
-            mView.playbackStarted();
-            if (!mWakeLock.isHeld()) {
-                mWakeLock.acquire();
-            }
-            // Only enable if we are not currently using the speaker phone.
-            if (!mView.isSpeakerPhoneOn()) {
-                mView.enableProximitySensor();
-            }
-            mPositionUpdater.startUpdating(startPosition, mDuration.get());
-        } catch (IOException e) {
-            handleError(e);
+    private void resetPrepareStartPlaying(final int clipPositionInMillis) {
+        if (mPrepareTask != null) {
+            mPrepareTask.cancel(false);
         }
+        mPrepareTask = mAsyncTaskExecutor.submit(Tasks.RESET_PREPARE_START_MEDIA_PLAYER,
+                new AsyncTask<Void, Void, Exception>() {
+                    @Override
+                    public Exception doInBackground(Void... params) {
+                        try {
+                            mPlayer.reset();
+                            mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri);
+                            mPlayer.setAudioStreamType(PLAYBACK_STREAM);
+                            mPlayer.prepare();
+                            return null;
+                        } catch (Exception e) {
+                            return e;
+                        }
+                    }
+
+                    @Override
+                    public void onPostExecute(Exception exception) {
+                        mPrepareTask = null;
+                        if (exception == null) {
+                            mDuration.set(mPlayer.getDuration());
+                            int startPosition =
+                                    constrain(clipPositionInMillis, 0, mDuration.get());
+                            mView.setClipPosition(startPosition, mDuration.get());
+                            mPlayer.seekTo(startPosition);
+                            mPlayer.start();
+                            mView.playbackStarted();
+                            if (!mWakeLock.isHeld()) {
+                                mWakeLock.acquire();
+                            }
+                            // Only enable if we are not currently using the speaker phone.
+                            if (!mView.isSpeakerPhoneOn()) {
+                                mView.enableProximitySensor();
+                            }
+                            mPositionUpdater.startUpdating(startPosition, mDuration.get());
+                        } else {
+                            handleError(exception);
+                        }
+                    }
+                });
     }
 
     private void handleError(Exception e) {
@@ -599,6 +620,9 @@
         if (mPlayer.isPlaying()) {
             stopPlaybackAtPosition(mPlayer.getCurrentPosition(), mDuration.get());
         }
+        if (mPrepareTask != null) {
+            mPrepareTask.cancel(false);
+        }
         if (mWakeLock.isHeld()) {
             mWakeLock.release();
         }
diff --git a/tests/res/xml/contacts_readonly.xml b/tests/res/xml/contacts_readonly.xml
new file mode 100644
index 0000000..df8d9c0
--- /dev/null
+++ b/tests/res/xml/contacts_readonly.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2011, 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.
+ */
+-->
+
+<!--
+    Contacts.xml without EditSchema.
+-->
+
+<ContactsAccountType
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    >
+        <ContactsDataKind
+                android:icon="@drawable/android"
+                android:mimeType="vnd.android.cursor.item/a.b.c"
+                android:summaryColumn="data1"
+                android:detailColumn="data2"
+                android:detailSocialSummary="true"
+                >
+        </ContactsDataKind>
+        <ContactsDataKind
+                android:icon="@drawable/default_icon"
+                android:mimeType="vnd.android.cursor.item/d.e.f"
+                android:summaryColumn="data3"
+                android:detailColumn="data4"
+                android:detailSocialSummary="false"
+                >
+        </ContactsDataKind>
+        <ContactsDataKind
+                android:icon="@drawable/android"
+                android:mimeType="vnd.android.cursor.item/xyz"
+                android:summaryColumn="data5"
+                android:detailColumn="data6"
+                android:detailSocialSummary="true"
+                >
+        </ContactsDataKind>
+</ContactsAccountType>
diff --git a/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java b/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java
index a020c8a..27c645a 100644
--- a/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java
+++ b/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java
@@ -19,8 +19,6 @@
 import com.android.contacts.tests.R;
 
 import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.XmlResourceParser;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Event;
 import android.provider.ContactsContract.CommonDataKinds.Im;
@@ -156,6 +154,55 @@
         assertEquals(expectInitialized, type.isInitialized());
     }
 
+    /**
+     * Initialize with "contacts_readonly.xml" and see if all data kinds are correctly registered.
+     */
+    public void testReadOnlyDefinition() {
+        final ExternalAccountType type = new ExternalAccountType(getContext(),
+                getTestContext().getPackageName(), false,
+                getTestContext().getResources().getXml(R.xml.contacts_readonly)
+                );
+        assertTrue(type.isInitialized());
+
+        // Shouldn't have a "null" mimetype.
+        assertTrue(type.getKindForMimetype(null) == null);
+
+        // 3 kinds are defined in XML and 4 are added by default.
+        assertEquals(4 + 3, type.getSortedDataKinds().size());
+
+        // Check for the default kinds.
+        assertNotNull(type.getKindForMimetype(StructuredName.CONTENT_ITEM_TYPE));
+        assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME));
+        assertNotNull(type.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME));
+        assertNotNull(type.getKindForMimetype(Photo.CONTENT_ITEM_TYPE));
+
+        // Check for type specific kinds.
+        DataKind kind = type.getKindForMimetype("vnd.android.cursor.item/a.b.c");
+        assertNotNull(kind);
+        // No check for icon -- we actually just ignore it.
+        assertEquals("data1", ((BaseAccountType.SimpleInflater) kind.actionHeader)
+                .getColumnNameForTest());
+        assertEquals("data2", ((BaseAccountType.SimpleInflater) kind.actionBody)
+                .getColumnNameForTest());
+        assertEquals(true, kind.actionBodySocial);
+
+        kind = type.getKindForMimetype("vnd.android.cursor.item/d.e.f");
+        assertNotNull(kind);
+        assertEquals("data3", ((BaseAccountType.SimpleInflater) kind.actionHeader)
+                .getColumnNameForTest());
+        assertEquals("data4", ((BaseAccountType.SimpleInflater) kind.actionBody)
+                .getColumnNameForTest());
+        assertEquals(false, kind.actionBodySocial);
+
+        kind = type.getKindForMimetype("vnd.android.cursor.item/xyz");
+        assertNotNull(kind);
+        assertEquals("data5", ((BaseAccountType.SimpleInflater) kind.actionHeader)
+                .getColumnNameForTest());
+        assertEquals("data6", ((BaseAccountType.SimpleInflater) kind.actionBody)
+                .getColumnNameForTest());
+        assertEquals(true, kind.actionBodySocial);
+    }
+
     private static void assertsDataKindEquals(List<DataKind> expectedKinds,
             List<DataKind> actualKinds) {
         final int count = Math.max(actualKinds.size(), expectedKinds.size());
diff --git a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
index 4d24f54..555b339 100644
--- a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
+++ b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
@@ -16,10 +16,10 @@
 
 package com.android.contacts.tests.allintents;
 
-import com.android.contacts.model.AccountWithDataSet;
 import com.android.contacts.tests.R;
 import com.google.android.collect.Lists;
 
+import android.accounts.Account;
 import android.app.ListActivity;
 import android.app.SearchManager;
 import android.content.ComponentName;
@@ -51,6 +51,8 @@
 /**
  * An activity that provides access to various modes of the contacts application.
  * Useful for manual and scripted tests.
+ * <p>
+ * Note: this class cannot depend (directly on indirectly) on anything outside the test package.
  */
 @SuppressWarnings("deprecation")
 public class AllIntentsActivity extends ListActivity
@@ -631,12 +633,12 @@
     }
 
     @Override
-    public void onAccountChosen(AccountWithDataSet account, int tag) {
+    public void onAccountChosen(Account account, String dataSet, int tag) {
         switch (ContactsIntent.get(tag)) {
             case EDIT_NEW_CONTACT_FOR_ACCOUNT: {
                 final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
                 intent.putExtra(Insert.ACCOUNT, account);
-                intent.putExtra(Insert.DATA_SET, account.dataSet);
+                intent.putExtra(Insert.DATA_SET, dataSet);
                 startActivity(intent);
                 break;
             }
@@ -644,7 +646,7 @@
                 final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
 
                 intent.putExtra(Insert.ACCOUNT, account);
-                intent.putExtra(Insert.DATA_SET, account.dataSet);
+                intent.putExtra(Insert.DATA_SET, dataSet);
                 putDataExtra(intent);
 
                 startActivity(intent);
diff --git a/tests/src/com/android/contacts/tests/allintents/SelectAccountDialogFragment.java b/tests/src/com/android/contacts/tests/allintents/SelectAccountDialogFragment.java
index c261553..f0c2df4 100644
--- a/tests/src/com/android/contacts/tests/allintents/SelectAccountDialogFragment.java
+++ b/tests/src/com/android/contacts/tests/allintents/SelectAccountDialogFragment.java
@@ -16,9 +16,8 @@
 
 package com.android.contacts.tests.allintents;
 
-import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
-
+import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
@@ -30,8 +29,6 @@
 import android.widget.ArrayAdapter;
 import android.widget.TextView;
 
-import java.util.List;
-
 /**
  * Shows a dialog asking the user which account to chose.
  * The result is passed back to the owning Activity
@@ -46,14 +43,14 @@
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         final Bundle parameters = getArguments();
 
-        final List<AccountWithDataSet> accounts =
-                AccountTypeManager.getInstance(getActivity()).getAccounts(false);
+        AccountManager accountManager = AccountManager.get(getActivity());
+        Account[] accounts = accountManager.getAccounts();
 
         final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
         final LayoutInflater inflater = LayoutInflater.from(builder.getContext());
 
-        final ArrayAdapter<AccountWithDataSet> accountAdapter =
-                new ArrayAdapter<AccountWithDataSet>(builder.getContext(),
+        final ArrayAdapter<Account> accountAdapter =
+                new ArrayAdapter<Account>(builder.getContext(),
                         android.R.layout.simple_list_item_2, accounts) {
             @Override
             public View getView(int position, View convertView, ViewGroup parent) {
@@ -64,7 +61,7 @@
                 final TextView text1 = (TextView)resultView.findViewById(android.R.id.text1);
                 final TextView text2 = (TextView)resultView.findViewById(android.R.id.text2);
 
-                final AccountWithDataSet account = getItem(position);
+                final Account account = getItem(position);
 
                 text1.setText("Name: " + account.name);
                 text2.setText("Type: " + account.type);
@@ -79,8 +76,10 @@
             public void onClick(DialogInterface dialog, int which) {
                 dialog.dismiss();
 
+                // We currently do not pass the dataSet argument to the listener. To do so, we would
+                // have to determine the dataSet as it is done in AccountTypeManager.
                 ((Listener) getActivity()).onAccountChosen(accountAdapter.getItem(which),
-                        parameters.getInt(EXTRA_TAG));
+                        null, parameters.getInt(EXTRA_TAG));
             }
         };
 
@@ -97,6 +96,6 @@
     }
 
     public interface Listener {
-        void onAccountChosen(AccountWithDataSet account, int tag);
+        void onAccountChosen(Account account, String dataSet, int tag);
     }
 }