Breaking out the Multi-Picker into a separate activity.

Continuing the "nuke" part of the nuke-and-rebuild
process for ContactsListActivity. At this stage the code
will look worse than before, but hopefully will remain
fully functional.

Bear with us - we are in the middle of a major refactoring.

Change-Id: Idad9fa2e589dce0bcd3f62b9c7d5bf22fea6c5e1
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7d88e8f..23fe067 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -223,12 +223,6 @@
                 <data android:mimeType="vnd.android.cursor.item/postal-address_v2" android:host="com.android.contacts" />
                 <data android:mimeType="vnd.android.cursor.item/postal-address" android:host="contacts" />
             </intent-filter>
-
-            <intent-filter>
-                <action android:name="com.android.contacts.action.GET_MULTIPLE_PHONES" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:mimeType="vnd.android.cursor.dir/phone_v2" android:host="com.android.contacts" />
-            </intent-filter>
         </activity>
 
         <!-- An activity for joining contacts -->
@@ -242,6 +236,15 @@
             </intent-filter>
         </activity>
 
+        <!-- An activity for selecting multiple phone numbers -->
+        <activity android:name="MultiplePhonePickerActivity">
+            <intent-filter>
+                <action android:name="com.android.contacts.action.GET_MULTIPLE_PHONES" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/phone_v2" android:host="com.android.contacts" />
+            </intent-filter>
+        </activity>
+
         <!-- The contacts search/filter UI -->
         <activity android:name="ContactsSearchActivity"
             android:theme="@style/ContactsSearchTheme"
diff --git a/src/com/android/contacts/ContactListItemView.java b/src/com/android/contacts/ContactListItemView.java
index db2bb48..9be3fba 100644
--- a/src/com/android/contacts/ContactListItemView.java
+++ b/src/com/android/contacts/ContactListItemView.java
@@ -146,6 +146,7 @@
     public void setOnCheckBoxClickListener(OnClickListener checkBoxClickListener) {
         mCheckBoxClickListener = checkBoxClickListener;
     }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // We will match parent's width and wrap content vertically, but make sure
@@ -470,6 +471,24 @@
     }
 
     /**
+     * Removes the photo view.  Should not be needed once we start handling different
+     * types of views as different types of views from the List's perspective.
+     *
+     * @deprecated
+     */
+    @Deprecated
+    public void removePhotoView() {
+        if (mPhotoView != null) {
+            removeView(mPhotoView);
+            mPhotoView = null;
+        }
+        if (mQuickContact != null) {
+            removeView(mQuickContact);
+            mQuickContact = null;
+        }
+    }
+
+    /**
      * Returns the text view for the contact name, creating it if necessary.
      */
     public TextView getNameTextView() {
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 832ea76..bf5fa49 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -32,7 +32,6 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ListActivity;
-import android.app.ProgressDialog;
 import android.app.SearchManager;
 import android.content.AsyncQueryHandler;
 import android.content.ContentResolver;
@@ -86,7 +85,6 @@
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.Log;
-import android.util.SparseIntArray;
 import android.view.ContextMenu;
 import android.view.ContextThemeWrapper;
 import android.view.KeyEvent;
@@ -97,19 +95,15 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.View.OnClickListener;
 import android.view.View.OnFocusChangeListener;
 import android.view.View.OnTouchListener;
-import android.view.animation.AnimationUtils;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
 import android.widget.ArrayAdapter;
-import android.widget.BaseAdapter;
 import android.widget.Button;
-import android.widget.CheckBox;
 import android.widget.Filter;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -117,8 +111,6 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
 
@@ -150,7 +142,7 @@
     private static final int SUBACTIVITY_VIEW_CONTACT = 2;
     private static final int SUBACTIVITY_DISPLAY_GROUP = 3;
     private static final int SUBACTIVITY_SEARCH = 4;
-    private static final int SUBACTIVITY_FILTER = 5;
+    protected static final int SUBACTIVITY_FILTER = 5;
 
     private static final int TEXT_HIGHLIGHTING_ANIMATION_DURATION = 350;
 
@@ -369,19 +361,16 @@
     public static final int POSTAL_ADDRESS_COLUMN_INDEX = 3;
     public static final int POSTAL_DISPLAY_NAME_COLUMN_INDEX = 4;
 
-    private static final int QUERY_TOKEN = 42;
+    protected static final int QUERY_TOKEN = 42;
 
     static final String KEY_PICKER_MODE = "picker_mode";
 
-    private static final String TEL_SCHEME = "tel";
-    private static final String CONTENT_SCHEME = "content";
-
-    private ContactItemListAdapter mAdapter;
+    public ContactItemListAdapter mAdapter;
     public ContactListEmptyView mEmptyView;
 
     public int mMode = MODE_DEFAULT;
     private boolean mRunQueriesSynchronously;
-    private QueryHandler mQueryHandler;
+    protected QueryHandler mQueryHandler;
     private boolean mJustCreated;
     private boolean mSyncEnabled;
     Uri mSelectedContactUri;
@@ -422,7 +411,7 @@
 
     private String mInitialFilter;
 
-    private static final String CLAUSE_ONLY_VISIBLE = Contacts.IN_VISIBLE_GROUP + "=1";
+    protected static final String CLAUSE_ONLY_VISIBLE = Contacts.IN_VISIBLE_GROUP + "=1";
     private static final String CLAUSE_ONLY_PHONES = Contacts.HAS_PHONE_NUMBER + "=1";
 
 
@@ -436,57 +425,6 @@
             Contacts.LOOKUP_KEY
     };
 
