Merge change I5ba08ed2 into eclair

* changes:
  Final drop of hdpi assets for contacts.
diff --git a/res/drawable-hdpi/ic_menu_import_export.png b/res/drawable-hdpi/ic_menu_import_export.png
new file mode 100644
index 0000000..1cefb7c
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_import_export.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts.png
new file mode 100644
index 0000000..d49cc7b
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png
new file mode 100644
index 0000000..0127f84
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts_phone.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png b/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png
new file mode 100644
index 0000000..8d56b31
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_folder_live_contacts_starred.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_phone.png b/res/drawable-mdpi/ic_launcher_phone.png
new file mode 100644
index 0000000..724f94a
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_phone.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_contact.png b/res/drawable-mdpi/ic_launcher_shortcut_contact.png
new file mode 100644
index 0000000..20d359d
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_contact.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_directdial.png b/res/drawable-mdpi/ic_launcher_shortcut_directdial.png
new file mode 100644
index 0000000..7081c08
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_directdial.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png b/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png
new file mode 100644
index 0000000..374c7c4
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_directmessage.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_import_export.png b/res/drawable-mdpi/ic_menu_import_export.png
new file mode 100644
index 0000000..4f1b608
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_import_export.png
Binary files differ
diff --git a/res/menu/list.xml b/res/menu/list.xml
index b5a2750..b8f9b76 100644
--- a/res/menu/list.xml
+++ b/res/menu/list.xml
@@ -38,7 +38,7 @@
 
     <item
         android:id="@+id/menu_import_export"
-        android:icon="@drawable/ic_menu_export_contact"
+        android:icon="@drawable/ic_menu_import_export"
         android:title="@string/menu_import_export" />
 
 </menu>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 407d1c5..4df8b7c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -962,7 +962,7 @@
 
     <!-- Shown as the header title over a collapsible section that, by default, hides
          secondary contact detail edit fields, such as birthday. -->
-    <string name="edit_secondary_collapse">Secondary details</string>
+    <string name="edit_secondary_collapse">More</string>
 
     <string name="dialog_primary_name">Primary name</string>
     <string name="dialog_new_contact_account">Create contact under account</string>
diff --git a/src/com/android/contacts/ContactOptionsActivity.java b/src/com/android/contacts/ContactOptionsActivity.java
index fbe4604..f93ddf8 100644
--- a/src/com/android/contacts/ContactOptionsActivity.java
+++ b/src/com/android/contacts/ContactOptionsActivity.java
@@ -52,13 +52,13 @@
     private TextView mRingtoneTitle;
     private CheckBox mSendToVoicemailCheckbox;
 
-    private Uri mAggregateUri;
+    private Uri mLookupUri;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mAggregateUri = getIntent().getData();
+        mLookupUri = getIntent().getData();
 
         setContentView(R.layout.contact_options);
 
@@ -176,7 +176,7 @@
 
     private boolean loadData() {
         Cursor c =
-                getContentResolver().query(mAggregateUri, AGGREGATES_PROJECTION, null, null, null);
+                getContentResolver().query(mLookupUri, AGGREGATES_PROJECTION, null, null, null);
         try {
             if (!c.moveToFirst()) {
                 return false;
@@ -195,7 +195,7 @@
         ContentValues values = new ContentValues(2);
         values.put(Contacts.CUSTOM_RINGTONE, mCustomRingtone);
         values.put(Contacts.SEND_TO_VOICEMAIL, mSendToVoicemail);
-        getContentResolver().update(mAggregateUri, values, null, null);
+        getContentResolver().update(mLookupUri, values, null, null);
     }
 }
 
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index c228178..c7d06e2 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -2138,7 +2138,8 @@
                         parent, false);
                 int stringId = mDisplayOnlyPhones ? R.string.listTotalPhoneContacts
                         : R.string.listTotalAllContacts;
-                totalContacts.setText(getString(stringId, getCount()));
+
+                totalContacts.setText(getString(stringId, getRealCount()));
                 return totalContacts;
             }
 
