auto import from //depot/cupcake/@137055
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index ada4778..012a33e 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -79,7 +79,7 @@
     
     static final String[] PHONES_PROJECTION = new String[] {
         Phones.PERSON_ID,
-        Phones.NAME,
+        Phones.DISPLAY_NAME,
         Phones.TYPE,
         Phones.LABEL,
         Phones.NUMBER,
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 6fad5a9..6e72fbd 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -57,8 +57,10 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
 import android.widget.AlphabetIndexer;
+import android.widget.Filter;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.ResourceCursorAdapter;
@@ -87,6 +89,7 @@
     static final int MENU_ITEM_DELETE = 7;
     static final int MENU_ITEM_TOGGLE_STAR = 8;
 
+    public static final int MENU_SEARCH = 1;
     public static final int MENU_DIALER = 9;
     public static final int MENU_NEW_CONTACT = 10;
     public static final int MENU_DISPLAY_GROUP = 11;
@@ -587,13 +590,22 @@
             }
         }
 
-        if (runQuery) {
-            // Calling requery here may cause an ANR, so always do the async query
+        if (mJustCreated && runQuery) {
+            // We need to start a query here the first time the activity is launched, as long
+            // as we aren't doing a filter.
             startQuery();
         }
         mJustCreated = false;
     }
     
+    @Override
+    protected void onRestart() {
+        super.onRestart();
+
+        // The cursor was killed off in onStop(), so we need to get a new one here
+        startQuery();
+    }
+    
     private void updateGroup() {
         if (mDefaultMode) {
             setDefaultMode();
@@ -625,7 +637,7 @@
 
         // We don't want the list to display the empty state, since when we resume it will still
         // be there and show up while the new query is happening. After the async query finished
-        // in response to onResume() setLoading(false) will be called.
+        // in response to onRestart() setLoading(false) will be called.
         mAdapter.setLoading(true);
         mAdapter.changeCursor(null);
 
@@ -644,6 +656,10 @@
             return false;
         }
 
+        // Search
+        menu.add(0, MENU_SEARCH, 0, R.string.menu_search)
+                .setIcon(android.R.drawable.ic_menu_search);
+
         // New contact
         menu.add(0, MENU_NEW_CONTACT, 0, R.string.menu_newContact)
                 .setIcon(android.R.drawable.ic_menu_add)
@@ -720,16 +736,21 @@
     
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        if (item.getItemId() == MENU_DISPLAY_GROUP) {
-            AlertDialog.Builder builder = new AlertDialog.Builder(this)
-                .setTitle(R.string.select_group_title)
-                .setPositiveButton(android.R.string.ok, this)
-                .setNegativeButton(android.R.string.cancel, null);
-            
-            setGroupEntries(builder);
-            
-            builder.show();
-            return true;
+        switch (item.getItemId()) {
+            case MENU_DISPLAY_GROUP:
+                AlertDialog.Builder builder = new AlertDialog.Builder(this)
+                    .setTitle(R.string.select_group_title)
+                    .setPositiveButton(android.R.string.ok, this)
+                    .setNegativeButton(android.R.string.cancel, null);
+                
+                setGroupEntries(builder);
+                
+                builder.show();
+                return true;
+
+            case MENU_SEARCH:
+                startSearch(null, false, null, false);
+                return true;
         }
         return false;
     }
@@ -888,6 +909,11 @@
 
     @Override
     protected void onListItemClick(ListView l, View v, int position, long id) {
+        // Hide soft keyboard, if visible
+        InputMethodManager inputMethodManager = (InputMethodManager)
+                getSystemService(Context.INPUT_METHOD_SERVICE);
+        inputMethodManager.hideSoftInputFromWindow(mList.getWindowToken(), 0);
+
         if (mMode == MODE_INSERT_OR_EDIT_CONTACT) {
             Intent intent;
             if (position == 0) {
@@ -1018,7 +1044,7 @@
 
             case MODE_WITH_PHONES:
                 mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
-                        People.PRIMARY_PHONE_ID + " IS NOT NULL", null, People.DEFAULT_SORT_ORDER);
+                        People.PRIMARY_PHONE_ID + " IS NOT NULL", null, SORT_ORDER);
                 break;
 
             case MODE_QUERY: {
@@ -1075,8 +1101,7 @@
                 } else {
                     uri = Uri.withAppendedPath(mGroupFilterUri, Uri.encode(filter));
                 }
-                return resolver.query(uri, CONTACTS_PROJECTION, null, null,
-                        People.DEFAULT_SORT_ORDER);
+                return resolver.query(uri, CONTACTS_PROJECTION, null, null, SORT_ORDER);
             }
 
             case MODE_ALL_CONTACTS:
@@ -1294,7 +1319,7 @@
         private CharSequence[] mLocalizedLabels;
 
         public ContactItemListAdapter(Context context) {
-            super(context, R.layout.contacts_list_item, null);
+            super(context, R.layout.contacts_list_item, null, false);
             
             mAlphabet = context.getString(com.android.internal.R.string.fast_scroll_alphabet);
             
@@ -1311,6 +1336,24 @@
             }
         }
 