-    /**
-     * User selected phone number and id in MODE_PICK_MULTIPLE_PHONES mode.
-     */
-    public UserSelection mUserSelection = new UserSelection(null, null);
-
-    /**
-     * The adapter for the phone numbers, used in MODE_PICK_MULTIPLE_PHONES mode.
-     */
-    public PhoneNumberAdapter mPhoneNumberAdapter = new PhoneNumberAdapter(this, null);
-
-    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;
-
-    /**
-     * Display only selected recipients or not in MODE_PICK_MULTIPLE_PHONES mode
-     */
-    public boolean mShowSelectedOnly = false;
-
     static {
         sContactsIdMatcher = new UriMatcher(UriMatcher.NO_MATCH);
         sContactsIdMatcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
@@ -564,19 +502,6 @@
         }
     };
 
-    public OnClickListener mCheckBoxClickerListener = new OnClickListener () {
-        public void onClick(View v) {
-            final ContactListItemCache cache = (ContactListItemCache) v.getTag();
-            if (cache.phoneId != PhoneNumberAdapter.INVALID_PHONE_ID) {
-                mUserSelection.setPhoneSelected(cache.phoneId, ((CheckBox) v).isChecked());
-            } else {
-                mUserSelection.setPhoneSelected(cache.phoneNumber,
-                        ((CheckBox) v).isChecked());
-            }
-            updateWidgets(true);
-        }
-    };
-
     private ContactListConfiguration mConfig;
 
     public ContactsListActivity() {
@@ -607,9 +532,6 @@
 
         resolveIntent(intent);
         initContentView();
-        if (mMode == MODE_PICK_MULTIPLE_PHONES) {
-            initMultiPicker(intent);
-        }
     }
 
     protected void resolveIntent(final Intent intent) {
@@ -657,30 +579,21 @@
             setContentView(R.layout.contacts_list_content);
         }
 
-        setupListView(new ContactItemListAdapter(this));
+        setupListView(createListAdapter());
         if (mSearchMode) {
             setupSearchView();
         }
 
-        if (mMode == MODE_PICK_MULTIPLE_PHONES) {
-            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);
-            }
-        }
-
         View emptyView = mList.getEmptyView();
         if (emptyView instanceof ContactListEmptyView) {
             mEmptyView = (ContactListEmptyView)emptyView;
         }
     }
 