@@ -2570,19 +2571,33 @@
 
         @Override
         public int getCount() {
+            if (!mDataValid) {
+                return 0;
+            }
+            int superCount = super.getCount();
+            if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+                superCount++;
+            }
             if (mSuggestionsCursorCount != 0) {
                 // When showing suggestions, we have 2 additional list items: the "Suggestions"
                 // and "All contacts" headers.
-                return mSuggestionsCursorCount + super.getCount() + 2;
+                return mSuggestionsCursorCount + superCount + 2;
             }
             else if (mFrequentSeparatorPos != ListView.INVALID_POSITION) {
                 // When showing strequent list, we have an additional list item - the separator.
-                return super.getCount() + 1;
+                return superCount + 1;
             } else {
-                return super.getCount();
+                return superCount;
             }
         }
 
+        /**
+         * Gets the actual count of contacts and excludes all the headers.
+         */
+        public int getRealCount() {
+            return super.getCount();
+        }
+
         private int getRealPosition(int pos) {
             if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
                 pos--;
diff --git a/src/com/android/contacts/ExportVCardActivity.java b/src/com/android/contacts/ExportVCardActivity.java
index 08f43c1..7c088ea 100644
--- a/src/com/android/contacts/ExportVCardActivity.java
+++ b/src/com/android/contacts/ExportVCardActivity.java
@@ -26,7 +26,6 @@
 import android.os.Handler;
 import android.os.PowerManager;
 import android.pim.vcard.VCardComposer;
-import android.provider.ContactsContract.Contacts;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -148,10 +147,12 @@
                 }
 
                 composer = new VCardComposer(ExportVCardActivity.this, mVCardTypeStr, true);
-                // composer = new VCardComposer(ExportVCardActivity,
-                // VCardConfig.VCARD_TYPE_V30_JAPANESE_UTF8, true);
+                /*int vcardType = (VCardConfig.VCARD_TYPE_V21_GENERIC |
+                        VCardConfig.FLAG_USE_QP_TO_PRIMARY_PROPERTIES);
+                composer = new VCardComposer(ExportVCardActivity.this, vcardType, true);*/
+
                 composer.addHandler(composer.new HandlerForOutputStream(outputStream));
- 
+
                 if (!composer.init()) {
                     final String errorReason = composer.getErrorReason();
                     Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason);
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 8172423..bec871f 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -108,7 +108,6 @@
     private static final String SPLIT_MIMETYPE = "split_mimetype";
 
     protected Uri mLookupUri;
-    private Uri mUri;
     private ContentResolver mResolver;
     private ViewAdapter mAdapter;
     private int mNumPhoneNumbers = 0;
@@ -174,7 +173,7 @@
 
     public void onClick(DialogInterface dialog, int which) {
         closeCursor();
-        getContentResolver().delete(mUri, null, null);
+        getContentResolver().delete(mLookupUri, null, null);
         finish();
     }
 
@@ -492,6 +491,14 @@
         // Empty
     }
 
