Provide a picker for third parties

Also fix a bug where custom labels wouldn't be shown for addresses

Bug:3378785
Change-Id: Iaafdc44fdcd67b878b80218976d8b94b529e8aeb
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ec0709f..cacecf6 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -281,6 +281,7 @@
                 <data android:mimeType="vnd.android.cursor.dir/phone" />
                 <data android:mimeType="vnd.android.cursor.dir/postal-address_v2" />
                 <data android:mimeType="vnd.android.cursor.dir/postal-address" />
+                <data android:mimeType="vnd.android.cursor.dir/email_v2" />
             </intent-filter>
 
             <intent-filter>
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index 4efc43f..c255ba1 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -23,7 +23,9 @@
 import com.android.contacts.list.ContactsIntentResolver;
 import com.android.contacts.list.ContactsRequest;
 import com.android.contacts.list.DirectoryListLoader;
+import com.android.contacts.list.EmailAddressPickerFragment;
 import com.android.contacts.list.OnContactPickerActionListener;
+import com.android.contacts.list.OnEmailAddressPickerActionListener;
 import com.android.contacts.list.OnPhoneNumberPickerActionListener;
 import com.android.contacts.list.OnPostalAddressPickerActionListener;
 import com.android.contacts.list.PhoneNumberPickerFragment;
@@ -171,6 +173,11 @@
                 break;
             }
 
+            case ContactsRequest.ACTION_PICK_EMAIL: {
+                setTitle(R.string.contactPickerActivityTitle);
+                break;
+            }
+
             case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
                 setTitle(R.string.callShortcutActivityTitle);
                 break;
@@ -236,6 +243,11 @@
                 break;
             }
 
+            case ContactsRequest.ACTION_PICK_EMAIL: {
+                mListFragment = new EmailAddressPickerFragment();
+                break;
+            }
+
             case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
                 PhoneNumberPickerFragment fragment = new PhoneNumberPickerFragment();
                 fragment.setShortcutAction(Intent.ACTION_CALL);
@@ -284,6 +296,9 @@
         } else if (mListFragment instanceof PostalAddressPickerFragment) {
             ((PostalAddressPickerFragment) mListFragment).setOnPostalAddressPickerActionListener(
                     new PostalAddressPickerActionListener());
+        } else if (mListFragment instanceof EmailAddressPickerFragment) {
+            ((EmailAddressPickerFragment) mListFragment).setOnEmailAddressPickerActionListener(
+                    new EmailAddressPickerActionListener());
         } else {
             throw new IllegalStateException("Unsupported list fragment type: " + mListFragment);
         }
@@ -334,6 +349,14 @@
         }
     }
 
+    private final class EmailAddressPickerActionListener implements
+            OnEmailAddressPickerActionListener {
+        @Override
+        public void onPickEmailAddressAction(Uri dataUri) {
+            returnPickerResult(dataUri);
+        }
+    }
+
     public void startActivityAndForwardResult(final Intent intent) {
         intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
 
diff --git a/src/com/android/contacts/list/ContactsIntentResolver.java b/src/com/android/contacts/list/ContactsIntentResolver.java
index afe29df..3ef68d8 100644
--- a/src/com/android/contacts/list/ContactsIntentResolver.java
+++ b/src/com/android/contacts/list/ContactsIntentResolver.java
@@ -27,6 +27,7 @@
 import android.provider.Contacts.ContactMethods;
 import android.provider.Contacts.People;
 import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.Contacts;
@@ -95,6 +96,8 @@
             } else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(resolvedType)) {
                 request.setActionCode(ContactsRequest.ACTION_PICK_POSTAL);
                 request.setLegacyCompatibilityMode(true);
+            } else if (Email.CONTENT_TYPE.equals(resolvedType)) {
+                request.setActionCode(ContactsRequest.ACTION_PICK_EMAIL);
             }
         } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
             String component = intent.getComponent().getClassName();