+    protected ContactItemListAdapter createListAdapter() {
+        return new ContactItemListAdapter(this);
+    }
+
     /**
      * Register an observer for provider status changes - we will need to
      * reflect them in the UI.
@@ -761,13 +674,6 @@
                 }
                 break;
             }
-            case R.id.done:
-                setMultiPickerResult();
-                finish();
-                break;
-            case R.id.revert:
-                finish();
-                break;
         }
     }
 
@@ -957,9 +863,6 @@
         // Save list state in the bundle so we can restore it after the QueryHandler has run
         if (mList != null) {
             icicle.putParcelable(LIST_STATE_KEY, mList.onSaveInstanceState());
-            if (mMode == MODE_PICK_MULTIPLE_PHONES && mUserSelection != null) {
-                mUserSelection.saveInstanceState(icicle);
-            }
         }
     }
 
@@ -968,9 +871,6 @@
         super.onRestoreInstanceState(icicle);
         // Retrieve list state. This will be applied after the QueryHandler has run
         mListState = icicle.getParcelable(LIST_STATE_KEY);
-        if (mMode == MODE_PICK_MULTIPLE_PHONES) {
-            mUserSelection = new UserSelection(icicle);
-        }
     }
 
     @Override
@@ -990,12 +890,6 @@
     public boolean onCreateOptionsMenu(Menu menu) {
         super.onCreateOptionsMenu(menu);
 
-        if (mMode == MODE_PICK_MULTIPLE_PHONES) {
-            final MenuInflater inflater = getMenuInflater();
-            inflater.inflate(R.menu.pick, menu);
-            return true;
-        }
-
         // If Contacts was invoked by another Activity simply as a way of
         // picking a contact, don't show the options menu
         if ((mMode & MODE_MASK_PICKER) == MODE_MASK_PICKER) {
@@ -1009,26 +903,6 @@
 
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
-        if (mMode == MODE_PICK_MULTIPLE_PHONES) {
-            if (mShowSelectedOnly) {
-                menu.findItem(R.id.menu_display_selected).setVisible(false);
-                menu.findItem(R.id.menu_display_all).setVisible(true);
-                menu.findItem(R.id.menu_select_all).setVisible(false);
-                menu.findItem(R.id.menu_select_none).setVisible(false);
-                return true;
-            }
-            menu.findItem(R.id.menu_display_all).setVisible(false);
-            menu.findItem(R.id.menu_display_selected).setVisible(true);
-            if (mUserSelection.isAllSelected()) {
-                menu.findItem(R.id.menu_select_all).setVisible(false);
-                menu.findItem(R.id.menu_select_none).setVisible(true);
-            } else {
-                menu.findItem(R.id.menu_select_all).setVisible(true);
-                menu.findItem(R.id.menu_select_none).setVisible(false);
-            }
-            return true;
-        }
-
         final boolean defaultMode = (mMode == MODE_DEFAULT);
         menu.findItem(R.id.menu_display_groups).setVisible(defaultMode);
         return true;
@@ -1063,28 +937,6 @@
                 startActivity(intent);
                 return true;
             }
-            case R.id.menu_select_all: {
-                mUserSelection.setAllPhonesSelected(true);
-                checkAll(true);
-                updateWidgets(true);
-                return true;
-            }
-            case R.id.menu_select_none: {
-                mUserSelection.setAllPhonesSelected(false);
-                checkAll(false);
-                updateWidgets(true);
-                return true;
-            }
-            case R.id.menu_display_selected: {
-                mShowSelectedOnly = true;
-                startQuery();
-                return true;
-            }
-            case R.id.menu_display_all: {
-                mShowSelectedOnly = false;
-                startQuery();
-                return true;
-            }
         }
         return false;
     }
@@ -1101,16 +953,8 @@
         } else {
             if (!mSearchMode && (mMode & MODE_MASK_NO_FILTER) == 0) {
                 if ((mMode & MODE_MASK_PICKER) != 0) {
-                    Bundle extras = null;
-                    if (mMode == MODE_PICK_MULTIPLE_PHONES) {
-                        extras = getIntent().getExtras();
-                        if (extras == null) {
-                            extras = new Bundle();
-                        }
-                        mUserSelection.fillSelectionForSearchMode(extras);
-                    }
                     ContactsSearchManager.startSearchForResult(this, initialQuery,
-                            SUBACTIVITY_FILTER, extras);
+                            SUBACTIVITY_FILTER, null);
                 } else {
                     ContactsSearchManager.startSearch(this, initialQuery);
                 }
@@ -1558,14 +1402,6 @@
         return false;
     }
 
-    @Override
-    public void onBackPressed() {
-        if (mMode == MODE_PICK_MULTIPLE_PHONES) {
-            setMultiPickerResult();
-        }
-        super.onBackPressed();
-    }
-
     /**
      * Prompt the user before deleting the given {@link Contacts} entry.
      */
@@ -2293,25 +2129,6 @@
                 mQueryHandler.startQuery(QUERY_TOKEN, null, uri, projection, null, null, null);
                 break;
 
-            case MODE_PICK_MULTIPLE_PHONES:
-                // 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));
-                    break;
-                }
-                // Fall through For other cases
             case MODE_PICK_PHONE:
                 mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
                         projection, CLAUSE_ONLY_VISIBLE, null, getSortOrder(projection));
@@ -2390,10 +2207,6 @@
                 return resolver.query(uri, projection, null, null, null);
             }
 