+        /**
+         * Callback on the UI thread when the content observer on the backing cursor fires.
+         * Instead of calling requery we need to do an async query so that the requery doesn't
+         * block the UI thread for a long time. 
+         */
+        @Override
+        protected void onContentChanged() {
+            CharSequence constraint = getListView().getTextFilter();
+            if (!TextUtils.isEmpty(constraint)) {
+                // Reset the filter state then start an async filter operation
+                Filter filter = getFilter();
+                filter.filter(constraint);
+            } else {
+                // Start an async query
+                startQuery();
+            }
+        }
+        
         public void setLoading(boolean loading) {
             mLoading = loading;
         }
diff --git a/src/com/android/contacts/EditContactActivity.java b/src/com/android/contacts/EditContactActivity.java
index c12074e..49569e3 100644
--- a/src/com/android/contacts/EditContactActivity.java
+++ b/src/com/android/contacts/EditContactActivity.java
@@ -69,6 +69,7 @@
 import android.provider.Contacts;
 import android.provider.Contacts.ContactMethods;
 import android.provider.Contacts.Intents.Insert;
+import android.provider.Contacts.Groups;
 import android.provider.Contacts.Organizations;
 import android.provider.Contacts.People;
 import android.provider.Contacts.Phones;
@@ -932,6 +933,44 @@
             if (!TextUtils.isEmpty(displayGroup)) {
                 People.addToGroup(mResolver, ContentUris.parseId(contactUri), displayGroup);
             }
+        } else {
+            // Check to see if we're not syncing everything and if so if My Contacts is synced.
+            // If it isn't then the created contact can end up not in any groups that are
+            // currently synced and end up getting removed from the phone, which is really bad.
+            boolean syncingEverything = !"0".equals(Contacts.Settings.getSetting(mResolver, null,
+                    Contacts.Settings.SYNC_EVERYTHING));
+            if (!syncingEverything) {
+                boolean syncingMyContacts = false;
+                Cursor c = mResolver.query(Groups.CONTENT_URI, new String[] { Groups.SHOULD_SYNC },
+                        Groups.SYSTEM_ID + "=?", new String[] { Groups.GROUP_MY_CONTACTS }, null);
+                if (c != null) {
+                    try {
+                        if (c.moveToFirst()) {
+                            syncingMyContacts = !"0".equals(c.getString(0));
+                        }
+                    } finally {
+                        c.close();
+                    }
+                }
+
+                if (!syncingMyContacts) {
+                    // Not syncing My Contacts, so find a group that is being synced and stick
+                    // the contact in there. We sort the list so at least all contacts
+                    // will appear in the same group.
+                    c = mResolver.query(Groups.CONTENT_URI, new String[] { Groups._ID },
+                            Groups.SHOULD_SYNC + "!=0", null, Groups.DEFAULT_SORT_ORDER);
+                    if (c != null) {
+                        try {
+                            if (c.moveToFirst()) {
+                                People.addToGroup(mResolver, ContentUris.parseId(contactUri),
+                                        c.getLong(0));
+                            }
+                        } finally {
+                            c.close();
+                        }
+                    }
+                }
+            }
         }
 
         // Handle the photo
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index 8d6360b..dbf2879 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -95,7 +95,7 @@
     /** The projection to use when querying the phones table */
     static final String[] PHONES_PROJECTION = new String[] {
             Phones.PERSON_ID,
-            Phones.NAME,
+            Phones.DISPLAY_NAME,
             Phones.TYPE,
             Phones.LABEL,
             Phones.NUMBER