+    private long getRefreshedContactId() {
+        Uri freshContactUri = Contacts.lookupContact(getContentResolver(), mLookupUri);
+        if (freshContactUri != null) {
+            return ContentUris.parseId(freshContactUri);
+        }
+        return -1;
+    }
+
     private ArrayList<Entity> readEntities(EntityIterator iterator) {
         ArrayList<Entity> entities = new ArrayList<Entity>();
         try {
@@ -507,15 +514,15 @@
     private void startEntityQuery() {
         closeCursor();
 
-        mUri = null;
+        Uri uri = null;
         if (mLookupUri != null) {
             mLookupUri = Contacts.getLookupUri(getContentResolver(), mLookupUri);
             if (mLookupUri != null) {
-                mUri = Contacts.lookupContact(getContentResolver(), mLookupUri);
+                uri = Contacts.lookupContact(getContentResolver(), mLookupUri);
             }
         }
 
-        if (mUri == null) {
+        if (uri == null) {
 
             // TODO either figure out a way to prevent a flash of black background or
             // use some other UI than a toast
@@ -525,11 +532,11 @@
             return;
         }
 
-        mCursor = mResolver.query(Uri.withAppendedPath(mUri, Contacts.Data.CONTENT_DIRECTORY),
+        mCursor = mResolver.query(Uri.withAppendedPath(uri, Contacts.Data.CONTENT_DIRECTORY),
                 new String[] {Contacts.DISPLAY_NAME}, null, null, null);
         mCursor.registerContentObserver(mObserver);
 
-        long contactId = ContentUris.parseId(mUri);
+        long contactId = ContentUris.parseId(uri);
         mHandler.startQueryEntities(TOKEN_QUERY, null,
                 RawContacts.CONTENT_URI, RawContacts.CONTACT_ID + "=" + contactId, null, null);
 
@@ -725,54 +732,22 @@
     }
 
     /**
-     * Shows a dialog that contains a list of all constituent contacts in this aggregate.
-     * The user picks a contact to be split into its own aggregate or clicks Cancel.
-     */
-    private void showSplitAggregateDialog() {
-        // Wrap this dialog in a specific theme so that list items have correct text color.
-        final ContextThemeWrapper dialogContext =
-                new ContextThemeWrapper(this, android.R.style.Theme_Light);
-        AlertDialog.Builder builder =
-                new AlertDialog.Builder(dialogContext);
-        builder.setTitle(getString(R.string.splitAggregate_title));
-
-        final SplitAggregateView view = new SplitAggregateView(dialogContext, mUri);
-        builder.setView(view);
-
-        builder.setInverseBackgroundForced(true);
-        builder.setCancelable(true);
-        builder.setNegativeButton(android.R.string.cancel,
-                new OnClickListener() {
-                    public void onClick(DialogInterface dialog, int which) {
-                        dialog.dismiss();
-                    }
-                });
-        final AlertDialog dialog = builder.create();
-
-        view.setOnContactSelectedListener(new OnContactSelectedListener() {
-            public void onContactSelected(long rawContactId) {
-                dialog.dismiss();
-                splitContact(rawContactId);
-            }
-        });
-
-        dialog.show();
-    }
-
-    /**
      * Shows a list of aggregates that can be joined into the currently viewed aggregate.
      */
     public void showJoinAggregateActivity() {
-        String displayName = null;
-        if (mCursor.moveToFirst()) {
-            displayName = mCursor.getString(0);
+        long freshId = getRefreshedContactId();
+        if (freshId > 0) {
+            String displayName = null;
+            if (mCursor.moveToFirst()) {
+                displayName = mCursor.getString(0);
+            }
+            Intent intent = new Intent(ContactsListActivity.JOIN_AGGREGATE);
+            intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_ID, freshId);
+            if (displayName != null) {
+                intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_NAME, displayName);
+            }
+            startActivityForResult(intent, REQUEST_JOIN_CONTACT);
         }
-        Intent intent = new Intent(ContactsListActivity.JOIN_AGGREGATE);
-        intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_ID, ContentUris.parseId(mUri));
-        if (displayName != null) {
-            intent.putExtra(ContactsListActivity.EXTRA_AGGREGATE_NAME, displayName);
-        }
-        startActivityForResult(intent, REQUEST_JOIN_CONTACT);
     }
 
     @Override
@@ -831,7 +806,7 @@
 
     private void showOptionsActivity() {
         final Intent intent = new Intent(this, ContactOptionsActivity.class);
-        intent.setData(mUri);
+        intent.setData(mLookupUri);
         startActivity(intent);
     }
 
@@ -870,8 +845,13 @@
                     }
                 } else if (mNumPhoneNumbers != 0) {
                     // There isn't anything selected, call the default number
-                    Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, mUri);
-                    startActivity(intent);
+                    long freshContactId = getRefreshedContactId();
+                    if (freshContactId > 0) {
+                        Uri hardContacUri = ContentUris.withAppendedId(
+                                Contacts.CONTENT_URI, freshContactId);
+                        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, hardContacUri);
+                        startActivity(intent);
+                    }
                 }
                 return true;
             }
@@ -939,7 +919,7 @@
         Sources sources = Sources.getInstance(this);
 
         // Build up method entries