-            case MODE_PICK_MULTIPLE_PHONES:
-                // Filter phone numbers as well.
-                mPhoneNumberAdapter.doFilter(filter, mShowSelectedOnly);
-                // Fall through
             case MODE_PICK_PHONE: {
                 Uri uri = getUriToQuery();
                 if (!TextUtils.isEmpty(filter)) {
@@ -2551,148 +2364,7 @@
         return (Cursor) listView.getAdapter().getItem(index);
     }
 
-    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_SCHEME.equals(scheme)) {
-                    phoneNumbers.add(uri.getSchemeSpecificPart());
-                } else if (phoneIds != null && CONTENT_SCHEME.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(UserSelection.EXTRA_SELECTION);
-            if (uris != null) {
-                selectedPhoneNumbers = new ArrayList<String>();
-                getPhoneNumbersOrIdsFromURIs(uris, selectedPhoneNumbers, phoneIds);
-            }
-        } else {
-            getPhoneNumbersOrIdsFromURIs(uris, phoneNumbers, phoneIds);
-            selectedPhoneNumbers = phoneNumbers;
-        }
-        mPhoneNumberAdapter = new PhoneNumberAdapter(this, phoneNumbers);
-        mUserSelection = new UserSelection(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));
-        }
-    }
-
-    private void checkAll(boolean checked) {
-        final ListView listView = getListView();
-        int childCount = listView.getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            final ContactListItemView child = (ContactListItemView)listView.getChildAt(i);
-            child.getCheckBoxView().setChecked(checked);
-        }
-    }
-
-    private class QueryHandler extends AsyncQueryHandler {
+    protected class QueryHandler extends AsyncQueryHandler {
         protected final WeakReference<ContactsListActivity> mActivity;
 
         public QueryHandler(Context context) {
@@ -2752,332 +2424,4 @@
         public ColorStateList textColor;
         public Drawable background;
     }
-
-    /**
-     * 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 PhoneNumberAdapter extends BaseAdapter {
-        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 Context mContext;
-
-        /** The position where this Adapter Phone numbers start*/
-        private int mStartPos;
-
-        public PhoneNumberAdapter(Context context, final List<String> phoneNumbers) {
-            init(context, phoneNumbers);
-        }
-
-        private void init(Context context, final List<String> phoneNumbers) {
-            mStartPos = (mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0 ? 1 : 0;
-            mContext = context;
-            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;
-            }
-            // Separator
-            if (position == mStartPos) {
-                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 >= mStartPos + 1 && position < mStartPos + viewCount) {
-                View view;
-                if (convertView != null && convertView.getTag() != null &&
-                        convertView.getTag() instanceof ContactListItemCache) {
-                    view = convertView;
-                } else {
-                    view = mAdapter.newView(mContext, null, parent);
-                }
-                bindView(view, mFilteredPhoneNumbers.get(position - 1 - mStartPos));
-                return view;
-            }
-            return null;
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            return position == mStartPos ? IGNORE_ITEM_VIEW_TYPE : super.getItemViewType(position);
-        }
-
-        private void bindView(View view, final String label) {
-            ContactListItemView itemView = (ContactListItemView) view;
-            final ContactListItemCache cache = (ContactListItemCache) view.getTag();
-            itemView.getNameTextView().setText(label);
-            CheckBox checkBox = itemView.getCheckBoxView();
-            checkBox.setChecked(mUserSelection.isSelected(label));
-            itemView.getChipView().setBackgroundResource(0);
-            cache.phoneId = INVALID_PHONE_ID;
-            cache.phoneNumber = label;
-            checkBox.setTag(cache);
-        }
-
-        public void doFilter(final String constraint, boolean selectedOnly) {
-            if (mPhoneNumbers == null) {
-                return;
-            }
-            mFilteredPhoneNumbers.clear();
-            for (String number : mPhoneNumbers) {
-                if (selectedOnly && !mUserSelection.isSelected(number) ||
-                        !TextUtils.isEmpty(constraint) && !number.startsWith(constraint)) {
-                    continue;
-                }
-                mFilteredPhoneNumbers.add(number);
-            }
-        }
-    }
-
-    /**
-     * This class is used to keep the user's selection in MODE_PICK_MULTIPLE_PHONES mode.
-     */
-    public class UserSelection {
-        public static final String EXTRA_SELECTION =
-            "com.android.contacts.ContactsListActivity.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>();
-
-        /**
-         * @param phoneNumbers the phone numbers are selected.
-         */
-        public UserSelection(final List<String> phoneNumbers, final List<Long> phoneIds) {
-            init(phoneNumbers, phoneIds);
-        }
-
-        /**
-         * Creates from a instance state.
-         */
-        public UserSelection (Bundle icicle) {
-            init(icicle.getStringArray(SELECTED_UNKNOWN_PHONES_KEY),
-                    icicle.getLongArray(SELECTED_PHONE_IDS_KEY));
-        }
-
-        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);
-
-            }
-        }
-
-        private void init(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);
-                }
-            }
-        }
-
-        private void init(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 = mAdapter.getCursor();
-                if (cursor != null) {
-                    int backupPos = cursor.getPosition();
-                    cursor.moveToPosition(-1);
-                    while (cursor.moveToNext()) {
-                        setPhoneSelected(cursor.getLong(PHONE_ID_COLUMN_INDEX), true);
-                    }
-                    cursor.moveToPosition(backupPos);
-                }
-                for (String number : mPhoneNumberAdapter.getFilteredPhoneNumbers()) {
-                    setPhoneSelected(number, true);
-                }
-            } else {
-                mSelectedPhoneIds.clear();
-                mSelectedPhoneNumbers.clear();
-            }
-        }
-
-        public boolean isAllSelected() {
-            return selectedCount() == mPhoneNumberAdapter.getFilteredPhoneNumbers().size()
-                    + 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 = 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());
-        }
-    }
 }
diff --git a/src/com/android/contacts/JoinContactActivity.java b/src/com/android/contacts/JoinContactActivity.java
index d34350a..58a14a6 100644
--- a/src/com/android/contacts/JoinContactActivity.java
+++ b/src/com/android/contacts/JoinContactActivity.java
@@ -333,7 +333,8 @@
             return superCount;
         }
 