diff --git a/src/com/android/contacts/list/ContactsRequest.java b/src/com/android/contacts/list/ContactsRequest.java
index aefa451..e20d189 100644
--- a/src/com/android/contacts/list/ContactsRequest.java
+++ b/src/com/android/contacts/list/ContactsRequest.java
@@ -62,6 +62,9 @@
     /** Show all postal addresses and pick them when clicking */
     public static final int ACTION_PICK_POSTAL = 100;
 
+    /** Show all postal addresses and pick them when clicking */
+    public static final int ACTION_PICK_EMAIL = 105;
+
     /** Show all contacts and create a shortcut for the picked contact */
     public static final int ACTION_CREATE_SHORTCUT_CONTACT = 110;
 
diff --git a/src/com/android/contacts/list/EmailAddressListAdapter.java b/src/com/android/contacts/list/EmailAddressListAdapter.java
new file mode 100644
index 0000000..96c69f9
--- /dev/null
+++ b/src/com/android/contacts/list/EmailAddressListAdapter.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.ContactCounts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A cursor adapter for the {@link Email#CONTENT_TYPE} content type.
+ */
+public class EmailAddressListAdapter extends ContactEntryListAdapter {
+
+    static final String[] EMAILS_PROJECTION = new String[] {
+        Email._ID,                       // 0
+        Email.TYPE,                      // 1
+        Email.LABEL,                     // 2
+        Email.DATA,                      // 3
+        Email.DISPLAY_NAME_PRIMARY,      // 4
+        Email.DISPLAY_NAME_ALTERNATIVE,  // 5
+        Email.PHOTO_ID,                  // 6
+    };
+
+    protected static final int EMAIL_ID_COLUMN_INDEX = 0;
+    protected static final int EMAIL_TYPE_COLUMN_INDEX = 1;
+    protected static final int EMAIL_LABEL_COLUMN_INDEX = 2;
+    protected static final int EMAIL_ADDRESS_COLUMN_INDEX = 3;
+    protected static final int EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX = 4;
+    protected static final int EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX = 5;
+    protected static final int EMAIL_PHOTO_ID_COLUMN_INDEX = 6;
+
+    private CharSequence mUnknownNameText;
+    private int mDisplayNameColumnIndex;
+    private int mAlternativeDisplayNameColumnIndex;
+
+    public EmailAddressListAdapter(Context context) {
+        super(context);
+
+        mUnknownNameText = context.getText(android.R.string.unknownName);
+    }
+
+    @Override
+    public void configureLoader(CursorLoader loader, long directoryId) {
+        final Builder builder;
+        if (isSearchMode()) {
+            builder = Email.CONTENT_FILTER_URI.buildUpon();
+            String query = getQueryString();
+            builder.appendPath(TextUtils.isEmpty(query) ? "" : query);
+        } else {
+            builder = Email.CONTENT_URI.buildUpon();
+        }
+        builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                String.valueOf(directoryId));
+        applyDataRestriction(builder);
+        loader.setUri(builder.build());
+        loader.setProjection(EMAILS_PROJECTION);
+
+        if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+            loader.setSortOrder(Email.SORT_KEY_PRIMARY);
+        } else {
+            loader.setSortOrder(Email.SORT_KEY_ALTERNATIVE);
+        }
+    }
+
+    protected static Builder buildSectionIndexerUri(Uri uri) {
+        return uri.buildUpon()
+                .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true");
+    }
+
+    @Override
+    public String getContactDisplayName(int position) {
+        return ((Cursor)getItem(position)).getString(mDisplayNameColumnIndex);
+    }
+
+    @Override
+    public void setContactNameDisplayOrder(int displayOrder) {
+        super.setContactNameDisplayOrder(displayOrder);
+        if (getContactNameDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+            mDisplayNameColumnIndex = EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX;
+            mAlternativeDisplayNameColumnIndex = EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX;
+        } else {
+            mDisplayNameColumnIndex = EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX;
+            mAlternativeDisplayNameColumnIndex = EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX;
+        }
+    }
+
+    /**
+     * Builds a {@link Data#CONTENT_URI} for the current cursor
+     * position.
+     */
+    public Uri getDataUri(int position) {
+        long id = ((Cursor)getItem(position)).getLong(EMAIL_ID_COLUMN_INDEX);
+        return ContentUris.withAppendedId(Data.CONTENT_URI, id);
+    }
+
+    @Override
+    protected View newView(Context context, int partition, Cursor cursor, int position,
+            ViewGroup parent) {
+        final ContactListItemView view = new ContactListItemView(context, null);
+        view.setUnknownNameText(mUnknownNameText);
+        view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
+        view.setQuickContactEnabled(isQuickContactEnabled());
+        return view;
+    }
+
+    @Override
+    protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+        ContactListItemView view = (ContactListItemView)itemView;
+        bindSectionHeaderAndDivider(view, position);
+        bindName(view, cursor);
+        bindPhoto(view, cursor);
+        bindEmailAddress(view, cursor);
+    }
+
+    protected void bindEmailAddress(ContactListItemView view, Cursor cursor) {
+        CharSequence label = null;
+        if (!cursor.isNull(EMAIL_TYPE_COLUMN_INDEX)) {
+            final int type = cursor.getInt(EMAIL_TYPE_COLUMN_INDEX);
+            final String customLabel = cursor.getString(EMAIL_LABEL_COLUMN_INDEX);
+
+            // TODO cache
+            label = Email.getTypeLabel(getContext().getResources(), type, customLabel);
+        }
+        view.setLabel(label);
+        view.showData(cursor, EMAIL_ADDRESS_COLUMN_INDEX);
+    }
+
+    protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
+        final int section = getSectionForPosition(position);
+        if (getPositionForSection(section) == position) {
+            String title = (String)getSections()[section];
+            view.setSectionHeader(title);
+        } else {
+            view.setDividerVisible(false);
+            view.setSectionHeader(null);
+        }
+
+        // move the divider for the last item in a section
+        if (getPositionForSection(section + 1) - 1 == position) {
+            view.setDividerVisible(false);
+        } else {
+            view.setDividerVisible(true);
+        }
+    }
+
+    protected void bindName(final ContactListItemView view, Cursor cursor) {
+        view.showDisplayName(cursor, mDisplayNameColumnIndex, isNameHighlightingEnabled(),
+                mAlternativeDisplayNameColumnIndex);
+//        view.showPhoneticName(cursor, PHONE_PHONETIC_NAME_COLUMN_INDEX);
+    }
+
+    protected void bindPhoto(final ContactListItemView view, Cursor cursor) {
+        long photoId = 0;
+        if (!cursor.isNull(EMAIL_PHOTO_ID_COLUMN_INDEX)) {
+            photoId = cursor.getLong(EMAIL_PHOTO_ID_COLUMN_INDEX);
+        }
+
+        getPhotoLoader().loadPhoto(view.getPhotoView(), photoId);
+    }
+//
+//    protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
+//        view.showSnippet(cursor, SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX,
+//                SUMMARY_SNIPPET_DATA1_COLUMN_INDEX, SUMMARY_SNIPPET_DATA4_COLUMN_INDEX);
+//    }
+
+}
diff --git a/src/com/android/contacts/list/EmailAddressPickerFragment.java b/src/com/android/contacts/list/EmailAddressPickerFragment.java
new file mode 100644
index 0000000..168e135
--- /dev/null
+++ b/src/com/android/contacts/list/EmailAddressPickerFragment.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.list;
+
+import com.android.contacts.R;
+
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Fragment containing an email list for picking.
+ */
+public class EmailAddressPickerFragment extends ContactEntryListFragment<ContactEntryListAdapter> {
+    private OnEmailAddressPickerActionListener mListener;
+
+    public EmailAddressPickerFragment() {
+        setQuickContactEnabled(false);
+        setPhotoLoaderEnabled(true);
+        setSectionHeaderDisplayEnabled(true);
+        setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DATA_SHORTCUT);
+    }
+
+    public void setOnEmailAddressPickerActionListener(OnEmailAddressPickerActionListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    protected void onItemClick(int position, long id) {
+        EmailAddressListAdapter adapter = (EmailAddressListAdapter)getAdapter();
+        pickEmailAddress(adapter.getDataUri(position));
+    }
+
+    @Override
+    protected ContactEntryListAdapter createListAdapter() {
+        EmailAddressListAdapter adapter = new EmailAddressListAdapter(getActivity());
+        adapter.setSectionHeaderDisplayEnabled(true);
+        adapter.setDisplayPhotos(true);
+        return adapter;
+    }
+
+    @Override
+    protected View inflateView(LayoutInflater inflater, ViewGroup container) {
+        return inflater.inflate(R.layout.contacts_list_content, null);
+    }
+
+    private void pickEmailAddress(Uri uri) {
+        mListener.onPickEmailAddressAction(uri);
+    }
+}
diff --git a/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java b/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java
new file mode 100644
index 0000000..e785323
--- /dev/null
+++ b/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.list;
+
+import android.net.Uri;
+
+/**
+ * Action callbacks that can be sent by a email address picker.
+ */
+public interface OnEmailAddressPickerActionListener  {
+
+    /**
+     * Returns the selected phone number to the requester.
+     */
+    void onPickEmailAddressAction(Uri dataUri);
+}
diff --git a/src/com/android/contacts/list/PostalAddressListAdapter.java b/src/com/android/contacts/list/PostalAddressListAdapter.java
index e622ec6..8b3c75d 100644
--- a/src/com/android/contacts/list/PostalAddressListAdapter.java
+++ b/src/com/android/contacts/list/PostalAddressListAdapter.java
@@ -131,7 +131,7 @@
             final String customLabel = cursor.getString(POSTAL_LABEL_COLUMN_INDEX);
 
             // TODO cache