-        if (mUri != null) {
+        if (mLookupUri != null) {
             for (Entity entity: mEntities) {
                 final ContentValues entValues = entity.getEntityValues();
                 final String accountType = entValues.getAsString(RawContacts.ACCOUNT_TYPE);
diff --git a/src/com/android/contacts/model/Editor.java b/src/com/android/contacts/model/Editor.java
index b7ae045..b3e8443 100644
--- a/src/com/android/contacts/model/Editor.java
+++ b/src/com/android/contacts/model/Editor.java
@@ -42,6 +42,7 @@
         public void onRequest(int request);
 
         public static final int REQUEST_PICK_PHOTO = 1;
+        public static final int FIELD_CHANGED = 2;
     }
 
     /**
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/EntityDelta.java
index 7ac0f5b..dfc4fc4 100644
--- a/src/com/android/contacts/model/EntityDelta.java
+++ b/src/com/android/contacts/model/EntityDelta.java
@@ -162,6 +162,44 @@
     }
 
     /**
+     * calls {@link #getSuperPrimaryEntry(String, boolean)} with true
+     * @see #getSuperPrimaryEntry(String, boolean)
+     */
+    public ValuesDelta getSuperPrimaryEntry(String mimeType) {
+        return getSuperPrimaryEntry(mimeType, true);
+    }
+
+    /**
+     * Returns the super-primary entry for the given mime type
+     * @param forceSelection if true, will try to return some value even if a super-primary
+     *     doesn't exist (may be a primary, or just a random item
+     * @return
+     */
+    public ValuesDelta getSuperPrimaryEntry(String mimeType, boolean forceSelection) {
+        final ArrayList<ValuesDelta> mimeEntries = getMimeEntries(mimeType, false);
+        if (mimeEntries == null) return null;
+
+        ValuesDelta primary = null;
+        for (ValuesDelta entry : mimeEntries) {
+            if (entry.isSuperPrimary()) {
+                return entry;
+            } else if (entry.isPrimary()) {
+                primary = entry;
+            }
+        }
+
+        if (!forceSelection) {
+            return null;
+        }
+
+        // When no direct super primary, return something
+        if (primary != null) {
+            return primary;
+        }
+        return mimeEntries.size() > 0 ? mimeEntries.get(0) : null;
+    }
+
+    /**
      * Return the list of child {@link ValuesDelta} from our optimized map,
      * creating the list if requested.
      */
@@ -552,6 +590,11 @@
             return mFromTemplate;
         }
 
+        public boolean isSuperPrimary() {
+            final Long isSuperPrimary = getAsLong(Data.IS_SUPER_PRIMARY);
+            return isSuperPrimary == null ? false : isSuperPrimary != 0;
+        }
+
         public boolean beforeExists() {
             return (mBefore != null && mBefore.containsKey(mIdColumn));
         }
diff --git a/src/com/android/contacts/model/EntitySet.java b/src/com/android/contacts/model/EntitySet.java
index 2137987..adc87ee 100644
--- a/src/com/android/contacts/model/EntitySet.java
+++ b/src/com/android/contacts/model/EntitySet.java
@@ -16,22 +16,24 @@
 
 package com.android.contacts.model;
 
-import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.google.android.collect.Lists;
-
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
-import android.content.ContentValues;
 import android.content.Entity;
 import android.content.EntityIterator;
 import android.content.ContentProviderOperation.Builder;
+import android.graphics.BitmapFactory;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.provider.ContactsContract.AggregationExceptions;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+
+import com.google.android.collect.Lists;
+
+import com.android.contacts.model.EntityDelta.ValuesDelta;
 
 import java.util.ArrayList;
 
@@ -223,6 +225,30 @@
         return -1;
     }
 
