Merge "Implemented all missing functionality from Editor-Fragment (minus Statehandling)"
diff --git a/src/com/android/contacts/MultiplePhonePickerActivity.java b/src/com/android/contacts/MultiplePhonePickerActivity.java
index b554166..6b066a7 100644
--- a/src/com/android/contacts/MultiplePhonePickerActivity.java
+++ b/src/com/android/contacts/MultiplePhonePickerActivity.java
@@ -16,164 +16,71 @@
 
 package com.android.contacts;
 
-import com.android.contacts.list.MultiplePhoneExtraAdapter;
-import com.android.contacts.list.MultiplePhonePickerAdapter;
-import com.android.contacts.list.MultiplePhonePickerItemView;
-import com.android.contacts.list.MultiplePhoneSelection;
+import com.android.contacts.list.MultiplePhonePickerFragment;
+import com.android.contacts.list.OnMultiplePhoneNumberPickerActionListener;
 
-import android.app.ProgressDialog;
-import android.content.ContentResolver;
-import android.content.ContentUris;
+import android.app.Activity;
+import android.app.FragmentTransaction;
 import android.content.Intent;
-import android.database.Cursor;
-import android.database.MatrixCursor;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.Parcelable;
 import android.provider.ContactsContract.Intents;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.text.TextUtils;
-import android.util.SparseIntArray;
 import android.view.Menu;
 import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewStub;
-import android.view.View.OnClickListener;
-import android.view.animation.AnimationUtils;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.ListView;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
 
 /**
  * Displays of phone numbers and allows selection of multiple numbers.
  */
-public class MultiplePhonePickerActivity extends ContactsListActivity implements OnClickListener {
-    /**
-     * User selected phone number and id in MODE_PICK_MULTIPLE_PHONES mode.
-     */
-    public final MultiplePhoneSelection mUserSelection = new MultiplePhoneSelection(this);
-
-    /**
-     * The adapter for the phone numbers, used in MODE_PICK_MULTIPLE_PHONES mode.
-     */
-    public final MultiplePhoneExtraAdapter mPhoneNumberAdapter =
-            new MultiplePhoneExtraAdapter(this, this, mUserSelection);
-
-    private static int[] CHIP_COLOR_ARRAY = {
-        R.drawable.appointment_indicator_leftside_1,
-        R.drawable.appointment_indicator_leftside_2,
-        R.drawable.appointment_indicator_leftside_3,
-        R.drawable.appointment_indicator_leftside_4,
-        R.drawable.appointment_indicator_leftside_5,
-        R.drawable.appointment_indicator_leftside_6,
-        R.drawable.appointment_indicator_leftside_7,
-        R.drawable.appointment_indicator_leftside_8,
-        R.drawable.appointment_indicator_leftside_9,
-        R.drawable.appointment_indicator_leftside_10,
-        R.drawable.appointment_indicator_leftside_11,
-        R.drawable.appointment_indicator_leftside_12,
-        R.drawable.appointment_indicator_leftside_13,
-        R.drawable.appointment_indicator_leftside_14,
-        R.drawable.appointment_indicator_leftside_15,
-        R.drawable.appointment_indicator_leftside_16,
-        R.drawable.appointment_indicator_leftside_17,
-        R.drawable.appointment_indicator_leftside_18,
-        R.drawable.appointment_indicator_leftside_19,
-        R.drawable.appointment_indicator_leftside_20,
-        R.drawable.appointment_indicator_leftside_21,
-    };
-
-    /**
-     * This is the map from contact to color index.
-     * A colored chip in MODE_PICK_MULTIPLE_PHONES mode is used to indicate the number of phone
-     * numbers belong to one contact
-     */
-    SparseIntArray mContactColor = new SparseIntArray();
-
-    /**
-     * UI control of action panel in MODE_PICK_MULTIPLE_PHONES mode.
-     */
-    private View mFooterView;
+public class MultiplePhonePickerActivity extends Activity {
 
     /**
      * Display only selected recipients or not in MODE_PICK_MULTIPLE_PHONES mode
      */
-    public boolean mShowSelectedOnly = false;
+    private boolean mShowSelectedOnly = false;
 
-    public OnClickListener mCheckBoxClickerListener = new OnClickListener () {
-        public void onClick(View v) {
-            final MultiplePhonePickerItemView itemView =
-                    (MultiplePhonePickerItemView) v.getParent();
-            if (itemView.phoneId != MultiplePhoneExtraAdapter.INVALID_PHONE_ID) {
-                mUserSelection.setPhoneSelected(itemView.phoneId, ((CheckBox) v).isChecked());
-            } else {
-                mUserSelection.setPhoneSelected(itemView.phoneNumber,
-                        ((CheckBox) v).isChecked());
+    private MultiplePhonePickerFragment mListFragment;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mListFragment = new MultiplePhonePickerFragment();
+        mListFragment.setOnMultiplePhoneNumberPickerActionListener(
+                new OnMultiplePhoneNumberPickerActionListener() {
+
+            public void onPhoneNumbersSelectedAction(Uri[] dataUris) {
+                returnActivityResult(dataUris);
             }
-            updateWidgets(true);
-        }
-    };
 
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        initMultiPicker(getIntent());
+            public void onFinishAction() {
+                finish();
+            }
+        });
+
+        Parcelable[] extras = getIntent().getParcelableArrayExtra(Intents.EXTRA_PHONE_URIS);
+        mListFragment.setSelectedUris(extras);
+        FragmentTransaction transaction = openFragmentTransaction();
+        transaction.add(mListFragment, android.R.id.content);
+        transaction.commit();
     }
 
     @Override
-    protected void onResume() {
-        super.onResume();
-
-        // TODO move this to onAttach of the corresponding fragment
-        ListView listView = (ListView)findViewById(android.R.id.list);
-        ((MultiplePhonePickerAdapter)listView.getAdapter()).setExtraAdapter(mPhoneNumberAdapter);
-        ViewStub stub = (ViewStub)findViewById(R.id.footer_stub);
-        if (stub != null) {
-            View stubView = stub.inflate();
-            mFooterView = stubView.findViewById(R.id.footer);
-            mFooterView.setVisibility(View.GONE);
-            Button doneButton = (Button) stubView.findViewById(R.id.done);
-            doneButton.setOnClickListener(this);
-            Button revertButton = (Button) stubView.findViewById(R.id.revert);
-            revertButton.setOnClickListener(this);
-        }
-    }
-
-    public void onClick(View v) {
-        int id = v.getId();
-        switch (id) {
-            case R.id.done:
-                setMultiPickerResult();
-                finish();
-                break;
-            case R.id.revert:
-                finish();
-                break;
-        }
+    public void onBackPressed() {
+        returnActivityResult(mListFragment.getSelectedUris());
+        super.onBackPressed();
     }
 
     @Override
     protected void onSaveInstanceState(Bundle icicle) {
         super.onSaveInstanceState(icicle);
-        ListView listView = (ListView)findViewById(android.R.id.list);
-        if (listView != null) {
-            if (mUserSelection != null) {
-                mUserSelection.saveInstanceState(icicle);
-            }
-        }
+        mListFragment.onSaveInstanceState(icicle);
     }
 
     @Override
     protected void onRestoreInstanceState(Bundle icicle) {
         super.onRestoreInstanceState(icicle);
-        // Retrieve list state. This will be applied after the QueryHandler has run
-        mUserSelection.restoreInstanceState(icicle);
+        mListFragment.onRestoreInstanceState(icicle);
     }
 
     @Override
@@ -185,6 +92,7 @@
         return true;
     }
 
+    /*
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
         if (mShowSelectedOnly) {
@@ -234,7 +142,7 @@
         }
         return super.onOptionsItemSelected(item);
     }
-
+*/
     @Override
     public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
             boolean globalSearch) {
@@ -242,203 +150,72 @@
 //        if (mProviderStatus != ProviderStatus.STATUS_NORMAL) {
 //            return;
 //        }
-
-        if (globalSearch) {
-            super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
-        } else {
-            if (!mSearchMode && (mMode & MODE_MASK_NO_FILTER) == 0) {
-                if ((mMode & MODE_MASK_PICKER) != 0) {
-                    Bundle extras = getIntent().getExtras();
-                    if (extras == null) {
-                        extras = new Bundle();
-                    }
-                    mUserSelection.fillSelectionForSearchMode(extras);
-                    ContactsSearchManager.startSearchForResult(this, initialQuery,
-                            SUBACTIVITY_FILTER, extras);
-                } else {
-                    ContactsSearchManager.startSearch(this, initialQuery);
-                }
-            }
-        }
+//
+//        if (globalSearch) {
+//            super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+//        } else {
+//            if (!mSearchMode && (mMode & MODE_MASK_NO_FILTER) == 0) {
+//                if ((mMode & MODE_MASK_PICKER) != 0) {
+//                    Bundle extras = getIntent().getExtras();
+//                    if (extras == null) {
+//                        extras = new Bundle();
+//                    }
+//                    mUserSelection.fillSelectionForSearchMode(extras);
+//                    ContactsSearchManager.startSearchForResult(this, initialQuery,
+//                            SUBACTIVITY_FILTER, extras);
+//                } else {
+//                    ContactsSearchManager.startSearch(this, initialQuery);
+//                }
+//            }
+//        }
     }
 
-    @Override
-    public void onBackPressed() {
-        setMultiPickerResult();
-        super.onBackPressed();
-    }
+//    @Override
+//    protected void startQuery(Uri uri, String[] projection) {
+//        // Filter unknown phone numbers first.
+//        mPhoneNumberAdapter.doFilter(null, mShowSelectedOnly);
+//        if (mShowSelectedOnly) {
+//            StringBuilder idSetBuilder = new StringBuilder();
+//            Iterator<Long> itr = mUserSelection.getSelectedPhonIds();
+//            if (itr.hasNext()) {
+//                idSetBuilder.append(Long.toString(itr.next()));
+//            }
+//            while (itr.hasNext()) {
+//                idSetBuilder.append(',');
+//                idSetBuilder.append(Long.toString(itr.next()));
+//            }
+//            String whereClause = Phone._ID + " IN (" + idSetBuilder.toString() + ")";
+//            mQueryHandler.startQuery(QUERY_TOKEN, null, uri, projection, whereClause, null,
+//                    getSortOrder(projection));
+//        } else {
+//            mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
+//                    projection, CLAUSE_ONLY_VISIBLE, null, getSortOrder(projection));
+//        }
+//    }
 
-    @Override
-    protected void startQuery(Uri uri, String[] projection) {
-        // Filter unknown phone numbers first.
-        mPhoneNumberAdapter.doFilter(null, mShowSelectedOnly);
-        if (mShowSelectedOnly) {
-            StringBuilder idSetBuilder = new StringBuilder();
-            Iterator<Long> itr = mUserSelection.getSelectedPhonIds();
-            if (itr.hasNext()) {
-                idSetBuilder.append(Long.toString(itr.next()));
-            }
-            while (itr.hasNext()) {
-                idSetBuilder.append(',');
-                idSetBuilder.append(Long.toString(itr.next()));
-            }
-            String whereClause = Phone._ID + " IN (" + idSetBuilder.toString() + ")";
-            mQueryHandler.startQuery(QUERY_TOKEN, null, uri, projection, whereClause, null,
-                    getSortOrder(projection));
-        } else {
-            mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
-                    projection, CLAUSE_ONLY_VISIBLE, null, getSortOrder(projection));
-        }
-    }
+//    @Override
+//    public Cursor doFilter(String filter) {
+//        String[] projection = getProjectionForQuery();
+//        if (mSearchMode && TextUtils.isEmpty(mListFragment.getQueryString())) {
+//            return new MatrixCursor(projection);
+//        }
+//
+//        final ContentResolver resolver = getContentResolver();
+//        // Filter phone numbers as well.
+//        mPhoneNumberAdapter.doFilter(filter, mShowSelectedOnly);
+//
+//        Uri uri = getUriToQuery();
+//        if (!TextUtils.isEmpty(filter)) {
+//            uri = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(filter));
+//        }
+//        return resolver.query(uri, projection, CLAUSE_ONLY_VISIBLE, null, getSortOrder(projection));
+//    }
 