-        private int getRealPosition(int pos) {
+        @Override
+        protected int getRealPosition(int pos) {
             if (mSuggestionsCursorCount != 0) {
                 // When showing suggestions, we have 2 additional list items: the "Suggestions"
                 // and "All contacts" separators.
diff --git a/src/com/android/contacts/MultiplePhonePickerActivity.java b/src/com/android/contacts/MultiplePhonePickerActivity.java
new file mode 100644
index 0000000..549fde8
--- /dev/null
+++ b/src/com/android/contacts/MultiplePhonePickerActivity.java
@@ -0,0 +1,455 @@
+/*
+ * 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;
+
+import com.android.contacts.list.ContactItemListAdapter;
+import com.android.contacts.list.MultiplePhoneExtraAdapter;
+import com.android.contacts.list.MultiplePhonePickerAdapter;
+import com.android.contacts.list.MultiplePhoneSelection;
+
+import android.app.ProgressDialog;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+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.ProviderStatus;
+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 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 {
+    /**
+     * 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;
+
+    /**
+     * Display only selected recipients or not in MODE_PICK_MULTIPLE_PHONES mode
+     */
+    public boolean mShowSelectedOnly = false;
+
+    public OnClickListener mCheckBoxClickerListener = new OnClickListener () {
+        public void onClick(View v) {
+            final ContactListItemCache cache = (ContactListItemCache) v.getTag();
+            if (cache.phoneId != MultiplePhoneExtraAdapter.INVALID_PHONE_ID) {
+                mUserSelection.setPhoneSelected(cache.phoneId, ((CheckBox) v).isChecked());
+            } else {
+                mUserSelection.setPhoneSelected(cache.phoneNumber,
+                        ((CheckBox) v).isChecked());
+            }
+            updateWidgets(true);
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        initMultiPicker(getIntent());
+    }
+
+    @Override
+    protected ContactItemListAdapter createListAdapter() {
+        return new MultiplePhonePickerAdapter(this, mPhoneNumberAdapter);
+    }
+
+    @Override
+    public void initContentView() {
+        super.initContentView();
+        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);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public void onClick(View v) {
+        int id = v.getId();
+        switch (id) {
+            case R.id.done:
+                setMultiPickerResult();
+                finish();
+                break;
+            case R.id.revert:
+                finish();
+                break;
+        }
+    }
+
+    @Override
+    protected void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+        if (mList != null) {
+            if (mUserSelection != null) {
+                mUserSelection.saveInstanceState(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);
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        super.onCreateOptionsMenu(menu);
+
+        final MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.pick, menu);
+        return true;
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        if (mShowSelectedOnly) {
+            menu.findItem(R.id.menu_display_selected).setVisible(false);
+            menu.findItem(R.id.menu_display_all).setVisible(true);
+            menu.findItem(R.id.menu_select_all).setVisible(false);
+            menu.findItem(R.id.menu_select_none).setVisible(false);
+            return true;
+        }
+        menu.findItem(R.id.menu_display_all).setVisible(false);
+        menu.findItem(R.id.menu_display_selected).setVisible(true);
+        if (mUserSelection.isAllSelected()) {
+            menu.findItem(R.id.menu_select_all).setVisible(false);
+            menu.findItem(R.id.menu_select_none).setVisible(true);
+        } else {
+            menu.findItem(R.id.menu_select_all).setVisible(true);
+            menu.findItem(R.id.menu_select_none).setVisible(false);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case R.id.menu_select_all: {
+                mUserSelection.setAllPhonesSelected(true);
+                checkAll(true);
+                updateWidgets(true);
+                return true;
+            }
+            case R.id.menu_select_none: {
+                mUserSelection.setAllPhonesSelected(false);
+                checkAll(false);
+                updateWidgets(true);
+                return true;
+            }
+            case R.id.menu_display_selected: {
+                mShowSelectedOnly = true;
+                startQuery();
+                return true;
+            }
+            case R.id.menu_display_all: {
+                mShowSelectedOnly = false;
+                startQuery();
+                return true;
+            }
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+            boolean globalSearch) {
+        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);
+                }
+            }
+        }
+    }
+
+    @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
+    public Cursor doFilter(String filter) {
+        String[] projection = getProjectionForQuery();
+        if (mSearchMode && TextUtils.isEmpty(getTextFilter())) {
+            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));
+        }
+    }
+
+    private void checkAll(boolean checked) {
+        // TODO fix this. It should iterate over the cursor rather than the views in the list.
+        /*
+        final ListView listView = getListView();
+        int childCount = listView.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final ContactListItemView child = (ContactListItemView)listView.getChildAt(i);
+            child.getCheckBoxView().setChecked(checked);
+        }
+        */
+    }
+}
diff --git a/src/com/android/contacts/list/ContactItemListAdapter.java b/src/com/android/contacts/list/ContactItemListAdapter.java
index 28a3e9f..96b265c 100644
--- a/src/com/android/contacts/list/ContactItemListAdapter.java
+++ b/src/com/android/contacts/list/ContactItemListAdapter.java
@@ -32,7 +32,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.AbsListView;
-import android.widget.CheckBox;
 import android.widget.CursorAdapter;
 import android.widget.Filter;
 import android.widget.ImageView;
@@ -48,10 +47,10 @@
     private final ContactsListActivity contactsListActivity;
     private SectionIndexer mIndexer;
     private boolean mLoading = true;
-    private CharSequence mUnknownNameText;
-    private boolean mDisplayPhotos = false;
+    protected CharSequence mUnknownNameText;
+    protected boolean mDisplayPhotos = false;
     private boolean mDisplayCallButton = false;
-    private boolean mDisplayAdditionalData = true;
+    protected boolean mDisplayAdditionalData = true;
     private int mFrequentSeparatorPos = ListView.INVALID_POSITION;
     private boolean mDisplaySectionHeaders = true;
 