+    public ValuesDelta getSuperPrimaryEntry(final String mimeType) {
+        ValuesDelta primary = null;
+        ValuesDelta randomEntry = null;
+        for (EntityDelta delta : this) {
+            final ArrayList<ValuesDelta> mimeEntries = delta.getMimeEntries(mimeType);
+            if (mimeEntries == null) return null;
+
+            for (ValuesDelta entry : mimeEntries) {
+                if (entry.isSuperPrimary()) {
+                    return entry;
+                } else if (primary == null && entry.isPrimary()) {
+                    primary = entry;
+                } else if (randomEntry == null) {
+                    randomEntry = entry;
+                }
+            }
+        }
+        // When no direct super primary, return something
+        if (primary != null) {
+            return primary;
+        }
+        return randomEntry;
+    }
+
     /** {@inheritDoc} */
     public int describeContents() {
         // Nothing special about this parcel
diff --git a/src/com/android/contacts/ui/EditContactActivity.java b/src/com/android/contacts/ui/EditContactActivity.java
index 450f4a9..9c0c69a 100644
--- a/src/com/android/contacts/ui/EditContactActivity.java
+++ b/src/com/android/contacts/ui/EditContactActivity.java
@@ -33,6 +33,7 @@
 import android.content.Intent;
 import android.content.OperationApplicationException;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.RemoteException;
@@ -41,8 +42,10 @@
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
 import android.provider.ContactsContract.Contacts.Data;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.ContextThemeWrapper;
@@ -62,12 +65,12 @@
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
 import com.android.contacts.ScrollingTabWidget;
-import com.android.contacts.model.GoogleSource;
 import com.android.contacts.model.ContactsSource;
 import com.android.contacts.model.Editor;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityModifier;
 import com.android.contacts.model.EntitySet;
+import com.android.contacts.model.GoogleSource;
 import com.android.contacts.model.Sources;
 import com.android.contacts.model.Editor.EditorListener;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
@@ -131,6 +134,7 @@
         // Build editor and listen for photo requests
         mEditor = (ContactEditorView)this.findViewById(android.R.id.tabcontent);
         mEditor.getPhotoEditor().setEditorListener(this);
+        mEditor.setNameEditorListener(this);
 
         findViewById(R.id.btn_done).setOnClickListener(this);
         findViewById(R.id.btn_discard).setOnClickListener(this);
@@ -141,10 +145,12 @@
         if (Intent.ACTION_EDIT.equals(action) && !hasIncomingState) {
             // Read initial state from database
             new QueryEntitiesTask(this).execute(intent);
-
+            mHeader.showStar(true);
+            mHeader.setContactUri(intent.getData(), false);
         } else if (Intent.ACTION_INSERT.equals(action) && !hasIncomingState) {
             // Trigger dialog to pick account type
             doAddAction();
+            mHeader.showStar(false);
         }
     }
 
@@ -372,20 +378,49 @@
     protected void bindHeader() {
         if (!hasValidState()) return;
 
-        // TODO: rebuild header widget based on internal entities
+        boolean starred = false;
 
-        // TODO: fill header bar with newly parsed data for speed
-        // TODO: handle legacy case correctly instead of assuming _id
+        ValuesDelta photoDelta = mState.getSuperPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
+        if (photoDelta != null) {
+            final byte[] photoBytes = photoDelta.getAsByteArray(Photo.PHOTO);
+            if (photoBytes != null) {
+                Bitmap photo = BitmapFactory.decodeByteArray(photoBytes, 0,
+                        photoBytes.length);
+                mHeader.setPhoto(photo);
+            }
+        }
 
-//        if (mContactId > 0) {
-//            mHeader.bindFromContactId(mContactId);
-//        }
+        ValuesDelta nameDelta = mState.getSuperPrimaryEntry(StructuredName.CONTENT_ITEM_TYPE);
+        if (nameDelta != null) {
+            String visibleName = getVisibleName(nameDelta);
+            if (visibleName != null) {
+                mHeader.setDisplayName(visibleName, null);
+            }
+        }
 
-//        mHeader.setDisplayName(displayName, phoneticName);
-//        mHeader.setPhoto(bitmap);
+        for (EntityDelta delta : mState) {
+            Long isCurrStarred = delta.getValues().getAsLong(RawContacts.STARRED);
+            starred = starred || (isCurrStarred != null && isCurrStarred != 0);
+        }
+        mHeader.setStared(starred);
     }
 
+    private static String getVisibleName(ValuesDelta nameDelta) {
+        final String givenName = nameDelta.getAsString(StructuredName.GIVEN_NAME);
+        final String familyName = nameDelta.getAsString(StructuredName.FAMILY_NAME);
+        final boolean hasGiven = !TextUtils.isEmpty(givenName);
+        final boolean hasFamily = !TextUtils.isEmpty(familyName);
 
+        if (hasGiven && hasFamily) {
+            return givenName + " " + familyName;
+        } else if (hasFamily) {
+            return familyName;
+        } else if (hasGiven) {
+            return givenName;
+        } else {
+            return null;
+        }
+    }
 
     /** {@inheritDoc} */
     public void onTabSelectionChanged(int tabIndex, boolean clicked) {
@@ -452,6 +487,7 @@
                 // state and returned to the last-visible tab.
                 final Bitmap photo = data.getParcelableExtra("data");
                 mEditor.setPhotoBitmap(photo);
+                bindHeader();
                 break;
             }
         }
