Merge "Suppress tts on every digits change"
diff --git a/res/layout/dialpad_fragment.xml b/res/layout/dialpad_fragment.xml
index 75d5938..b2784e2 100644
--- a/res/layout/dialpad_fragment.xml
+++ b/res/layout/dialpad_fragment.xml
@@ -52,6 +52,7 @@
             android:layout_height="match_parent"
             android:layout_alignParentRight="true"
             android:src="@drawable/ic_menu_overflow"
+            android:contentDescription="@*android:string/action_menu_overflow_description"
             android:background="@android:color/transparent"/>
 
     </RelativeLayout>
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 78c4b18..2df2e47 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -18,6 +18,7 @@
 
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.AccountWithDataSet;
+import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDeltaList;
 import com.android.contacts.model.EntityModifier;
 import com.google.android.collect.Lists;
@@ -48,6 +49,7 @@
 import android.provider.ContactsContract.Groups;
 import android.provider.ContactsContract.Profile;
 import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.RawContactsEntity;
 import android.util.Log;
 import android.widget.Toast;
 
@@ -355,9 +357,19 @@
                     throw new IllegalStateException("Version consistency failed for a new contact");
                 }
 
-                final EntityDeltaList newState = EntityDeltaList.fromQuery(resolver,
-                        sb.toString(), null, null);
+                final EntityDeltaList newState = EntityDeltaList.fromQuery(
+                        isProfile
+                                ? RawContactsEntity.PROFILE_CONTENT_URI
+                                : RawContactsEntity.CONTENT_URI,
+                        resolver, sb.toString(), null, null);
                 state = EntityDeltaList.mergeAfter(newState, state);
+
+                // Update the new state to use profile URIs if appropriate.
+                if (isProfile) {
+                    for (EntityDelta delta : state) {
+                        delta.setProfileQueryUri();
+                    }
+                }
             }
         }
 
diff --git a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
index 418c8e3..3d4b70f 100644
--- a/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
+++ b/src/com/android/contacts/activities/ConfirmAddDetailActivity.java
@@ -58,6 +58,7 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.RawContactsEntity;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
@@ -378,7 +379,10 @@
                 mSelection = Data.RAW_CONTACT_ID + "=?";
             }
 
-            return EntityDeltaList.fromQuery(activityTarget.getContentResolver(), mSelection,
+            // Note that this query does not need to concern itself with whether the contact is
+            // the user's profile, since the profile does not show up in the picker.
+            return EntityDeltaList.fromQuery(RawContactsEntity.CONTENT_URI,
+                    activityTarget.getContentResolver(), mSelection,
                     new String[] { selectionArg }, null);
         }
 
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 9abcef1..2e54642 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -479,9 +479,26 @@
 
         // For user profile, change the contacts query URI
         mIsUserProfile = data.isUserProfile();
+        boolean localProfileExists = false;
+
         if (mIsUserProfile) {
             for (EntityDelta state : mState) {
+                // For profile contacts, we need a different query URI
                 state.setProfileQueryUri();
+                // Try to find a local profile contact
+                if (state.getValues().getAsString(RawContacts.ACCOUNT_TYPE) == null) {
+                    localProfileExists = true;
+                }
+            }
+            // Editor should always present a local profile for editing
+            if (!localProfileExists) {
+                final ContentValues values = new ContentValues();
+                values.putNull(RawContacts.ACCOUNT_NAME);
+                values.putNull(RawContacts.ACCOUNT_TYPE);
+                values.putNull(RawContacts.DATA_SET);
+                EntityDelta insert = new EntityDelta(ValuesDelta.fromAfter(values));
+                insert.setProfileQueryUri();
+                mState.add(insert);
             }
         }
         mRequestFocus = true;
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index 7e81dcd..c8778c2 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -33,6 +33,9 @@
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Contacts;
 import android.text.TextUtils;
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
@@ -46,6 +49,11 @@
 import android.widget.QuickContactBadge;
 import android.widget.TextView;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * A custom view for an item in the contact list.
  * The view contains the contact's photo, a set of text views (for name, status, etc...) and
@@ -1094,8 +1102,25 @@
             setSnippet(null);
             return;
         }
+        String snippet;
+        String columnContent = cursor.getString(summarySnippetColumnIndex);
 
-        String snippet = cursor.getString(summarySnippetColumnIndex);
+        // Do client side snippeting if provider didn't do it
+        Bundle extras = cursor.getExtras();
+        if (extras.getBoolean(ContactsContract.DEFERRED_SNIPPETING)) {
+            int displayNameIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
+
+            snippet = ContactsContract.snippetize(columnContent,
+                    displayNameIndex < 0 ? null : cursor.getString(displayNameIndex),
+                            extras.getString(ContactsContract.DEFERRED_SNIPPETING_QUERY),
+                            DefaultContactListAdapter.SNIPPET_START_MATCH,
+                            DefaultContactListAdapter.SNIPPET_END_MATCH,
+                            DefaultContactListAdapter.SNIPPET_ELLIPSIS,
+                            DefaultContactListAdapter.SNIPPET_MAX_TOKENS);
+        } else {
+            snippet = columnContent;
+        }
+
         if (snippet != null) {
             int from = 0;
             int to = snippet.length();
diff --git a/src/com/android/contacts/list/DefaultContactListAdapter.java b/src/com/android/contacts/list/DefaultContactListAdapter.java
index f202522..2a8d665 100644
--- a/src/com/android/contacts/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/list/DefaultContactListAdapter.java
@@ -85,6 +85,7 @@
                 }
                 builder.appendQueryParameter(SearchSnippetColumns.SNIPPET_ARGS_PARAM_KEY,
                         SNIPPET_ARGS);
+                builder.appendQueryParameter(SearchSnippetColumns.DEFERRED_SNIPPETING_KEY,"1");
                 loader.setUri(builder.build());
                 loader.setProjection(FILTER_PROJECTION);
             }
diff --git a/src/com/android/contacts/model/EntityDeltaList.java b/src/com/android/contacts/model/EntityDeltaList.java
index 9b7bdc6..5a9355b 100644
--- a/src/com/android/contacts/model/EntityDeltaList.java
+++ b/src/com/android/contacts/model/EntityDeltaList.java
@@ -21,6 +21,7 @@
 import android.content.Entity;
 import android.content.EntityIterator;
 import android.content.ContentProviderOperation.Builder;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.provider.ContactsContract.AggregationExceptions;
@@ -63,10 +64,10 @@
      * given query parameters. This closes the {@link EntityIterator} when
      * finished, so it doesn't subscribe to updates.
      */
-    public static EntityDeltaList fromQuery(ContentResolver resolver, String selection,
-            String[] selectionArgs, String sortOrder) {
+    public static EntityDeltaList fromQuery(Uri entityUri, ContentResolver resolver,
+            String selection, String[] selectionArgs, String sortOrder) {
         final EntityIterator iterator = RawContacts.newEntityIterator(resolver.query(
-                RawContactsEntity.CONTENT_URI, null, selection, selectionArgs,
+                entityUri, null, selection, selectionArgs,
                 sortOrder));
         try {
             return fromIterator(iterator);