@@ -164,10 +163,6 @@
             // We don't want the separator view to be recycled.
             return IGNORE_ITEM_VIEW_TYPE;
         }
-        if (contactsListActivity.mMode == ContactsListActivity.MODE_PICK_MULTIPLE_PHONES
-                && position < contactsListActivity.mPhoneNumberAdapter.getCount()) {
-            return contactsListActivity.mPhoneNumberAdapter.getItemViewType(position);
-        }
         return super.getItemViewType(position);
     }
 
@@ -204,12 +199,6 @@
             return view;
         }
 
-        // Check whether this view should be retrieved from mPhoneNumberAdapter
-        if (contactsListActivity.mMode == ContactsListActivity.MODE_PICK_MULTIPLE_PHONES
-                && position < contactsListActivity.mPhoneNumberAdapter.getCount()) {
-            return contactsListActivity.mPhoneNumberAdapter.getView(position, convertView, parent);
-        }
-
         int realPosition = getRealPosition(position);
         if (!mCursor.moveToPosition(realPosition)) {
             throw new IllegalStateException("couldn't move cursor to position " + position);
@@ -271,7 +260,6 @@
     public View newView(Context context, Cursor cursor, ViewGroup parent) {
         final ContactListItemView view = new ContactListItemView(context, null);
         view.setOnCallButtonClickListener(contactsListActivity);
-        view.setOnCheckBoxClickListener(contactsListActivity.mCheckBoxClickerListener);
         view.setTag(new ContactsListActivity.ContactListItemCache());
         return view;
     }
@@ -334,17 +322,6 @@
             }
         }
 
-        if (contactsListActivity.mMode == ContactsListActivity.MODE_PICK_MULTIPLE_PHONES) {
-            cache.phoneId =
-                Long.valueOf(cursor.getLong(ContactsListActivity.PHONE_ID_COLUMN_INDEX));
-            CheckBox checkBox = view.getCheckBoxView();
-            checkBox.setChecked(contactsListActivity.mUserSelection.isSelected(cache.phoneId));
-            checkBox.setTag(cache);
-            int color = contactsListActivity.getChipColor(cursor
-                    .getLong(ContactsListActivity.PHONE_CONTACT_ID_COLUMN_INDEX));
-            view.getChipView().setBackgroundResource(color);
-        }
-
         // Set the name
         cursor.copyStringToBuffer(nameColumnIndex, cache.nameBuffer);
         TextView nameView = view.getNameTextView();
@@ -508,7 +485,7 @@
      * Computes the span of the display name that has highlighted parts and configures
      * the display name text view accordingly.
      */
-    private void buildDisplayNameWithHighlighting(TextView textView, Cursor cursor,
+    protected void buildDisplayNameWithHighlighting(TextView textView, Cursor cursor,
             CharArrayBuffer buffer1, CharArrayBuffer buffer2,
             TextWithHighlighting textWithHighlighting) {
         int oppositeDisplayOrderColumnIndex;
@@ -584,28 +561,28 @@
         }
 
         if (contactsListActivity.mEmptyView != null && (cursor == null || cursor.getCount() == 0)) {
-            contactsListActivity.mEmptyView.show(contactsListActivity.mSearchMode,
-                    contactsListActivity.mDisplayOnlyPhones,
-                    contactsListActivity.mMode == ContactsListActivity.MODE_STREQUENT
-                    || contactsListActivity.mMode == ContactsListActivity.MODE_STARRED,
-                    contactsListActivity.mMode == ContactsListActivity.MODE_QUERY
-                    || contactsListActivity.mMode == ContactsListActivity.MODE_QUERY_PICK
-                    || contactsListActivity.mMode == ContactsListActivity.MODE_QUERY_PICK_PHONE
-                    || contactsListActivity.mMode == ContactsListActivity.MODE_QUERY_PICK_TO_VIEW
-                    || contactsListActivity.mMode == ContactsListActivity.MODE_QUERY_PICK_TO_EDIT,
-                    contactsListActivity.mShortcutAction != null,
-                    contactsListActivity.mMode == ContactsListActivity.MODE_PICK_MULTIPLE_PHONES,
-                    contactsListActivity.mShowSelectedOnly);
+            prepareEmptyView();
         }
 
         super.changeCursor(cursor);
 
         // Update the indexer for the fast scroll widget
         updateIndexer(cursor);
+    }
 
-        if (contactsListActivity.mMode == ContactsListActivity.MODE_PICK_MULTIPLE_PHONES) {
-            contactsListActivity.updateChipColor(cursor);
-        }
+    protected void prepareEmptyView() {
+        contactsListActivity.mEmptyView.show(contactsListActivity.mSearchMode,
+                contactsListActivity.mDisplayOnlyPhones,
+                contactsListActivity.mMode == ContactsListActivity.MODE_STREQUENT
+                || contactsListActivity.mMode == ContactsListActivity.MODE_STARRED,
+                contactsListActivity.mMode == ContactsListActivity.MODE_QUERY
+                || contactsListActivity.mMode == ContactsListActivity.MODE_QUERY_PICK
+                || contactsListActivity.mMode == ContactsListActivity.MODE_QUERY_PICK_PHONE
+                || contactsListActivity.mMode == ContactsListActivity.MODE_QUERY_PICK_TO_VIEW
+                || contactsListActivity.mMode == ContactsListActivity.MODE_QUERY_PICK_TO_EDIT,
+                contactsListActivity.mShortcutAction != null,
+                false,
+                false);
     }
 
     private void updateIndexer(Cursor cursor) {
@@ -702,10 +679,6 @@
             superCount++;
         }
 