@@ -708,6 +744,10 @@
                 doPickPhotoAction();
                 break;
             }
+            case EditorListener.FIELD_CHANGED: {
+                bindHeader();
+                break;
+            }
         }
     }
 
diff --git a/src/com/android/contacts/ui/FastTrackWindow.java b/src/com/android/contacts/ui/FastTrackWindow.java
index 25a0167..2f0d212 100644
--- a/src/com/android/contacts/ui/FastTrackWindow.java
+++ b/src/com/android/contacts/ui/FastTrackWindow.java
@@ -675,6 +675,7 @@
                 // Otherwise fall back to default VIEW action
                 mIntent = new Intent(Intent.ACTION_VIEW, mDataUri);
             }
+	    mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         }
 
         /** {@inheritDoc} */
@@ -759,7 +760,9 @@
         /** {@inheritDoc} */
         public Intent getIntent() {
             final Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mId);
-            return new Intent(Intent.ACTION_VIEW, contactUri);
+            final Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
+	    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+	    return intent;
         }
 
         /** {@inheritDoc} */
diff --git a/src/com/android/contacts/ui/widget/ContactEditorView.java b/src/com/android/contacts/ui/widget/ContactEditorView.java
index cd94e52..245986b 100644
--- a/src/com/android/contacts/ui/widget/ContactEditorView.java
+++ b/src/com/android/contacts/ui/widget/ContactEditorView.java
@@ -22,6 +22,7 @@
 import com.android.contacts.model.EntityModifier;
 import com.android.contacts.model.ContactsSource.DataKind;
 import com.android.contacts.model.ContactsSource.EditType;
+import com.android.contacts.model.Editor.EditorListener;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 
 import android.content.Context;
@@ -34,6 +35,7 @@
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.text.TextWatcher;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -173,8 +175,8 @@
         EntityModifier.ensureKindExists(state, source, Photo.CONTENT_ITEM_TYPE);
         mHasPhotoEditor = (source.getKindForMimetype(Photo.CONTENT_ITEM_TYPE) != null);
         mPhoto.setVisibility(mHasPhotoEditor ? View.VISIBLE : View.GONE);
-	mPhoto.setEnabled(!source.readOnly);
-	mName.setEnabled(!source.readOnly);
+        mPhoto.setEnabled(!source.readOnly);
+        mName.setEnabled(!source.readOnly);
 
         mReadOnly.setVisibility(source.readOnly ? View.VISIBLE : View.GONE);
 
@@ -204,4 +206,11 @@
             }
         }
     }
+
+    /**
+     * Sets the {@link EditorListener} on the name field
+     */
+    public void setNameEditorListener(EditorListener listener) {
+        mName.setEditorListener(listener);
+    }
 }
diff --git a/src/com/android/contacts/ui/widget/GenericEditorView.java b/src/com/android/contacts/ui/widget/GenericEditorView.java
index 6387374..6c782f8 100644
--- a/src/com/android/contacts/ui/widget/GenericEditorView.java
+++ b/src/com/android/contacts/ui/widget/GenericEditorView.java
@@ -17,14 +17,13 @@
 package com.android.contacts.ui.widget;
 
 import com.android.contacts.R;
+import com.android.contacts.model.Editor;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityModifier;
 import com.android.contacts.model.ContactsSource.DataKind;
 import com.android.contacts.model.ContactsSource.EditField;
 import com.android.contacts.model.ContactsSource.EditType;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
-import com.android.contacts.model.Editor;
-import com.android.contacts.model.Editor.EditorListener;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -152,6 +151,9 @@
     public void onFieldChanged(String column, String value) {
         // Field changes are saved directly
         mEntry.put(column, value);
+        if (mListener != null) {
+            mListener.onRequest(EditorListener.FIELD_CHANGED);
+        }
     }
 
     private void rebuildValues() {