-    @Override
-    public Cursor doFilter(String filter) {
-        String[] projection = getProjectionForQuery();
-        if (mSearchMode && TextUtils.isEmpty(mListFragment.getQueryString())) {
-            return new MatrixCursor(projection);
-        }
-
-        final ContentResolver resolver = getContentResolver();
-        // Filter phone numbers as well.
-        mPhoneNumberAdapter.doFilter(filter, mShowSelectedOnly);
-
-        Uri uri = getUriToQuery();
-        if (!TextUtils.isEmpty(filter)) {
-            uri = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(filter));
-        }
-        return resolver.query(uri, projection, CLAUSE_ONLY_VISIBLE, null, getSortOrder(projection));
-    }
-
-    private void initMultiPicker(final Intent intent) {
-        final Handler handler = new Handler();
-        // TODO : Shall we still show the progressDialog in search mode.
-        final ProgressDialog progressDialog = new ProgressDialog(this);
-        progressDialog.setMessage(getText(R.string.adding_recipients));
-        progressDialog.setIndeterminate(true);
-        progressDialog.setCancelable(false);
-
-        final Runnable showProgress = new Runnable() {
-            public void run() {
-                progressDialog.show();
-            }
-        };
-        handler.postDelayed(showProgress, 1);
-
-        new Thread(new Runnable() {
-            public void run() {
-                try {
-                    loadSelectionFromIntent(intent);
-                } finally {
-                    handler.removeCallbacks(showProgress);
-                    progressDialog.dismiss();
-                }
-                final Runnable populateWorker = new Runnable() {
-                    public void run() {
-                        if (mAdapter != null) {
-                            mAdapter.notifyDataSetChanged();
-                        }
-                        updateWidgets(false);
-                    }
-                };
-                handler.post(populateWorker);
-            }
-        }).start();
-    }
-
-    private void getPhoneNumbersOrIdsFromURIs(final Parcelable[] uris,
-            final List<String> phoneNumbers, final List<Long> phoneIds) {
-        if (uris != null) {
-            for (Parcelable paracelable : uris) {
-                Uri uri = (Uri) paracelable;
-                if (uri == null) continue;
-                String scheme = uri.getScheme();
-                if (phoneNumbers != null && "tel".equals(scheme)) {
-                    phoneNumbers.add(uri.getSchemeSpecificPart());
-                } else if (phoneIds != null && "content".equals(scheme)) {
-                    phoneIds.add(ContentUris.parseId(uri));
-                }
-            }
-        }
-    }
-
-    private void loadSelectionFromIntent(Intent intent) {
-        Parcelable[] uris = intent.getParcelableArrayExtra(Intents.EXTRA_PHONE_URIS);
-        ArrayList<String> phoneNumbers = new ArrayList<String>();
-        ArrayList<Long> phoneIds = new ArrayList<Long>();
-        ArrayList<String> selectedPhoneNumbers = null;
-        if (mSearchMode) {
-            // All selection will be read from EXTRA_SELECTION
-            getPhoneNumbersOrIdsFromURIs(uris, phoneNumbers, null);
-            uris = intent.getParcelableArrayExtra(MultiplePhoneSelection.EXTRA_SELECTION);
-            if (uris != null) {
-                selectedPhoneNumbers = new ArrayList<String>();
-                getPhoneNumbersOrIdsFromURIs(uris, selectedPhoneNumbers, phoneIds);
-            }
-        } else {
-            getPhoneNumbersOrIdsFromURIs(uris, phoneNumbers, phoneIds);
-            selectedPhoneNumbers = phoneNumbers;
-        }
-        mPhoneNumberAdapter.setPhoneNumbers(phoneNumbers);
-        mUserSelection.setSelection(selectedPhoneNumbers, phoneIds);
-    }
-
-    private void setMultiPickerResult() {
-        setResult(RESULT_OK, mUserSelection.createSelectionIntent());
-    }
-
-    /**
-     * Go through the cursor and assign the chip color to contact who has more than one phone
-     * numbers.
-     * Assume the cursor is sorted by CONTACT_ID.
-     */
-    public void updateChipColor(Cursor cursor) {
-        if (cursor == null || cursor.getCount() == 0) {
-            return;
-        }
-        mContactColor.clear();
-        int backupPos = cursor.getPosition();
-        cursor.moveToFirst();
-        int color = 0;
-        long prevContactId = cursor.getLong(PHONE_CONTACT_ID_COLUMN_INDEX);
-        while (cursor.moveToNext()) {
-            long contactId = cursor.getLong(PHONE_CONTACT_ID_COLUMN_INDEX);
-            if (prevContactId == contactId) {
-                if (mContactColor.indexOfKey(Long.valueOf(contactId).hashCode()) < 0) {
-                    mContactColor.put(Long.valueOf(contactId).hashCode(), CHIP_COLOR_ARRAY[color]);
-                    color++;
-                    if (color >= CHIP_COLOR_ARRAY.length) {
-                        color = 0;
-                    }
-                }
-            }
-            prevContactId = contactId;
-        }
-        cursor.moveToPosition(backupPos);
-    }
-
-    /**
-     * Get assigned chip color resource id for a given contact, 0 is returned if there is no mapped
-     * resource.
-     */
-    public int getChipColor(long contactId) {
-        return mContactColor.get(Long.valueOf(contactId).hashCode());
-    }
-
-    private void updateWidgets(boolean changed) {
-        int selected = mUserSelection.selectedCount();
-
-        if (selected >= 1) {
-            final String format =
-                getResources().getQuantityString(R.plurals.multiple_picker_title, selected);
-            setTitle(String.format(format, selected));
-        } else {
-            setTitle(getString(R.string.contactsList));
-        }
-
-        if (changed && mFooterView.getVisibility() == View.GONE) {
-            mFooterView.setVisibility(View.VISIBLE);
-            mFooterView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.footer_appear));
-        }
+    public void returnActivityResult(Uri[] dataUris) {
+        Intent intent = new Intent();
+        intent.putExtra(Intents.EXTRA_PHONE_URIS, dataUris);
+        setResult(RESULT_OK, intent);
+        finish();
     }
 
     private void checkAll(boolean checked) {
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index dd9ca08..28444a4 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -188,9 +188,10 @@
         mLine4Height = 0;
 
         // Obtain the natural dimensions of the name text (we only care about height)
-        mNameTextView.measure(0, 0);
-
-        mLine1Height = mNameTextView.getMeasuredHeight();
+        if (isVisible(mNameTextView)) {
+            mNameTextView.measure(0, 0);
+            mLine1Height = mNameTextView.getMeasuredHeight();
+        }
 
         if (isVisible(mPhoneticNameTextView)) {
             mPhoneticNameTextView.measure(0, 0);
@@ -288,10 +289,12 @@
         int totalTextHeight = mLine1Height + mLine2Height + mLine3Height + mLine4Height;
         int textTopBound = (bottomBound + topBound - totalTextHeight) / 2;
 
-        mNameTextView.layout(leftBound,
-                textTopBound,
-                rightBound,
-                textTopBound + mLine1Height);
+        if (isVisible(mNameTextView)) {
+            mNameTextView.layout(leftBound,
+                    textTopBound,
+                    rightBound,
+                    textTopBound + mLine1Height);
+        }
 
         int dataLeftBound = leftBound;
         if (isVisible(mPhoneticNameTextView)) {
diff --git a/src/com/android/contacts/list/JoinContactListAdapter.java b/src/com/android/contacts/list/JoinContactListAdapter.java
index 26c2e22..614e4e5 100644
--- a/src/com/android/contacts/list/JoinContactListAdapter.java
+++ b/src/com/android/contacts/list/JoinContactListAdapter.java
@@ -151,13 +151,10 @@
             cursor.moveToPosition(position);
         }
 
-        boolean newView;
         View v;
         if (convertView == null || convertView.getTag() == null) {
-            newView = true;
             v = newView(getContext(), cursor, parent);
         } else {
-            newView = false;
             v = convertView;
         }
         bindView(position, v, cursor, showingSuggestion);
diff --git a/src/com/android/contacts/list/MultiplePhoneExtraAdapter.java b/src/com/android/contacts/list/MultiplePhoneExtraAdapter.java
deleted file mode 100644
index 66548db..0000000
--- a/src/com/android/contacts/list/MultiplePhoneExtraAdapter.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * 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.list;
-
-import com.android.contacts.MultiplePhonePickerActivity;
-import com.android.contacts.R;
-
-import android.content.Context;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.CheckBox;
-import android.widget.TextView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class is the adapter for the phone numbers which may not be found in the contacts. It is
- * called in ContactItemListAdapter in MODE_PICK_MULTIPLE_PHONES mode and shouldn't be a adapter
- * for any View due to the missing implementation of getItem and getItemId.
- */
-public class MultiplePhoneExtraAdapter extends BaseAdapter {
-
-    private final MultiplePhonePickerActivity mMultiplePhonePickerActivity;
-
-    public static final long INVALID_PHONE_ID = -1;
-
-    /** The initial phone numbers */
-    private List<String> mPhoneNumbers;
-
-    /** The phone numbers after the filtering */
-    private ArrayList<String> mFilteredPhoneNumbers = new ArrayList<String>();
-
-    private final Context mContext;
-
-    private final MultiplePhoneSelection mSelection;
-
-    public MultiplePhoneExtraAdapter(MultiplePhonePickerActivity multiplePhonePickerActivity,
-            Context context, MultiplePhoneSelection selection) {
-        mContext = context;
-        mMultiplePhonePickerActivity = multiplePhonePickerActivity;
-        mSelection = selection;
-    }
-
-    public void setPhoneNumbers(ArrayList<String> phoneNumbers) {
-        if (phoneNumbers != null) {
-            mFilteredPhoneNumbers.addAll(phoneNumbers);
-            mPhoneNumbers = phoneNumbers;
-        } else {
-            mPhoneNumbers = new ArrayList<String>();
-        }
-    }
-
-    public int getCount() {
-        int filteredCount = mFilteredPhoneNumbers.size();
-        if (filteredCount == 0) {
-            return 0;
-        }
-        // Count on the separator
-        return 1 + filteredCount;
-    }
-
-    public Object getItem(int position) {
-        // This method is not used currently.
-        throw new RuntimeException("This method is not implemented");
-    }
-
-    public long getItemId(int position) {
-        // This method is not used currently.
-        throw new RuntimeException("This method is not implemented");
-    }
-
-    /**
-     * @return the initial phone numbers, the zero length array is returned when there is no
-     * initial numbers.
-     */
-    public final List<String> getPhoneNumbers() {
-        return mPhoneNumbers;
-    }
-
-    /**
-     * @return the filtered phone numbers, the zero size ArrayList is returned when there is no
-     * initial numbers.
-     */
-    public ArrayList<String> getFilteredPhoneNumbers() {
-        return mFilteredPhoneNumbers;
-    }
-
-    public View getView(int position, View convertView, ViewGroup parent) {
-        int viewCount = getCount();
-        if (viewCount == 0) {
-            return null;
-        }
-
-        int startPos = (this.mMultiplePhonePickerActivity.mMode &
-                MultiplePhonePickerActivity.MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0 ? 1 : 0;
-
-        // Separator
-        if (position == startPos) {
-            TextView view;
-            if (convertView != null && convertView instanceof TextView) {
-                view = (TextView) convertView;
-            } else {
-                LayoutInflater inflater =
-                    (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-                view = (TextView) inflater.inflate(R.layout.list_separator, parent, false);
-            }
-            view.setText(R.string.unknown_contacts_separator);
-            return view;
-        }
-        // PhoneNumbers start from position of startPos + 1
-        if (position >= startPos + 1 && position < startPos + viewCount) {
-            View view;
-            if (convertView != null) {
-                view = convertView;
-            } else {
-                view = this.mMultiplePhonePickerActivity.mAdapter.newView(mContext, null, parent);
-            }
-            bindView(view, mFilteredPhoneNumbers.get(position - 1 - startPos));
-            return view;
-        }
-        return null;
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        int startPos = (this.mMultiplePhonePickerActivity.mMode &
-                MultiplePhonePickerActivity.MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0 ? 1 : 0;
-
-        return position == startPos ? IGNORE_ITEM_VIEW_TYPE : super.getItemViewType(position);
-    }
-
-    private void bindView(View view, final String label) {
-        MultiplePhonePickerItemView itemView = (MultiplePhonePickerItemView) view;
-        itemView.setDividerVisible(true);
-        itemView.setSectionHeader(null);
-        itemView.setLabel(null);
-        itemView.setData(null, 0);
-        itemView.removePhotoView();
-
-        itemView.getNameTextView().setText(label);
-        CheckBox checkBox = itemView.getCheckBoxView();
-        checkBox.setChecked(mSelection.isSelected(label));
-        itemView.getChipView().setBackgroundResource(0);
-        itemView.phoneId = INVALID_PHONE_ID;
-        itemView.phoneNumber = label;
-    }
-
-    public void doFilter(final String constraint, boolean selectedOnly) {
-        if (mPhoneNumbers == null) {
-            return;
-        }
-        mFilteredPhoneNumbers.clear();
-        for (String number : mPhoneNumbers) {
-            if (selectedOnly && !mSelection.isSelected(number) ||
-                    !TextUtils.isEmpty(constraint) && !number.startsWith(constraint)) {
-                continue;
-            }
-            mFilteredPhoneNumbers.add(number);
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/list/MultiplePhonePickerAdapter.java b/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
index 11109d2..16ec183 100644
--- a/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
+++ b/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
@@ -15,175 +15,309 @@
  */
 package com.android.contacts.list;
 
-import com.android.contacts.ContactsListActivity;
-import com.android.contacts.MultiplePhonePickerActivity;
+import com.android.contacts.R;
 
+import android.content.ContentUris;
 import android.content.Context;
 import android.database.Cursor;
-import android.provider.ContactsContract.Contacts;
+import android.net.Uri;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.text.TextUtils;
+import android.util.SparseIntArray;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.QuickContactBadge;
-import android.widget.TextView;
 
-public class MultiplePhonePickerAdapter extends ContactItemListAdapter {
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
 
-    private final MultiplePhonePickerActivity mMultiplePhonePickerActivity;
-    private MultiplePhoneExtraAdapter mExtraAdapter;
+/**
+ * List adapter for the multiple phone picker.
+ */
+public class MultiplePhonePickerAdapter extends PhoneNumberListAdapter {
 
-    public MultiplePhonePickerAdapter(MultiplePhonePickerActivity multiplePhonePickerActivity) {
-        super(multiplePhonePickerActivity);
-        this.mMultiplePhonePickerActivity = multiplePhonePickerActivity;
+    public interface OnSelectionChangeListener {
+        void onSelectionChange();
     }
 
-    public void setExtraAdapter(MultiplePhoneExtraAdapter extraAdapter) {
-        mExtraAdapter = extraAdapter;
+    private static final int[] CHIP_COLOR_ARRAY = {
+        R.drawable.appointment_indicator_leftside_1,
+        R.drawable.appointment_indicator_leftside_2,
+        R.drawable.appointment_indicator_leftside_3,
+        R.drawable.appointment_indicator_leftside_4,
+        R.drawable.appointment_indicator_leftside_5,
+        R.drawable.appointment_indicator_leftside_6,
+        R.drawable.appointment_indicator_leftside_7,
+        R.drawable.appointment_indicator_leftside_8,
+        R.drawable.appointment_indicator_leftside_9,
+        R.drawable.appointment_indicator_leftside_10,
+        R.drawable.appointment_indicator_leftside_11,
+        R.drawable.appointment_indicator_leftside_12,
+        R.drawable.appointment_indicator_leftside_13,
+        R.drawable.appointment_indicator_leftside_14,
+        R.drawable.appointment_indicator_leftside_15,
+        R.drawable.appointment_indicator_leftside_16,
+        R.drawable.appointment_indicator_leftside_17,
+        R.drawable.appointment_indicator_leftside_18,
+        R.drawable.appointment_indicator_leftside_19,
+        R.drawable.appointment_indicator_leftside_20,
+        R.drawable.appointment_indicator_leftside_21,
+    };
+
+    public static final long INVALID_PHONE_ID = -1;
+
+    /** The phone numbers */
+    private ArrayList<String> mPhoneNumbers = new ArrayList<String>();
+
+    /** The selected phone numbers in the PhoneNumberAdapter */
+    private HashSet<String> mSelectedPhoneNumbers = new HashSet<String>();
+
+    /** The phone numbers after the filtering */
+    private ArrayList<String> mFilteredPhoneNumbers = new ArrayList<String>();
+
+    /** The PHONE_ID of selected number in user contacts*/
+    private HashSet<Long> mSelectedPhoneIds = new HashSet<Long>();
+
+    private boolean mSelectionChanged;
+
+    private OnSelectionChangeListener mSelectionChangeListener;
+
+    /**
+     * This is a map from contact ID to color index. A colored chip is used to
+     * indicate the number of phone numbers belong to one contact
+     */
+    private SparseIntArray mContactColor = new SparseIntArray();
+
+    public MultiplePhonePickerAdapter(Context context) {
+        super(context);
+    }
+
+    public void setOnSelectionChangeListener(OnSelectionChangeListener listener) {
+        this.mSelectionChangeListener = listener;
+    }
+
+    public void setPhoneNumbers(ArrayList<String> phoneNumbers) {
+        mPhoneNumbers.clear();
+        mPhoneNumbers.addAll(phoneNumbers);
+    }
+
+    public int getSelectedCount() {
+        return mSelectedPhoneNumbers.size() + mSelectedPhoneIds.size();
+    }
+
+    public Uri[] getSelectedUris() {
+        Uri[] uris = new Uri[mSelectedPhoneNumbers.size() + mSelectedPhoneIds.size()];
+        int count = mPhoneNumbers.size();
+        int index = 0;
+        for (int i = 0; i < count; i++) {
+            String phoneNumber = mPhoneNumbers.get(i);
+            if (isSelected(phoneNumber)) {
+                uris[index++] = Uri.parse("tel:" + phoneNumber);
+            }
+        }
+        for (Long contactId : mSelectedPhoneIds) {
+            uris[index++] = ContentUris.withAppendedId(Phone.CONTENT_URI, contactId);
+        }
+        return uris;
+    }
+
+    public void setSelectedUris(Uri[] uris) {
+        mSelectedPhoneNumbers.clear();
+        mSelectedPhoneIds.clear();
+        if (uris != null) {
+            for (Uri uri : uris) {
+                String scheme = uri.getScheme();
+                if ("tel".equals(scheme)) {
+                    String phoneNumber = uri.getSchemeSpecificPart();
+                    if (!mPhoneNumbers.contains(phoneNumber)) {
+                        mPhoneNumbers.add(phoneNumber);
+                    }
+                    mSelectedPhoneNumbers.add(phoneNumber);
+            } else if ("content".equals(scheme)) {
+                mSelectedPhoneIds.add(ContentUris.parseId(uri));
+            }
+            }
+        }
+        mFilteredPhoneNumbers.clear();
+        mFilteredPhoneNumbers.addAll(mPhoneNumbers);
+    }
+
+    public void toggleSelection(int position) {
+        if (position < mFilteredPhoneNumbers.size()) {
+            String phoneNumber = mPhoneNumbers.get(position);
+            setPhoneSelected(phoneNumber, !isSelected(phoneNumber));
+        } else {
+            Cursor cursor = getCursor();
+            cursor.moveToPosition(position - mFilteredPhoneNumbers.size());
+            long phoneId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
+            setPhoneSelected(phoneId, !isSelected(phoneId));
+        }
+        notifyDataSetChanged();
+    }
+
+    public boolean isSelectionChanged() {
+        return mSelectionChanged;
+    }
+
+    public void setSelectionChanged(boolean flag) {
+        mSelectionChanged = flag;
+        if (mSelectionChangeListener != null) {
+            mSelectionChangeListener.onSelectionChange();
+        }
+    }
+
+    public void setPhoneSelected(final String phoneNumber, boolean selected) {
+        if (!TextUtils.isEmpty(phoneNumber)) {
+            if (selected) {
+                mSelectedPhoneNumbers.add(phoneNumber);
+            } else {
+                mSelectedPhoneNumbers.remove(phoneNumber);
+            }
+        }
+        setSelectionChanged(true);
+    }
+
+    public void setPhoneSelected(long phoneId, boolean selected) {
+        if (selected) {
+            mSelectedPhoneIds.add(phoneId);
+        } else {
+            mSelectedPhoneIds.remove(phoneId);
+        }
+        setSelectionChanged(true);
+    }
+
+    public boolean isSelected(long phoneId) {
+        return mSelectedPhoneIds.contains(phoneId);
+    }
+
+    public boolean isSelected(final String phoneNumber) {
+        return mSelectedPhoneNumbers.contains(phoneNumber);
+    }
+
+    public void setAllPhonesSelected(boolean selected) {
+//        if (selected) {
+//            Cursor cursor = this.mMultiplePhoneSelectionActivity.mAdapter.getCursor();
+//            if (cursor != null) {
+//                int backupPos = cursor.getPosition();
+//                cursor.moveToPosition(-1);
+//                while (cursor.moveToNext()) {
+//                    setPhoneSelected(cursor
+//                            .getLong(MultiplePhonePickerActivity.PHONE_ID_COLUMN_INDEX), true);
+//                }
+//                cursor.moveToPosition(backupPos);
+//            }
+//            for (String number : this.mMultiplePhoneSelectionActivity.mPhoneNumberAdapter
+//                    .getFilteredPhoneNumbers()) {
+//                setPhoneSelected(number, true);
+//            }
+//        } else {
+//            mSelectedPhoneIds.clear();
+//            mSelectedPhoneNumbers.clear();
+//        }
+    }
+
+    public boolean isAllSelected() {
+        return false;
+//        return selectedCount() == this.mMultiplePhoneSelectionActivity.mPhoneNumberAdapter
+//                .getFilteredPhoneNumbers().size()
+//                + this.mMultiplePhoneSelectionActivity.mAdapter.getCount();
+    }
+
+    public Iterator<Long> getSelectedPhoneIds() {
+        return mSelectedPhoneIds.iterator();
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        return 2;
     }
 
     @Override
     public int getItemViewType(int position) {
-        if (position == 0 && mMultiplePhonePickerActivity.mShowNumberOfContacts) {
-            return IGNORE_ITEM_VIEW_TYPE;
-        }
-
-        if (position < mExtraAdapter.getCount()) {
-            return mExtraAdapter.getItemViewType(position);
-        }
-
-        return super.getItemViewType(position);
+        return position < mPhoneNumbers.size() ? 0 : 1;
     }
 
     @Override
     public View getView(int position, View convertView, ViewGroup parent) {
-        if (position == 0 && mMultiplePhonePickerActivity.mShowNumberOfContacts) {
-            return super.getView(position, convertView, parent);
+        View view;
+        if (convertView == null || convertView.getTag() == null) {
+            view = newView(getContext(), null, parent);
+        } else {
+            view = convertView;
         }
 
-        if (position < mExtraAdapter.getCount()) {
-            return mExtraAdapter.getView(position,
-                    convertView, parent);
+        boolean showingSuggestion = false;
+
+        if (position < mFilteredPhoneNumbers.size()) {
+            bindExtraPhoneView(view, position);
+        } else {
+            Cursor cursor = getCursor();
+            cursor.moveToPosition(position - mFilteredPhoneNumbers.size());
+            bindView(view, getContext(), cursor);
         }
-        return super.getView(position, convertView, parent);
+        return view;
     }
 
     @Override
     public View newView(Context context, Cursor cursor, ViewGroup parent) {
         final MultiplePhonePickerItemView view = new MultiplePhonePickerItemView(context, null);
-        view.setOnCallButtonClickListener(mMultiplePhonePickerActivity);
-        view.setOnCheckBoxClickListener(mMultiplePhonePickerActivity.mCheckBoxClickerListener);
+        view.setUnknownNameText(getUnknownNameText());
+        view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
         return view;
     }
 
+    private void bindExtraPhoneView(View itemView, int position) {
+        final MultiplePhonePickerItemView view = (MultiplePhonePickerItemView)itemView;
+        String phoneNumber = mFilteredPhoneNumbers.get(position);
+        view.getNameTextView().setText(phoneNumber);
+        CheckBox checkBox = view.getCheckBoxView();
+        checkBox.setChecked(isSelected(phoneNumber));
+        view.phoneId = INVALID_PHONE_ID;
+        view.phoneNumber = phoneNumber;
+    }
+
     @Override
     public void bindView(View itemView, Context context, Cursor cursor) {
+        super.bindView(itemView, context, cursor);
+
         final MultiplePhonePickerItemView view = (MultiplePhonePickerItemView)itemView;
-
-        int typeColumnIndex;
-        int dataColumnIndex;
-        int labelColumnIndex;
-        int defaultType;
-        int nameColumnIndex;
-        int phoneticNameColumnIndex;
-        int photoColumnIndex = ContactsListActivity.SUMMARY_PHOTO_ID_COLUMN_INDEX;
-        boolean displayAdditionalData = mDisplayAdditionalData;
-        nameColumnIndex = ContactsListActivity.PHONE_DISPLAY_NAME_COLUMN_INDEX;
-        phoneticNameColumnIndex = -1;
-        dataColumnIndex = ContactsListActivity.PHONE_NUMBER_COLUMN_INDEX;
-        typeColumnIndex = ContactsListActivity.PHONE_TYPE_COLUMN_INDEX;
-        labelColumnIndex = ContactsListActivity.PHONE_LABEL_COLUMN_INDEX;
-        defaultType = Phone.TYPE_HOME;
-        photoColumnIndex = ContactsListActivity.PHONE_PHOTO_ID_COLUMN_INDEX;
-
-        view.phoneId = Long.valueOf(cursor.getLong(ContactsListActivity.PHONE_ID_COLUMN_INDEX));
+        view.phoneId = Long.valueOf(cursor.getLong(PHONE_ID_COLUMN_INDEX));
         CheckBox checkBox = view.getCheckBoxView();
-        checkBox.setChecked(mMultiplePhonePickerActivity.mUserSelection.isSelected(view.phoneId));
-        int color = mMultiplePhonePickerActivity.getChipColor(cursor
-                .getLong(ContactsListActivity.PHONE_CONTACT_ID_COLUMN_INDEX));
-        view.getChipView().setBackgroundResource(color);
+        checkBox.setChecked(isSelected(view.phoneId));
 
-        // Set the name
-        cursor.copyStringToBuffer(nameColumnIndex, view.nameBuffer);
-        TextView nameView = view.getNameTextView();
-        int size = view.nameBuffer.sizeCopied;
-        if (size != 0) {
-            nameView.setText(view.nameBuffer.data, 0, size);
-        } else {
-            nameView.setText(mUnknownNameText);
-        }
-
-        // Set the photo, if requested
-        if (mDisplayPhotos) {
-            boolean useQuickContact = false;
-
-            long photoId = 0;
-            if (!cursor.isNull(photoColumnIndex)) {
-                photoId = cursor.getLong(photoColumnIndex);
-            }
-
-            ImageView viewToUse;
-            if (useQuickContact) {
-                // Build soft lookup reference
-                final long contactId = cursor.getLong(ContactsListActivity.SUMMARY_ID_COLUMN_INDEX);
-                final String lookupKey = cursor
-                        .getString(ContactsListActivity.SUMMARY_LOOKUP_KEY_COLUMN_INDEX);
-                QuickContactBadge quickContact = view.getQuickContact();
-                quickContact.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
-                viewToUse = quickContact;
-            } else {
-                viewToUse = view.getPhotoView();
-            }
-
-            final int position = cursor.getPosition();
-            getPhotoLoader().loadPhoto(viewToUse, photoId);
-        }
-
-        if (!displayAdditionalData) {
-            if (phoneticNameColumnIndex != -1) {
-
-                // Set the name
-                cursor.copyStringToBuffer(phoneticNameColumnIndex, view.phoneticNameBuffer);
-                int phoneticNameSize = view.phoneticNameBuffer.sizeCopied;
-                if (phoneticNameSize != 0) {
-                    view.setLabel(view.phoneticNameBuffer.data, phoneticNameSize);
-                } else {
-                    view.setLabel(null);
-                }
-            } else {
-                view.setLabel(null);
-            }
-            return;
-        }
-
-        // Set the data.
-        cursor.copyStringToBuffer(dataColumnIndex, view.dataBuffer);
-
-        size = view.dataBuffer.sizeCopied;
-        view.setData(view.dataBuffer.data, size);
-
-        // Set the label.
-        if (!cursor.isNull(typeColumnIndex)) {
-            final int type = cursor.getInt(typeColumnIndex);
-            final String label = cursor.getString(labelColumnIndex);
-            view.setLabel(Phone.getTypeLabel(context.getResources(), type, label));
-        } else {
-            view.setLabel(null);
-        }
+        long contactId = cursor.getLong(PHONE_CONTACT_ID_COLUMN_INDEX);
+        view.getChipView().setBackgroundResource(getChipColor(contactId));
     }
 
-    @Override
-    public void changeCursor(Cursor cursor) {
-        super.changeCursor(cursor);
-        mMultiplePhonePickerActivity.updateChipColor(cursor);
+//    @Override
+//    protected void prepareEmptyView() {
+//        mMultiplePhonePickerActivity.mEmptyView.show(mMultiplePhonePickerActivity.mSearchMode,
+//                true, false, false, false, true, mMultiplePhonePickerActivity.mShowSelectedOnly);
+//    }
+
+    /**
+     * Get assigned chip color resource id for a given contact, 0 is returned if there is no mapped
+     * resource.
+     */
+    public int getChipColor(long contactId) {
+        return mContactColor.get((int)contactId);
     }
 
-    @Override
-    protected void prepareEmptyView() {
-        mMultiplePhonePickerActivity.mEmptyView.show(mMultiplePhonePickerActivity.mSearchMode,
-                true, false, false, false, true, mMultiplePhonePickerActivity.mShowSelectedOnly);
-    }
+    // TODO filtering
+//    public void doFilter(final String constraint, boolean selectedOnly) {
+//        if (mPhoneNumbers == null) {
+//            return;
+//        }
+//        mFilteredPhoneNumbers.clear();
+//        for (String number : mPhoneNumbers) {
+//            if (selectedOnly && !mSelection.isSelected(number) ||
+//                    !TextUtils.isEmpty(constraint) && !number.startsWith(constraint)) {
+//                continue;
+//            }
+//            mFilteredPhoneNumbers.add(number);
+//        }
+//    }
 
     @Override
     public int getCount() {
@@ -191,13 +325,39 @@
             return 0;
         }
 
-        int count = super.getCount();
-        count += mExtraAdapter.getCount();
-        return count;
+        return super.getCount() + mFilteredPhoneNumbers.size();
     }
 
     @Override
-    protected int getRealPosition(int pos) {
-        return pos - mExtraAdapter.getCount();
+    public void changeCursor(Cursor cursor) {
+        super.changeCursor(cursor);
+        updateChipColor(cursor);
+    }
+
+    /**
+     * Go through the cursor and assign the chip color to contact who has more
+     * than one phone numbers. Assume the cursor is clustered by CONTACT_ID.
+     */
+    public void updateChipColor(Cursor cursor) {
+        if (cursor == null || cursor.getCount() == 0) {
+            return;
+        }
+        mContactColor.clear();
+        cursor.moveToFirst();
+        int colorIndex = 0;
+        long prevContactId = cursor.getLong(PHONE_CONTACT_ID_COLUMN_INDEX);
+        while (cursor.moveToNext()) {
+            long contactId = cursor.getLong(PHONE_CONTACT_ID_COLUMN_INDEX);
+            if (prevContactId == contactId) {
+                if (mContactColor.indexOfKey((int)contactId) < 0) {
+                    mContactColor.put((int)contactId, CHIP_COLOR_ARRAY[colorIndex]);
+                    colorIndex++;
+                    if (colorIndex >= CHIP_COLOR_ARRAY.length) {
+                        colorIndex = 0;
+                    }
+                }
+            }
+            prevContactId = contactId;
+        }
     }
 }
diff --git a/src/com/android/contacts/list/MultiplePhonePickerFragment.java b/src/com/android/contacts/list/MultiplePhonePickerFragment.java
index a38c0ec..dcf62d7 100644
--- a/src/com/android/contacts/list/MultiplePhonePickerFragment.java
+++ b/src/com/android/contacts/list/MultiplePhonePickerFragment.java
@@ -15,35 +15,165 @@
  */
 package com.android.contacts.list;
 
-import com.android.contacts.MultiplePhonePickerActivity;
 import com.android.contacts.R;
+import com.android.contacts.list.MultiplePhonePickerAdapter.OnSelectionChangeListener;
 
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewStub;
+import android.view.View.OnClickListener;
+import android.view.animation.AnimationUtils;
+import android.widget.Button;
 
 /**
  * Fragment for the multiple phone picker.
  */
-public class MultiplePhonePickerFragment extends ContactEntryListFragment {
+public class MultiplePhonePickerFragment
+        extends ContactEntryListFragment<MultiplePhonePickerAdapter>
+        implements OnClickListener, OnSelectionChangeListener {
+
+    private static final String SELECTION_EXTRA_KEY = "selection";
+    private static final String SELECTION_CHANGED_EXTRA_KEY = "selectionChanged";
+
+    private OnMultiplePhoneNumberPickerActionListener mListener;
+
+    /**
+     * UI control of action panel in MODE_PICK_MULTIPLE_PHONES mode.
+     */
+    private View mFooterView;
+
+    private Uri[] mSelectedUris;
+    private boolean mSelectionChanged;
+
+    public MultiplePhonePickerFragment() {
+        setSectionHeaderDisplayEnabled(false);
+        setPhotoLoaderEnabled(true);
+    }
+
+    public void setOnMultiplePhoneNumberPickerActionListener(
+            OnMultiplePhoneNumberPickerActionListener listener) {
+        mListener = listener;
+    }
+
+    public Uri[] getSelectedUris() {
+        return getAdapter().getSelectedUris();
+    }
+
+    public void setSelectedUris(Parcelable[] extras) {
+        Uri[] uris = new Uri[extras == null ? 0 : extras.length];
+        if (extras != null) {
+            for (int i = 0; i < extras.length; i++) {
+                uris[i] = (Uri)extras[i];
+            }
+        }
+        setSelectedUris(uris);
+    }
+
+    public void setSelectedUris(Uri[] uris) {
+        mSelectedUris = uris;
+        MultiplePhonePickerAdapter adapter = getAdapter();
+        if (adapter != null) {
+            adapter.setSelectedUris(uris);
+        }
+    }
 
     @Override
-    public ContactEntryListAdapter createListAdapter() {
-        MultiplePhonePickerAdapter adapter =
-                new MultiplePhonePickerAdapter((MultiplePhonePickerActivity)getActivity());
-        adapter.setSectionHeaderDisplayEnabled(true);
-        adapter.setDisplayPhotos(true);
-        return adapter;
+    protected MultiplePhonePickerAdapter createListAdapter() {
+        return new MultiplePhonePickerAdapter(getActivity());
+    }
+
+    @Override
+    protected void configureAdapter() {
+        super.configureAdapter();
+        MultiplePhonePickerAdapter adapter = getAdapter();
+        adapter.setSelectedUris(mSelectedUris);
+        adapter.setSelectionChanged(mSelectionChanged);
+        adapter.setOnSelectionChangeListener(this);
     }
 
     @Override
     protected View inflateView(LayoutInflater inflater, ViewGroup container) {
-        return inflater.inflate(R.layout.contacts_list_content, null);
+        View view = inflater.inflate(R.layout.contacts_list_content, null);
+        ViewStub stub = (ViewStub)view.findViewById(R.id.footer_stub);
+        if (stub != null) {
+            View stubView = stub.inflate();
+            mFooterView = stubView.findViewById(R.id.footer);
+            mFooterView.setVisibility(View.GONE);
+            Button doneButton = (Button) stubView.findViewById(R.id.done);
+            doneButton.setOnClickListener(this);
+            Button revertButton = (Button) stubView.findViewById(R.id.revert);
+            revertButton.setOnClickListener(this);
+        }
+        return view;
     }
 
     @Override
     protected void onItemClick(int position, long id) {
-        // TODO
-        throw new UnsupportedOperationException();
+        getAdapter().toggleSelection(position);
+    }
+
+    public void onClick(View v) {
+        int id = v.getId();
+        switch (id) {
+            case R.id.done:
+                mListener.onPhoneNumbersSelectedAction(getAdapter().getSelectedUris());
+                break;
+            case R.id.revert:
+                mListener.onFinishAction();
+                break;
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        updateWidgets();
+    }
+
+    public void onSelectionChange() {
+        updateWidgets();
+    }
+
+    private void updateWidgets() {
+        int selected = getAdapter().getSelectedCount();
+
+        Activity context = getActivity();
+        if (selected >= 1) {
+            final String format = context.getResources().getQuantityString(
+                    R.plurals.multiple_picker_title, selected);
+
+            // TODO: turn this into a callback
+            context.setTitle(String.format(format, selected));
+        } else {
+            // TODO: turn this into a callback
+            context.setTitle(context.getString(R.string.contactsList));
+        }
+
+        if (getAdapter().isSelectionChanged() && mFooterView.getVisibility() == View.GONE) {
+            mFooterView.setVisibility(View.VISIBLE);
+            mFooterView.startAnimation(AnimationUtils.loadAnimation(context, R.anim.footer_appear));
+        }
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        icicle.putParcelableArray(SELECTION_EXTRA_KEY, getAdapter().getSelectedUris());
+        icicle.putBoolean(SELECTION_CHANGED_EXTRA_KEY, getAdapter().isSelectionChanged());
+    }
+
+    @Override
+    public void onRestoreInstanceState(Bundle icicle) {
+        super.onRestoreInstanceState(icicle);
+        setSelectedUris(icicle.getParcelableArray(SELECTION_EXTRA_KEY));
+        mSelectionChanged = icicle.getBoolean(SELECTION_CHANGED_EXTRA_KEY, false);
+        if (getAdapter() != null) {
+            getAdapter().setSelectionChanged(mSelectionChanged);
+        }
     }
 }
diff --git a/src/com/android/contacts/list/MultiplePhonePickerItemView.java b/src/com/android/contacts/list/MultiplePhonePickerItemView.java
index af4c6c8..4801d33 100644
--- a/src/com/android/contacts/list/MultiplePhonePickerItemView.java
+++ b/src/com/android/contacts/list/MultiplePhonePickerItemView.java
@@ -38,8 +38,6 @@
     private int mChipRightMargin;
     private int mCheckBoxMargin;
 
-    private OnClickListener mCheckBoxClickListener;
-
     public long phoneId;
     // phoneNumber only validates when phoneId = INVALID_PHONE_ID
     public String phoneNumber;
@@ -55,10 +53,6 @@
                 resources.getDimensionPixelOffset(R.dimen.list_item_header_checkbox_margin);
     }
 
-    public void setOnCheckBoxClickListener(OnClickListener checkBoxClickListener) {
-        mCheckBoxClickListener = checkBoxClickListener;
-    }
-
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (isVisible(mChipView)) {
@@ -118,7 +112,8 @@
     public CheckBox getCheckBoxView() {
         if (mCheckBox == null) {
             mCheckBox = new CheckBox(mContext);
-            mCheckBox.setOnClickListener(mCheckBoxClickListener);
+            mCheckBox.setClickable(false);
+            mCheckBox.setFocusable(false);
             addView(mCheckBox);
         }
         return mCheckBox;
diff --git a/src/com/android/contacts/list/MultiplePhoneSelection.java b/src/com/android/contacts/list/MultiplePhoneSelection.java
deleted file mode 100644
index e9249e4..0000000
--- a/src/com/android/contacts/list/MultiplePhoneSelection.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * 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.list;
-
-import com.android.contacts.MultiplePhonePickerActivity;
-
-import android.content.ContentUris;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract.Intents;
-import android.provider.ContactsContract.CommonDataKinds.Phone;
-import android.text.TextUtils;
-
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * This class is used to keep the user's selection in MODE_PICK_MULTIPLE_PHONES mode.
- */
-public class MultiplePhoneSelection {
-
-    private final MultiplePhonePickerActivity mMultiplePhoneSelectionActivity;
-
-    private static final String TEL_SCHEME = "tel";
-
-    public static final String EXTRA_SELECTION =
-        "com.android.contacts.MultiplePhoneSelectionActivity.UserSelection.extra.SELECTION";
-    private static final String SELECTED_UNKNOWN_PHONES_KEY = "selected_unknown_phones";
-    private static final String SELECTED_PHONE_IDS_KEY = "selected_phone_id";
-
-    /** The PHONE_ID of selected number in user contacts*/
-    private HashSet<Long> mSelectedPhoneIds = new HashSet<Long>();
-
-    /** The selected phone numbers in the PhoneNumberAdapter */
-    private HashSet<String> mSelectedPhoneNumbers = new HashSet<String>();
-
-    public MultiplePhoneSelection(MultiplePhonePickerActivity multiplePhonePickerActivity) {
-        this.mMultiplePhoneSelectionActivity = multiplePhonePickerActivity;
-    }
-
-    public void saveInstanceState(Bundle icicle) {
-        int selectedUnknownsCount = mSelectedPhoneNumbers.size();
-        if (selectedUnknownsCount > 0) {
-            String[] selectedUnknows = new String[selectedUnknownsCount];
-            icicle.putStringArray(SELECTED_UNKNOWN_PHONES_KEY,
-                    mSelectedPhoneNumbers.toArray(selectedUnknows));
-        }
-        int selectedKnownsCount = mSelectedPhoneIds.size();
-        if (selectedKnownsCount > 0) {
-            long[] selectedPhoneIds = new long [selectedKnownsCount];
-            int index = 0;
-            for (Long phoneId : mSelectedPhoneIds) {
-                selectedPhoneIds[index++] = phoneId.longValue();
-            }
-            icicle.putLongArray(SELECTED_PHONE_IDS_KEY, selectedPhoneIds);
-
-        }
-    }
-
-    public void restoreInstanceState(Bundle icicle) {
-        if (icicle != null) {
-            setSelection(icicle.getStringArray(SELECTED_UNKNOWN_PHONES_KEY),
-                    icicle.getLongArray(SELECTED_PHONE_IDS_KEY));
-        }
-    }
-
-    public void setSelection(final String[] selecedUnknownNumbers, final long[] selectedPhoneIds) {
-        if (selecedUnknownNumbers != null) {
-            for (String number : selecedUnknownNumbers) {
-                setPhoneSelected(number, true);
-            }
-        }
-        if (selectedPhoneIds != null) {
-            for (long id : selectedPhoneIds) {
-                setPhoneSelected(id, true);
-            }
-        }
-    }
-
-    public void setSelection(final List<String> selecedUnknownNumbers,
-            final List<Long> selectedPhoneIds) {
-        if (selecedUnknownNumbers != null) {
-            setPhoneNumbersSelected(selecedUnknownNumbers, true);
-        }
-        if (selectedPhoneIds != null) {
-            setPhoneIdsSelected(selectedPhoneIds, true);
-        }
-    }
-
-    private void setPhoneNumbersSelected(final List<String> phoneNumbers, boolean selected) {
-        if (selected) {
-            mSelectedPhoneNumbers.addAll(phoneNumbers);
-        } else {
-            mSelectedPhoneNumbers.removeAll(phoneNumbers);
-        }
-    }
-
-    private void setPhoneIdsSelected(final List<Long> phoneIds, boolean selected) {
-        if (selected) {
-            mSelectedPhoneIds.addAll(phoneIds);
-        } else {
-            mSelectedPhoneIds.removeAll(phoneIds);
-        }
-    }
-
-    public void setPhoneSelected(final String phoneNumber, boolean selected) {
-        if (!TextUtils.isEmpty(phoneNumber)) {
-            if (selected) {
-                mSelectedPhoneNumbers.add(phoneNumber);
-            } else {
-                mSelectedPhoneNumbers.remove(phoneNumber);
-            }
-        }
-    }
-
-    public void setPhoneSelected(long phoneId, boolean selected) {
-        if (selected) {
-            mSelectedPhoneIds.add(phoneId);
-        } else {
-            mSelectedPhoneIds.remove(phoneId);
-        }
-    }
-
-    public boolean isSelected(long phoneId) {
-        return mSelectedPhoneIds.contains(phoneId);
-    }
-
-    public boolean isSelected(final String phoneNumber) {
-        return mSelectedPhoneNumbers.contains(phoneNumber);
-    }
-
-    public void setAllPhonesSelected(boolean selected) {
-        if (selected) {
-            Cursor cursor = this.mMultiplePhoneSelectionActivity.mAdapter.getCursor();
-            if (cursor != null) {
-                int backupPos = cursor.getPosition();
-                cursor.moveToPosition(-1);
-                while (cursor.moveToNext()) {
-                    setPhoneSelected(cursor
-                            .getLong(MultiplePhonePickerActivity.PHONE_ID_COLUMN_INDEX), true);
-                }
-                cursor.moveToPosition(backupPos);
-            }
-            for (String number : this.mMultiplePhoneSelectionActivity.mPhoneNumberAdapter
-                    .getFilteredPhoneNumbers()) {
-                setPhoneSelected(number, true);
-            }
-        } else {
-            mSelectedPhoneIds.clear();
-            mSelectedPhoneNumbers.clear();
-        }
-    }
-
-    public boolean isAllSelected() {
-        return selectedCount() == this.mMultiplePhoneSelectionActivity.mPhoneNumberAdapter
-                .getFilteredPhoneNumbers().size()
-                + this.mMultiplePhoneSelectionActivity.mAdapter.getCount();
-    }
-
-    public int selectedCount() {
-        return mSelectedPhoneNumbers.size() + mSelectedPhoneIds.size();
-    }
-
-    public Iterator<Long> getSelectedPhonIds() {
-        return mSelectedPhoneIds.iterator();
-    }
-
-    private int fillSelectedNumbers(Uri[] uris, int from) {
-        int count = mSelectedPhoneNumbers.size();
-        if (count == 0)
-            return from;
-        // Below loop keeps phone numbers by initial order.
-        List<String> phoneNumbers = this.mMultiplePhoneSelectionActivity.mPhoneNumberAdapter
-                .getPhoneNumbers();
-        for (String phoneNumber : phoneNumbers) {
-            if (isSelected(phoneNumber)) {
-                Uri.Builder ub = new Uri.Builder();
-                ub.scheme(TEL_SCHEME);
-                ub.encodedOpaquePart(phoneNumber);
-                uris[from++] = ub.build();
-            }
-        }
-        return from;
-    }
-
-    private int fillSelectedPhoneIds(Uri[] uris, int from) {
-        int count = mSelectedPhoneIds.size();
-        if (count == 0)
-            return from;
-        Iterator<Long> it = mSelectedPhoneIds.iterator();
-        while (it.hasNext()) {
-            uris[from++] = ContentUris.withAppendedId(Phone.CONTENT_URI, it.next());
-        }
-        return from;
-    }
-
-    private Uri[] getSelected() {
-        Uri[] uris = new Uri[mSelectedPhoneNumbers.size() + mSelectedPhoneIds.size()];
-        int from  = fillSelectedNumbers(uris, 0);
-        fillSelectedPhoneIds(uris, from);
-        return uris;
-    }
-
-    public Intent createSelectionIntent() {
-        Intent intent = new Intent();
-        intent.putExtra(Intents.EXTRA_PHONE_URIS, getSelected());
-
-        return intent;
-    }
-
-    public void fillSelectionForSearchMode(Bundle bundle) {
-        bundle.putParcelableArray(EXTRA_SELECTION, getSelected());
-    }
-}
\ No newline at end of file
diff --git a/src/com/android/contacts/list/OnMultiplePhoneNumberPickerActionListener.java b/src/com/android/contacts/list/OnMultiplePhoneNumberPickerActionListener.java
new file mode 100644
index 0000000..ac010ba
--- /dev/null
+++ b/src/com/android/contacts/list/OnMultiplePhoneNumberPickerActionListener.java
@@ -0,0 +1,34 @@
+/*
+ * 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.list;
+
+import android.net.Uri;
+
+/**
+ * Action callbacks that can be sent by a multiple phone number picker.
+ */
+public interface OnMultiplePhoneNumberPickerActionListener {
+
+    /**
+     * Returns the selected phone numbers to the requester.
+     */
+    void onPhoneNumbersSelectedAction(Uri[] dataUris);
+
+    /**
+     * Closes the picker without changing the selection.
+     */
+    void onFinishAction();
+}
diff --git a/src/com/android/contacts/list/PhoneNumberListAdapter.java b/src/com/android/contacts/list/PhoneNumberListAdapter.java
index 70ec4ec..ffac30b 100644
--- a/src/com/android/contacts/list/PhoneNumberListAdapter.java
+++ b/src/com/android/contacts/list/PhoneNumberListAdapter.java
@@ -64,6 +64,10 @@
         mUnknownNameText = context.getText(android.R.string.unknownName);
     }
 
+    protected CharSequence getUnknownNameText() {
+        return mUnknownNameText;
+    }
+
     @Override
     public void configureLoader(CursorLoader loader) {
         loader.setUri(buildSectionIndexerUri(Phone.CONTENT_URI));