-        if (contactsListActivity.mMode == ContactsListActivity.MODE_PICK_MULTIPLE_PHONES) {
-            superCount += contactsListActivity.mPhoneNumberAdapter.getCount();
-        }
-
         if (mFrequentSeparatorPos != ListView.INVALID_POSITION) {
             // When showing strequent list, we have an additional list item - the separator.
             return superCount + 1;
@@ -721,7 +694,7 @@
         return super.getCount();
     }
 
-    private int getRealPosition(int pos) {
+    protected int getRealPosition(int pos) {
         if (contactsListActivity.mShowNumberOfContacts) {
             pos--;
         }
@@ -731,10 +704,6 @@
             return pos - 1;
         }
 
-        if (contactsListActivity.mMode == ContactsListActivity.MODE_PICK_MULTIPLE_PHONES) {
-            pos -= contactsListActivity.mPhoneNumberAdapter.getCount();
-        }
-
         if (mFrequentSeparatorPos == ListView.INVALID_POSITION) {
             // No separator, identity map
             return pos;
diff --git a/src/com/android/contacts/list/MultiplePhoneExtraAdapter.java b/src/com/android/contacts/list/MultiplePhoneExtraAdapter.java
new file mode 100644
index 0000000..09fc0db
--- /dev/null
+++ b/src/com/android/contacts/list/MultiplePhoneExtraAdapter.java
@@ -0,0 +1,183 @@
+/*
+ * 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.ContactListItemView;
+import com.android.contacts.MultiplePhonePickerActivity;
+import com.android.contacts.R;
+import com.android.contacts.ContactsListActivity.ContactListItemCache;
+
+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 && convertView.getTag() != null &&
+                    convertView.getTag() instanceof ContactListItemCache) {
+                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) {
+        ContactListItemView itemView = (ContactListItemView) view;
+        itemView.setDividerVisible(true);
+        itemView.setSectionHeader(null);
+        itemView.setLabel(null);
+        itemView.setData(null, 0);
+        itemView.removePhotoView();
+
+        final ContactListItemCache cache = (ContactListItemCache) view.getTag();
+        itemView.getNameTextView().setText(label);
+        CheckBox checkBox = itemView.getCheckBoxView();
+        checkBox.setChecked(mSelection.isSelected(label));
+        itemView.getChipView().setBackgroundResource(0);
+        cache.phoneId = INVALID_PHONE_ID;
+        cache.phoneNumber = label;
+        checkBox.setTag(cache);
+    }
+
+    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
new file mode 100644
index 0000000..8451526
--- /dev/null
+++ b/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
@@ -0,0 +1,205 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+
+package com.android.contacts.list;
+
+import com.android.contacts.ContactListItemView;
+import com.android.contacts.ContactsListActivity;
+import com.android.contacts.MultiplePhonePickerActivity;
+import com.android.contacts.ContactsListActivity.ContactListItemCache;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+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 {
+
+    private final MultiplePhonePickerActivity mMultiplePhonePickerActivity;
+    private final MultiplePhoneExtraAdapter mExtraAdapter;
+
+    public MultiplePhonePickerAdapter(MultiplePhonePickerActivity multiplePhonePickerActivity,
+            MultiplePhoneExtraAdapter extraAdapter) {
+        super(multiplePhonePickerActivity);
+        this.mMultiplePhonePickerActivity = multiplePhonePickerActivity;
+        this.mExtraAdapter = extraAdapter;
+    }
+
+    @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);
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (position == 0 && mMultiplePhonePickerActivity.mShowNumberOfContacts) {
+            return super.getView(position, convertView, parent);
+        }
+
+        if (position < mExtraAdapter.getCount()) {
+            return mExtraAdapter.getView(position,
+                    convertView, parent);
+        }
+        return super.getView(position, convertView, parent);
+    }
+
+    @Override
+    public View newView(Context context, Cursor cursor, ViewGroup parent) {
+        final ContactListItemView view = new ContactListItemView(context, null);
+        view.setOnCallButtonClickListener(mMultiplePhonePickerActivity);
+        view.setOnCheckBoxClickListener(mMultiplePhonePickerActivity.mCheckBoxClickerListener);
+        view.setTag(new MultiplePhonePickerActivity.ContactListItemCache());
+        return view;
+    }
+
+    @Override
+    public void bindView(View itemView, Context context, Cursor cursor) {
+        final ContactListItemView view = (ContactListItemView)itemView;
+        final ContactListItemCache cache = (ContactListItemCache)view.getTag();
+
+        int typeColumnIndex;
+        int dataColumnIndex;
+        int labelColumnIndex;
+        int defaultType;
+        int nameColumnIndex;
+        int phoneticNameColumnIndex;
+        int photoColumnIndex = ContactsListActivity.SUMMARY_PHOTO_ID_COLUMN_INDEX;
+        boolean displayAdditionalData = mDisplayAdditionalData;
+        boolean highlightingEnabled = false;
+        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;
+
+        cache.phoneId = Long.valueOf(cursor.getLong(ContactsListActivity.PHONE_ID_COLUMN_INDEX));
+        CheckBox checkBox = view.getCheckBoxView();
+        checkBox.setChecked(mMultiplePhonePickerActivity.mUserSelection
+                .isSelected(cache.phoneId));
+        checkBox.setTag(cache);
+        int color = mMultiplePhonePickerActivity.getChipColor(cursor
+                .getLong(ContactsListActivity.PHONE_CONTACT_ID_COLUMN_INDEX));
+        view.getChipView().setBackgroundResource(color);
+
+        // Set the name
+        cursor.copyStringToBuffer(nameColumnIndex, cache.nameBuffer);
+        TextView nameView = view.getNameTextView();
+        int size = cache.nameBuffer.sizeCopied;
+        if (size != 0) {
+            if (highlightingEnabled) {
+                if (cache.textWithHighlighting == null) {
+                    cache.textWithHighlighting =
+                            mMultiplePhonePickerActivity.mHighlightingAnimation
+                                    .createTextWithHighlighting();
+                }
+                buildDisplayNameWithHighlighting(nameView, cursor, cache.nameBuffer,
+                        cache.highlightedTextBuffer, cache.textWithHighlighting);
+            } else {
+                nameView.setText(cache.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();
+            mMultiplePhonePickerActivity.mPhotoLoader.loadPhoto(viewToUse, photoId);
+        }
+
+        if (!displayAdditionalData) {
+            if (phoneticNameColumnIndex != -1) {
+
+                // Set the name
+                cursor.copyStringToBuffer(phoneticNameColumnIndex, cache.phoneticNameBuffer);
+                int phoneticNameSize = cache.phoneticNameBuffer.sizeCopied;
+                if (phoneticNameSize != 0) {
+                    view.setLabel(cache.phoneticNameBuffer.data, phoneticNameSize);
+                } else {
+                    view.setLabel(null);
+                }
+            } else {
+                view.setLabel(null);
+            }
+            return;
+        }
+
+        // Set the data.
+        cursor.copyStringToBuffer(dataColumnIndex, cache.dataBuffer);
+
+        size = cache.dataBuffer.sizeCopied;
+        view.setData(cache.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);
+        }
+    }
+
+    @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);
+    }
+
+    @Override
+    public int getCount() {
+        if (!mDataValid) {
+            return 0;
+        }
+
+        int count = super.getCount();
+        count += mExtraAdapter.getCount();
+        return count;
+    }
+
+    @Override
+    protected int getRealPosition(int pos) {
+        return pos - mExtraAdapter.getCount();
+    }
+}
diff --git a/src/com/android/contacts/list/MultiplePhoneSelection.java b/src/com/android/contacts/list/MultiplePhoneSelection.java
new file mode 100644
index 0000000..e9249e4
--- /dev/null
+++ b/src/com/android/contacts/list/MultiplePhoneSelection.java
@@ -0,0 +1,230 @@
+/*
+ * 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/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
index 7f4919d..d6b9cac 100644
--- a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
+++ b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
@@ -53,6 +53,8 @@
             "com.android.contacts.ContactsListActivity";
     private static final String SEARCH_RESULTS_ACTIVITY_CLASS_NAME =
             "com.android.contacts.SearchResultsActivity";
+    private static final String MULTIPLE_PHONE_PICKER_ACTIVITY_CLASS_NAME =
+        "com.android.contacts.MultiplePhonePickerActivity";
 
     private static final int LIST_DEFAULT = 0;
     private static final int LIST_ALL_CONTACTS_ACTION = 1;
@@ -356,7 +358,10 @@
             case ACTION_GET_MULTIPLE_PHONES: {
                 Intent intent = new Intent(Intents.ACTION_GET_MULTIPLE_PHONES);
                 intent.setType(Phone.CONTENT_TYPE);
-                startContactsListActivityForResult(intent);
+                intent.putExtra(Intents.EXTRA_PHONE_URIS, new Uri[] {
+                        Uri.parse("tel:555-1212"), Uri.parse("tel:555-2121")
+                });
+                startMultiplePhoneSelectionActivityForResult(intent);
                 break;
             }
         }
@@ -395,6 +400,13 @@
         startActivity(intent);
     }
 
+    private void startMultiplePhoneSelectionActivityForResult(Intent intent) {
+        intent.setComponent(
+                new ComponentName(ANDROID_CONTACTS_PACKAGE,
+                        MULTIPLE_PHONE_PICKER_ACTIVITY_CLASS_NAME));
+        startActivityForResult(intent, 13);
+    }
+
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         Intent intent = new Intent(this, ResultActivity.class);