-            label = StructuredPostal.getTypeLabel(getContext().getResources(), type, label);
+            label = StructuredPostal.getTypeLabel(getContext().getResources(), type, customLabel);
         }
         view.setLabel(label);
         view.showData(cursor, POSTAL_ADDRESS_COLUMN_INDEX);
diff --git a/src/com/android/contacts/list/PostalAddressPickerFragment.java b/src/com/android/contacts/list/PostalAddressPickerFragment.java
index f14b718..5f7ca56 100644
--- a/src/com/android/contacts/list/PostalAddressPickerFragment.java
+++ b/src/com/android/contacts/list/PostalAddressPickerFragment.java
@@ -73,7 +73,7 @@
         return inflater.inflate(R.layout.contacts_list_content, null);
     }
 
-    public void pickPostalAddress(Uri uri) {
+    private void pickPostalAddress(Uri uri) {
         mListener.onPickPostalAddressAction(uri);
     }
 }
diff --git a/tests/res/values/donottranslate_strings.xml b/tests/res/values/donottranslate_strings.xml
index 8557fd6..bd272c3 100644
--- a/tests/res/values/donottranslate_strings.xml
+++ b/tests/res/values/donottranslate_strings.xml
@@ -32,6 +32,7 @@
         <item>ACTION_PICK: phone (legacy)</item>
         <item>ACTION_PICK: postal</item>
         <item>ACTION_PICK: postal (legacy)</item>
+        <item>ACTION_PICK: e-mail</item>
         <item>ACTION_CREATE_SHORTCUT: contact</item>
         <item>ACTION_CREATE_SHORTCUT: dial</item>
         <item>ACTION_CREATE_SHORTCUT: message</item>
diff --git a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
index 50a1f1f..03b6302 100644
--- a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
+++ b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
@@ -73,6 +73,7 @@
         ACTION_PICK_PHONE_LEGACY,
         ACTION_PICK_POSTAL,
         ACTION_PICK_POSTAL_LEGACY,
+        ACTION_PICK_EMAIL,
         ACTION_CREATE_SHORTCUT_CONTACT,
         ACTION_CREATE_SHORTCUT_DIAL,
         ACTION_CREATE_SHORTCUT_MESSAGE,
@@ -195,6 +196,11 @@
                 startContactSelectionActivityForResult(intent);
                 break;
             }
+            case ACTION_PICK_EMAIL: {
+                startContactSelectionActivityForResult(
+                        new Intent(Intent.ACTION_PICK, Email.CONTENT_URI));
+                break;
+            }
             case ACTION_CREATE_SHORTCUT_CONTACT: {
                 Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
                 startContactSelectionActivityForResult(intent);