auto import from //branches/cupcake_rel/...@140373
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 012a33e..974fc05 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -166,19 +166,19 @@
                 String callText = null;
                 switch (callType) {
                     case Calls.INCOMING_TYPE:
-                        mCallTypeIcon.setImageResource(android.R.drawable.sym_call_incoming);
+                        mCallTypeIcon.setImageResource(R.drawable.ic_call_log_header_incoming_call);
                         mCallType.setText(R.string.type_incoming);
                         callText = getString(R.string.callBack);
                         break;
     
                     case Calls.OUTGOING_TYPE:
-                        mCallTypeIcon.setImageResource(android.R.drawable.sym_call_outgoing);
+                        mCallTypeIcon.setImageResource(R.drawable.ic_call_log_header_outgoing_call);
                         mCallType.setText(R.string.type_outgoing);
                         callText = getString(R.string.callAgain);
                         break;
     
                     case Calls.MISSED_TYPE:
-                        mCallTypeIcon.setImageResource(android.R.drawable.sym_call_missed);
+                        mCallTypeIcon.setImageResource(R.drawable.ic_call_log_header_missed_call);
                         mCallType.setText(R.string.type_missed);
                         callText = getString(R.string.returnCall);
                         break;
diff --git a/src/com/android/contacts/ContactsGroupSyncSelector.java b/src/com/android/contacts/ContactsGroupSyncSelector.java
index 80b5166..30aec94 100644
--- a/src/com/android/contacts/ContactsGroupSyncSelector.java
+++ b/src/com/android/contacts/ContactsGroupSyncSelector.java
@@ -36,6 +36,8 @@
 import android.widget.ArrayAdapter;
 import android.widget.ListView;
 
+import java.util.ArrayList;
+
 public final class ContactsGroupSyncSelector extends ListActivity implements View.OnClickListener {
 
     private static final String[] PROJECTION = new String[] {
@@ -51,12 +53,12 @@
 
     private static final int SUBACTIVITY_GET_ACCOUNT = 1;
 
-    boolean[] mChecked;
+    ArrayList<Boolean> mChecked;
+    ArrayList<Long> mGroupIds;
     boolean mSyncAllGroups;
-    long[] mGroupIds;
     
     private final class GroupsAdapter extends ArrayAdapter<CharSequence> {
-        public GroupsAdapter(CharSequence[] items) {
+        public GroupsAdapter(ArrayList<CharSequence> items) {
             super(ContactsGroupSyncSelector.this,
                     android.R.layout.simple_list_item_checked,
                     android.R.id.text1, items);
@@ -94,7 +96,7 @@
     @Override
     protected void onListItemClick(ListView list, View view, int position, long id) {
         boolean isChecked = list.isItemChecked(position);
-        mChecked[position] = isChecked;
+        mChecked.set(position, isChecked);
         if (position == 0) {
             mSyncAllGroups = isChecked;
             adjustChecks();
@@ -127,11 +129,12 @@
                     Settings.setSetting(resolver, null, Settings.SYNC_EVERYTHING, "1");
                 } else {
                     ContentValues values = new ContentValues();
-                    int count = mChecked.length;
+                    int count = mChecked.size();
                     for (int i = 1; i < count; i++) {
                         values.clear();
-                        values.put(Groups.SHOULD_SYNC, mChecked[i]);
-                        resolver.update(ContentUris.withAppendedId(Groups.CONTENT_URI, mGroupIds[i]),
+                        values.put(Groups.SHOULD_SYNC, mChecked.get(i));
+                        resolver.update(
+                                ContentUris.withAppendedId(Groups.CONTENT_URI, mGroupIds.get(i)),
                                 values, null, null);
                     }
                     // For now we only support a single account and the UI doesn't know what
@@ -189,33 +192,34 @@
         Cursor cursor = resolver.query(Groups.CONTENT_URI, PROJECTION, null, null, Groups.NAME);
         if (cursor != null) {
             try {
-                int count = cursor.getCount() + 1;
-                CharSequence[] items = new String[count];
-                boolean[] checked = new boolean[count];
-                long[] groupIds = new long[count];
-    
-                int i = 0;
-                items[i++] = getString(R.string.syncAllGroups);
-                items[i++] = getString(R.string.groupNameMyContacts);
-    
+                int count = cursor.getCount() + 1; // add 1 for "sync all"
+                ArrayList<CharSequence> items = new ArrayList<CharSequence>(count);
+                ArrayList<Boolean> checked = new ArrayList<Boolean>(count);
+                ArrayList<Long> groupIds = new ArrayList<Long>(count);
+
+                // The first item in the list is always "sync all"
+                items.add(getString(R.string.syncAllGroups));
+                checked.add(mSyncAllGroups);
+                groupIds.add(Long.valueOf(0)); // dummy entry
+
                 while (cursor.moveToNext()) {
                     String name = cursor.getString(COLUMN_INDEX_NAME);
                     String systemId = cursor.isNull(COLUMN_INDEX_SYSTEM_ID) ?
                             null : cursor.getString(COLUMN_INDEX_SYSTEM_ID);
                     if (systemId == null || !Groups.GROUP_MY_CONTACTS.equals(systemId)) {
-                        items[i] = name;
-                        checked[i] = cursor.getInt(COLUMN_INDEX_SHOULD_SYNC) != 0;
-                        groupIds[i] = cursor.getLong(COLUMN_INDEX_ID);
-                        i++;
+                        items.add(name);
+                        checked.add(cursor.getInt(COLUMN_INDEX_SHOULD_SYNC) != 0);
+                        groupIds.add(cursor.getLong(COLUMN_INDEX_ID));
                     } else {
-                        checked[1] = cursor.getInt(COLUMN_INDEX_SHOULD_SYNC) != 0;
-                        groupIds[1] = cursor.getLong(COLUMN_INDEX_ID);
+                        // If My Contacts is around it wants to be the second list entry
+                        items.add(1, getString(R.string.groupNameMyContacts));
+                        checked.add(1, cursor.getInt(COLUMN_INDEX_SHOULD_SYNC) != 0);
+                        groupIds.add(1, cursor.getLong(COLUMN_INDEX_ID));
                     }
                 }
                 mChecked = checked;
-                mSyncAllGroups = getShouldSyncEverything(resolver);
-                checked[0] = mSyncAllGroups;
                 mGroupIds = groupIds;
+                mSyncAllGroups = getShouldSyncEverything(resolver);
     
                 // Setup the adapter
                 setListAdapter(new GroupsAdapter(items));
@@ -233,10 +237,10 @@
                 list.setItemChecked(i, true);
             }
         } else {
-            boolean[] checked = mChecked;
+            ArrayList<Boolean> checked = mChecked;
             int count = list.getCount();
             for (int i = 0; i < count; i++) {
-                list.setItemChecked(i, checked[i]);
+                list.setItemChecked(i, checked.get(i));
             }
         }
     }
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index b9dc4f2..5ba0ec5 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -41,12 +41,12 @@
 import android.preference.PreferenceManager;
 import android.provider.Contacts;
 import android.provider.Contacts.ContactMethods;
-import android.provider.Contacts.ContactMethodsColumns;
 import android.provider.Contacts.Groups;
 import android.provider.Contacts.Intents;
 import android.provider.Contacts.People;
 import android.provider.Contacts.Phones;
 import android.provider.Contacts.Presence;
+import android.provider.Contacts.Intents.Insert;
 import android.provider.Contacts.Intents.UI;
 import android.text.TextUtils;
 import android.util.Log;
@@ -70,6 +70,8 @@
 import android.widget.SectionIndexer;
 import android.widget.TextView;
 
+import static com.android.contacts.ShowOrCreateActivity.QUERY_KIND_EMAIL_OR_IM;
+
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -139,8 +141,8 @@
             55 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
     /** Run a search query */
     static final int MODE_QUERY = 60 | MODE_MASK_NO_FILTER;
-    /** Show all contacts matching query, or handle special cases where 0 or 1 contacts found. */
-    static final int MODE_SHOW_OR_CREATE_CONTACT = 65 | MODE_MASK_PICKER | MODE_MASK_NO_FILTER;
+    /** Run a search query in PICK mode, but that still launches to VIEW */
+    static final int MODE_QUERY_PICK_TO_VIEW = 65 | MODE_MASK_NO_FILTER | MODE_MASK_PICKER;
 
     static final int DEFAULT_MODE = MODE_ALL_CONTACTS;
 
@@ -270,27 +272,13 @@
     private Uri mGroupUri;
     private boolean mJustCreated;
     private boolean mSyncEnabled;
-    
-    /**
-     * {@link Bundle} of extras to include when launching
-     * {@link Intents.Insert#ACTION}, usually when responding to
-     * {@link Intents#SHOW_OR_CREATE_CONTACT}.
-     */
-    private Bundle mCreateExtras;
-    
-    /**
-     * Title to display to user when asking if a contact should be created,
-     * usually the requested E-mail address or phone number when responding to a
-     * {@link Intents#SHOW_OR_CREATE_CONTACT}.
-     */
-    private String mCreateData;
 
     /**
      * Cursor row index that holds reference back to {@link People#_ID}, such as
      * {@link ContactMethods#PERSON_ID}. Used when responding to a
-     * {@link Intents#SHOW_OR_CREATE_CONTACT}.
+     * {@link Intent#ACTION_SEARCH} in mode {@link #MODE_QUERY_PICK_TO_VIEW}.
      */
-    private int mCreatePersonIndex;
+    private int mQueryPersonIdIndex;
 
     /**
      * Used to keep track of the scroll state of the list.
@@ -300,7 +288,22 @@
 
     private boolean mCreateShortcut;
     private boolean mDefaultMode = false;
+    
+    /**
+     * Internal query type when in mode {@link #MODE_QUERY_PICK_TO_VIEW}.
+     */
+    private int mQueryMode = QUERY_MODE_NONE;
 
+    private static final int QUERY_MODE_NONE = -1;
+    private static final int QUERY_MODE_MAILTO = 1;
+    private static final int QUERY_MODE_TEL = 2;
+    
+    /**
+     * Data to use when in mode {@link #MODE_QUERY_PICK_TO_VIEW}. Usually
+     * provided by scheme-specific part of incoming {@link Intent#getData()}.
+     */
+    private String mQueryData;
+    
     private class DeleteClickListener implements DialogInterface.OnClickListener {
         private Uri mUri;
 
@@ -313,23 +316,6 @@
         }
     }
     
-    private class IntentClickListener implements DialogInterface.OnClickListener {
-        private Activity mParent;
-        private Intent mIntent;
-
-        public IntentClickListener(Activity parent, Intent intent) {
-            mParent = parent;
-            mIntent = intent;
-        }
-
-        public void onClick(DialogInterface dialog, int which) {
-            if (mIntent != null) {
-                mParent.startActivity(mIntent);
-            }
-            mParent.finish();
-        }
-    }
-
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -407,8 +393,20 @@
                 finish();
                 return;
             }
-            // Otherwise handle the more normal search case
-            mMode = MODE_QUERY;
+            
+            // See if search request has extras to specify query
+            if (intent.hasExtra(Insert.EMAIL)) {
+                mMode = MODE_QUERY_PICK_TO_VIEW;
+                mQueryMode = QUERY_MODE_MAILTO;
+                mQueryData = intent.getStringExtra(Insert.EMAIL);
+            } else if (intent.hasExtra(Insert.PHONE)) {
+                mMode = MODE_QUERY_PICK_TO_VIEW;
+                mQueryMode = QUERY_MODE_TEL;
+                mQueryData = intent.getStringExtra(Insert.PHONE);
+            } else {
+                // Otherwise handle the more normal search case
+                mMode = MODE_QUERY;
+            }
 
         // Since this is the filter activity it receives all intents
         // dispatched from the SearchManager for security reasons
@@ -436,8 +434,6 @@
             startActivity(newIntent);
             finish();
             return;
-        } else if (Intents.SHOW_OR_CREATE_CONTACT.equals(action)) {
-            mMode = MODE_SHOW_OR_CREATE_CONTACT;
         }
 
         if (mMode == MODE_UNKNOWN) {
@@ -492,60 +488,6 @@
         }
     }
 
-    /**
-     * Handles special cases of the {@link Intents#SHOW_OR_CREATE_CONTACT}
-     * intent. When zero results found, prompt user to create new contact. When
-     * one contact found, shortcut to viewing that contact.
-     * 
-     * @param c Valid cursor after performing query
-     */
-    private void handleShowOrCreate(final Cursor c) {
-        int count = 0;
-        long personId = 0;
-        if (c != null) {
-            count = c.getCount();
-            if (count == 1 && c.moveToFirst()) {
-                // Try reading ID for the only contact returned
-                personId = c.getLong(mCreatePersonIndex);
-            }
-        }
-        
-        if (count == 1) {
-            // If we only found one item, jump right to viewing it
-            Intent showIntent = new Intent(Intent.ACTION_VIEW,
-                    ContentUris.withAppendedId(People.CONTENT_URI, personId));
-            startActivity(showIntent);
-            finish();
-            
-        } else if (count == 0) {
-            // Insert create values coming from our request
-            Intent createIntent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
-            createIntent.putExtras(mCreateExtras);
-            
-            // Prompt user if they really want to start creating a new
-            // contact. Skip this step if the caller requested {@link
-            // Contacts#EXTRA_FORCE_CREATE}.
-            boolean forceCreate = getIntent().getBooleanExtra(Intents.EXTRA_FORCE_CREATE, false);
-            
-            if (forceCreate) {
-                startActivity(createIntent);
-                finish();
-            } else {
-                CharSequence message = getResources().getString(
-                        R.string.add_contact_dlg_message_fmt, mCreateData);
-                
-                new AlertDialog.Builder(this)
-                        .setTitle(R.string.add_contact_dlg_title)
-                        .setMessage(message)
-                        .setPositiveButton(android.R.string.ok,
-                                new IntentClickListener(this, createIntent))
-                        .setNegativeButton(android.R.string.cancel,
-                                new IntentClickListener(this, null))
-                        .show();
-            }
-        }
-    }
-
     private void setEmptyText() {
         TextView empty = (TextView) findViewById(R.id.emptyText);
         // Center the text by default
@@ -1046,10 +988,10 @@
                 Intent intent = new Intent(Intent.ACTION_VIEW,
                         ContentUris.withAppendedId(People.CONTENT_URI, id));
                 startActivity(intent);
-            } else if (mMode == MODE_SHOW_OR_CREATE_CONTACT) {
-                // Figure out person ID because we might be using indirect cursor
+            } else if (mMode == MODE_QUERY_PICK_TO_VIEW) {
+                // Started with query that should launch to view contact
                 Cursor c = (Cursor) mAdapter.getItem(position);
-                long personId = c.getLong(mCreatePersonIndex);
+                long personId = c.getLong(mQueryPersonIdIndex);
                 Intent intent = new Intent(Intent.ACTION_VIEW,
                         ContentUris.withAppendedId(People.CONTENT_URI, personId));
                 startActivity(intent);
@@ -1184,52 +1126,25 @@
                 break;
             }
             
-            case MODE_SHOW_OR_CREATE_CONTACT: {
-                // Caller requested a specific E-mail address or phone number,
-                // so show only matching entries. Once the query finishes we
-                // handle edge cases of 0 or 1 items.
-                Uri data = getIntent().getData();
-                String scheme = null;
-                String ssp = null;
-                if (data != null) {
-                    scheme = data.getScheme();
-                    ssp = data.getSchemeSpecificPart();
-                    mCreateData = ssp;
-                }
-                
-                mCreateExtras = new Bundle();
-                Bundle originalExtras = getIntent().getExtras();
-                if (originalExtras != null) {
-                    mCreateExtras.putAll(originalExtras);
-                }
-
-                if ("mailto".equals(scheme)) {
-                    mCreateExtras.putString(Intents.Insert.EMAIL, ssp);
-                    mCreatePersonIndex = CONTACT_METHODS_PERSON_ID_INDEX;
-                    
+            case MODE_QUERY_PICK_TO_VIEW: {
+                if (mQueryMode == QUERY_MODE_MAILTO) {
+                    mQueryPersonIdIndex = CONTACT_METHODS_PERSON_ID_INDEX;
                     mQueryHandler.startQuery(QUERY_TOKEN, null,
                             ContactMethods.CONTENT_URI, CONTACT_METHODS_PROJECTION,
-                            ContactMethodsColumns.KIND + "=" + Contacts.KIND_EMAIL + " AND " +
-                            ContactMethods.DATA + "=?", new String[] { ssp },
+                            QUERY_KIND_EMAIL_OR_IM + " AND " + ContactMethods.DATA + "=?",
+                            new String[] { mQueryData },
                             getSortOrder(CONTACT_METHODS_PROJECTION));
                     
-                } else if ("tel".equals(scheme)) {
-                    mCreateExtras.putString(Intents.Insert.PHONE, ssp);
-                    mCreatePersonIndex = PHONES_PERSON_ID_INDEX;
-                    
+                } else if (mQueryMode == QUERY_MODE_TEL) {
+                    mQueryPersonIdIndex = PHONES_PERSON_ID_INDEX;
                     mQueryHandler.startQuery(QUERY_TOKEN, null,
-                            Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, ssp),
+                            Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, mQueryData),
                             PHONES_PROJECTION, null, null,
                             getSortOrder(PHONES_PROJECTION));
-                    
-                } else {
-                    Log.w(TAG, "Invalid intent:" + getIntent());
-                    finish();
                 }
-                
                 break;
             }
-
+            
             case MODE_STARRED:
                 mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI,
                         CONTACTS_PROJECTION,
@@ -1413,7 +1328,6 @@
                     getString(R.string.groupNameWithPhones));
             prefStrings.add(GROUP_WITH_PHONES);
             
-            int i = 3;
             int currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS;
             while (cursor.moveToNext()) {
                 String systemId = cursor.getString(GROUPS_COLUMN_INDEX_SYSTEM_ID);
@@ -1423,9 +1337,8 @@
                     // All groups that aren't My Contacts, since that one is localized on the phone
                     groups.add(name);
                     if (name.equals(mDisplayInfo)) {
-                        currentIndex = i;
+                        currentIndex = groups.size() - 1;
                     }
-                    i++;
                 } else {
                     // The My Contacts group
                     groups.add(DISPLAY_GROUP_INDEX_MY_CONTACTS,
@@ -1443,8 +1356,7 @@
                 currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES;
             }
             mDisplayGroups = groups.toArray(new CharSequence[groups.size()]);
-            builder.setSingleChoiceItems(mDisplayGroups,
-                    currentIndex, this);
+            builder.setSingleChoiceItems(mDisplayGroups, currentIndex, this);
             mDisplayGroupOriginalSelection = currentIndex;
         } finally {
             cursor.close();
@@ -1467,11 +1379,6 @@
                 activity.getListView().clearTextFilter();                
                 activity.mAdapter.changeCursor(cursor);
                 
-                // Handle SHOW_OR_CREATE now that we have valid cursor
-                if (activity.mMode == MODE_SHOW_OR_CREATE_CONTACT) {
-                    activity.handleShowOrCreate(cursor);
-                }
-    
                 // Now that the cursor is populated again, it's possible to restore the list state
                 if (activity.mListState != null) {
                     activity.mList.onRestoreInstanceState(activity.mListState);
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index dbf2879..8949f6e 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -114,17 +114,11 @@
     private static final int QUERY_TOKEN = 53;
     private static final int UPDATE_TOKEN = 54;
 
-    private RecentCallsAdapter mAdapter;
+    RecentCallsAdapter mAdapter;
     private QueryHandler mQueryHandler;
-    private String mVoiceMailNumber;
+    String mVoiceMailNumber;
 
-    private CharSequence[] mLabelArray;
-
-    private Drawable mDrawableIncoming;
-    private Drawable mDrawableOutgoing;
-    private Drawable mDrawableMissed;
-
-    private static final class ContactInfo {
+    static final class ContactInfo {
         public long personId;
         public String name;
         public int type;
@@ -136,13 +130,14 @@
 
     public static final class RecentCallsListItemViews {
         TextView line1View;
-        TextView line2View;
-        TextView durationView;
+        TextView labelView;
+        TextView numberView;
         TextView dateView;
         ImageView iconView;
+        View callView;
     }
 
-    private static final class CallerInfoQuery {
+    static final class CallerInfoQuery {
         String number;
         int position;
         String name;
@@ -151,8 +146,8 @@
     }
 
     /** Adapter class to fill in data for the Call Log */
-    private final class RecentCallsAdapter extends ResourceCursorAdapter
-            implements Runnable, ViewTreeObserver.OnPreDrawListener {
+    final class RecentCallsAdapter extends ResourceCursorAdapter
+            implements Runnable, ViewTreeObserver.OnPreDrawListener, View.OnClickListener {
         HashMap<String,ContactInfo> mContactInfo;
         private final LinkedList<CallerInfoQuery> mRequests;
         private volatile boolean mDone;
@@ -163,6 +158,20 @@
         private boolean mFirst;
         private Thread mCallerIdThread;
 
+        private CharSequence[] mLabelArray;
+
+        private Drawable mDrawableIncoming;
+        private Drawable mDrawableOutgoing;
+        private Drawable mDrawableMissed;
+
+        public void onClick(View view) {
+            String number = (String) view.getTag();
+            if (!TextUtils.isEmpty(number)) {
+                Uri telUri = Uri.fromParts("tel", number, null);
+                startActivity(new Intent(Intent.ACTION_CALL_PRIVILEGED, telUri));
+            }
+        }
+
         public boolean onPreDraw() {
             if (mFirst) {
                 mHandler.sendEmptyMessageDelayed(START_THREAD, 1000);
@@ -191,6 +200,14 @@
             mContactInfo = new HashMap<String,ContactInfo>();
             mRequests = new LinkedList<CallerInfoQuery>();
             mPreDrawListener = null;
+
+            mDrawableIncoming = getResources().getDrawable(
+                    R.drawable.ic_call_log_list_incoming_call);
+            mDrawableOutgoing = getResources().getDrawable(
+                    R.drawable.ic_call_log_list_outgoing_call);
+            mDrawableMissed = getResources().getDrawable(
+                    R.drawable.ic_call_log_list_missed_call);
+            mLabelArray = getResources().getTextArray(com.android.internal.R.array.phoneTypes);
         }
 
         void setLoading(boolean loading) {
@@ -331,11 +348,13 @@
             // Get the views to bind to
             RecentCallsListItemViews views = new RecentCallsListItemViews();
             views.line1View = (TextView) view.findViewById(R.id.line1);
-            views.line2View = (TextView) view.findViewById(R.id.line2);
-            views.durationView = (TextView) view.findViewById(R.id.duration);
+            views.labelView = (TextView) view.findViewById(R.id.label);
+            views.numberView = (TextView) view.findViewById(R.id.number);
             views.dateView = (TextView) view.findViewById(R.id.date);
             views.iconView = (ImageView) view.findViewById(R.id.call_type_icon);
-
+            views.callView = view.findViewById(R.id.call_icon);
+            views.callView.setOnClickListener(this);
+            
             view.setTag(views);
 
             return view;
@@ -350,6 +369,9 @@
             String callerName = c.getString(CALLER_NAME_COLUMN_INDEX);
             int callerNumberType = c.getInt(CALLER_NUMBERTYPE_COLUMN_INDEX);
             String callerNumberLabel = c.getString(CALLER_NUMBERLABEL_COLUMN_INDEX);
+            
+            // Store away the number so we can call it directly if you click on the call icon
+            views.callView.setTag(number);
 
             // Lookup contacts with this number
             ContactInfo info = mContactInfo.get(number);
@@ -387,32 +409,24 @@
             // Set the text lines
             if (!TextUtils.isEmpty(name)) {
                 views.line1View.setText(name);
+                views.labelView.setVisibility(View.VISIBLE);
                 CharSequence numberLabel = Phones.getDisplayLabel(context, ntype, label,
                         mLabelArray);
+                views.numberView.setVisibility(View.VISIBLE);
+                views.numberView.setText(number);
                 if (!TextUtils.isEmpty(numberLabel)) {
-                    views.line2View.setText(numberLabel);
+                    views.labelView.setText(numberLabel);
+                    views.labelView.setVisibility(View.VISIBLE);
                 } else {
-                    views.line2View.setText(number);
+                    views.labelView.setVisibility(View.GONE);
                 }
-
-                // Set the presence icon
-/*
-                int serverStatus;
-                if (!c.isNull(SERVER_STATUS_COLUMN_INDEX)) {
-                    serverStatus = c.getInt(SERVER_STATUS_COLUMN_INDEX);
-                    views.line2View.setCompoundDrawablesWithIntrinsicBounds(
-                            getResources().getDrawable(
-                                    Presence.getPresenceIconResourceId(serverStatus)),
-                            null, null, null);
-                } else {
-                    views.line2View.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
-                }
-*/
             } else {
                 if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
                     number = getString(R.string.unknown);
                 } else if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
                     number = getString(R.string.private_num);
+                } else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
+                    number = getString(R.string.payphone);
                 } else if (number.equals(mVoiceMailNumber)) {
                     number = getString(R.string.voicemail);
                 } else {
@@ -421,29 +435,18 @@
                 }
 
                 views.line1View.setText(number);
-                views.line2View.setText(null);
-
-                // Clear the presence icon
-//                views.line2View.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+                views.numberView.setVisibility(View.GONE);
+                views.labelView.setVisibility(View.GONE);
             }
 
             int type = c.getInt(CALL_TYPE_COLUMN_INDEX);
             long date = c.getLong(DATE_COLUMN_INDEX);
 
-            // Set the duration
-            if (type == Calls.MISSED_TYPE) {
-                views.durationView.setVisibility(View.GONE);
-            } else {
-                views.durationView.setVisibility(View.VISIBLE);
-                views.durationView.setText(DateUtils.formatElapsedTime(c.getLong(DURATION_COLUMN_INDEX)));
-            }
-
             // Set the date/time field by mixing relative and absolute times.
-            int flags = DateUtils.FORMAT_ABBREV_RELATIVE | DateUtils.FORMAT_SHOW_DATE
-                    | DateUtils.FORMAT_ABBREV_MONTH;
+            int flags = DateUtils.FORMAT_ABBREV_RELATIVE;
             
-            views.dateView.setText(DateUtils.getRelativeDateTimeString(context, date,
-                    DateUtils.MINUTE_IN_MILLIS, DateUtils.DAY_IN_MILLIS * 2, flags));
+            views.dateView.setText(DateUtils.getRelativeTimeSpanString(date,
+                    System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, flags));
 
             // Set the icon
             switch (type) {
@@ -459,6 +462,7 @@
                     views.iconView.setImageDrawable(mDrawableMissed);
                     break;
             }
+
             // Listen for the first draw
             if (mPreDrawListener == null) {
                 mFirst = true;
@@ -496,11 +500,6 @@
 
         setContentView(R.layout.recent_calls);
 
-        mDrawableIncoming = getResources().getDrawable(android.R.drawable.sym_call_incoming);
-        mDrawableOutgoing = getResources().getDrawable(android.R.drawable.sym_call_outgoing);
-        mDrawableMissed = getResources().getDrawable(android.R.drawable.sym_call_missed);
-        mLabelArray = getResources().getTextArray(com.android.internal.R.array.phoneTypes);
-
         // Typing here goes to the dialer
         setDefaultKeyMode(DEFAULT_KEYS_DIALER);
 
@@ -616,6 +615,8 @@
             number = getString(R.string.unknown);
         } else if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
             number = getString(R.string.private_num);
+        } else if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
+            number = getString(R.string.payphone);
         } else if (number.equals(mVoiceMailNumber)) {
             number = getString(R.string.voicemail);
             numberUri = Uri.parse("voicemail:x");
@@ -799,7 +800,8 @@
             String number = cursor.getString(NUMBER_COLUMN_INDEX);
             if (TextUtils.isEmpty(number)
                     || number.equals(CallerInfo.UNKNOWN_NUMBER)
-                    || number.equals(CallerInfo.PRIVATE_NUMBER)) {
+                    || number.equals(CallerInfo.PRIVATE_NUMBER)
+                    || number.equals(CallerInfo.PAYPHONE_NUMBER)) {
                 // This number can't be called, do nothing
                 return;
             }
diff --git a/src/com/android/contacts/ShowOrCreateActivity.java b/src/com/android/contacts/ShowOrCreateActivity.java
new file mode 100755
index 0000000..8d3cf0b
--- /dev/null
+++ b/src/com/android/contacts/ShowOrCreateActivity.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.AsyncQueryHandler;
+import android.content.ComponentName;
+import android.content.ContentUris;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Contacts;
+import android.provider.Contacts.ContactMethods;
+import android.provider.Contacts.ContactMethodsColumns;
+import android.provider.Contacts.Intents;
+import android.provider.Contacts.People;
+import android.provider.Contacts.Phones;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Handle several edge cases around showing or possibly creating contacts in
+ * connected with a specific E-mail address or phone number. Will search based
+ * on incoming {@link Intent#getData()} as described by
+ * {@link Intents#SHOW_OR_CREATE_CONTACT}.
+ * <ul>
+ * <li>If no matching contacts found, will prompt user with dialog to add to a
+ * contact, then will use {@link Intent#ACTION_INSERT_OR_EDIT} to let create new
+ * contact or edit new data into an existing one.
+ * <li>If one matching contact found, directly show {@link Intent#ACTION_VIEW}
+ * that specific contact.
+ * <li>If more than one matching found, show list of matching contacts using
+ * {@link Intent#ACTION_SEARCH}.
+ * </ul>
+ */
+public final class ShowOrCreateActivity extends Activity {
+    static final String TAG = "ShowOrCreateActivity";
+    static final boolean LOGD = false;
+
+    static final String[] PHONES_PROJECTION = new String[] {
+        Phones._ID,
+        Phones.PERSON_ID,
+    };
+
+    static final String[] CONTACT_METHODS_PROJECTION = new String[] {
+        ContactMethods._ID,
+        ContactMethods.PERSON_ID,
+    };
+    
+    static final String SCHEME_MAILTO = "mailto";
+    static final String SCHEME_TEL = "tel";
+    
+    static final int ID_INDEX = 0;
+    static final int PERSON_ID_INDEX = 1;
+
+    /**
+     * Query clause to filter {@link ContactMethods#CONTENT_URI} to only search
+     * {@link Contacts#KIND_EMAIL} or {@link Contacts#KIND_IM}.
+     */
+    static final String QUERY_KIND_EMAIL_OR_IM = ContactMethodsColumns.KIND +
+            " IN (" + Contacts.KIND_EMAIL + "," + Contacts.KIND_IM + ")";
+    
+    static final int QUERY_TOKEN = 42;
+    
+    private QueryHandler mQueryHandler;
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        
+        // Create handler if doesn't exist, otherwise cancel any running
+        if (mQueryHandler == null) {
+            mQueryHandler = new QueryHandler(this);
+        } else {
+            mQueryHandler.cancelOperation(QUERY_TOKEN);
+        }
+
+        final Intent intent = getIntent();
+        final Uri data = intent.getData();
+        
+        // Unpack scheme and target data from intent
+        String scheme = null;
+        String ssp = null;
+        if (data != null) {
+            scheme = data.getScheme();
+            ssp = data.getSchemeSpecificPart();
+        }
+        
+        // Build set of extras for possible use when creating contact
+        Bundle createExtras = new Bundle();
+        Bundle originalExtras = intent.getExtras();
+        if (originalExtras != null) {
+            createExtras.putAll(originalExtras);
+        }
+        mQueryHandler.setCreateExtras(createExtras);
+        
+        // Read possible extra with specific title
+        String createDescrip = intent.getStringExtra(Intents.EXTRA_CREATE_DESCRIPTION);
+        if (createDescrip == null) {
+            createDescrip = ssp;
+        }
+        mQueryHandler.setCreateDescription(createDescrip);
+        
+        // Allow caller to bypass dialog prompt
+        boolean createForce = intent.getBooleanExtra(Intents.EXTRA_FORCE_CREATE, false);
+        mQueryHandler.setCreateForce(createForce);
+        
+        // Handle specific query request
+        if (SCHEME_MAILTO.equals(scheme)) {
+            createExtras.putString(Intents.Insert.EMAIL, ssp);
+            mQueryHandler.startQuery(QUERY_TOKEN, null,
+                    ContactMethods.CONTENT_URI, CONTACT_METHODS_PROJECTION,
+                    QUERY_KIND_EMAIL_OR_IM + " AND " + ContactMethods.DATA + "=?",
+                    new String[] { ssp }, null);
+            
+        } else if (SCHEME_TEL.equals(scheme)) {
+            createExtras.putString(Intents.Insert.PHONE, ssp);
+            mQueryHandler.startQuery(QUERY_TOKEN, null,
+                    Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, ssp),
+                    PHONES_PROJECTION, null, null, null);
+            
+        } else {
+            Log.w(TAG, "Invalid intent:" + getIntent());
+            finish();
+        }
+    }
+    
+    @Override
+    protected void onStop() {
+        super.onStop();
+        if (mQueryHandler != null) {
+            mQueryHandler.cancelOperation(QUERY_TOKEN);
+        }
+    }
+    
+    /**
+     * Listener for {@link DialogInterface} that launches a given {@link Intent}
+     * when clicked. When clicked, this also closes the parent using
+     * {@link Activity#finish()}.
+     */
+    private static class IntentClickListener implements DialogInterface.OnClickListener {
+        private Activity mParent;
+        private Intent mIntent;
+
+        /**
+         * @param parent {@link Activity} to use for launching target.
+         * @param intent Target {@link Intent} to launch when clicked.
+         */
+        public IntentClickListener(Activity parent, Intent intent) {
+            mParent = parent;
+            mIntent = intent;
+        }
+
+        public void onClick(DialogInterface dialog, int which) {
+            if (mIntent != null) {
+                mParent.startActivity(mIntent);
+            }
+            mParent.finish();
+        }
+    }
+
+    /**
+     * Handle asynchronous query to find matching contacts. When query finishes,
+     * will handle based on number of matching contacts found.
+     */
+    private static final class QueryHandler extends AsyncQueryHandler {
+        private final WeakReference<Activity> mActivity;
+        private Bundle mCreateExtras;
+        private String mCreateDescrip;
+        private boolean mCreateForce;
+
+        public QueryHandler(Activity activity) {
+            super(activity.getContentResolver());
+            mActivity = new WeakReference<Activity>(activity);
+        }
+        
+        public void setCreateExtras(Bundle createExtras) {
+            mCreateExtras = createExtras;
+        }
+        
+        public void setCreateDescription(String createDescrip) {
+            mCreateDescrip = createDescrip;
+        }
+        
+        public void setCreateForce(boolean createForce) {
+            mCreateForce = createForce;
+        }
+
+        @Override
+        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
+            Activity activity = mActivity.get();
+            if (activity == null) {
+                return;
+            }
+            
+            // Count contacts found by query
+            int count = 0;
+            long personId = -1;
+            if (cursor != null) {
+                try {
+                    count = cursor.getCount();
+                    if (count == 1 && cursor.moveToFirst()) {
+                        // Try reading ID if only one contact returned
+                        personId = cursor.getLong(PERSON_ID_INDEX);
+                    }
+                } finally {
+                    cursor.close();
+                }
+            }
+            
+            if (LOGD) Log.d(TAG, "onQueryComplete count=" + count);
+            
+            if (count == 1) {
+                // If we only found one item, jump right to viewing it
+                Intent viewIntent = new Intent(Intent.ACTION_VIEW,
+                        ContentUris.withAppendedId(People.CONTENT_URI, personId));
+                activity.startActivity(viewIntent);
+                activity.finish();
+                
+            } else if (count > 1) {
+                // If more than one, show pick list
+                Intent listIntent = new Intent(Intent.ACTION_SEARCH);
+                listIntent.setComponent(new ComponentName(activity, ContactsListActivity.class));
+                listIntent.putExtras(mCreateExtras);
+                activity.startActivity(listIntent);
+                activity.finish();
+                
+            } else {
+                // No matching contacts found
+                if (mCreateForce) {
+                    // Forced to create new contact
+                    Intent createIntent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
+                    createIntent.putExtras(mCreateExtras);
+                    createIntent.setType(People.CONTENT_TYPE);
+                    
+                    activity.startActivity(createIntent);
+                    activity.finish();
+                    
+                } else {
+                    // Prompt user to insert or edit contact 
+                    Intent createIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+                    createIntent.putExtras(mCreateExtras);
+                    createIntent.setType(People.CONTENT_ITEM_TYPE);
+                    
+                    CharSequence message = activity.getResources().getString(
+                            R.string.add_contact_dlg_message_fmt, mCreateDescrip);
+                    
+                    new AlertDialog.Builder(activity)
+                            .setTitle(R.string.add_contact_dlg_title)
+                            .setMessage(message)
+                            .setPositiveButton(android.R.string.ok,
+                                    new IntentClickListener(activity, createIntent))
+                            .setNegativeButton(android.R.string.cancel,
+                                    new IntentClickListener(activity, null))
+                            .show();
+                }
+            }
+        }
+    }
+}