am 85cc962d: DO NOT MERGE - Updated dialer assets (2)

Merge commit '85cc962d35c049bdf44c2846383b0fa6316320ac' into gingerbread-plus-aosp

* commit '85cc962d35c049bdf44c2846383b0fa6316320ac':
  DO NOT MERGE - Updated dialer assets (2)
diff --git a/res/layout-finger/quickcontact_item_nodata.xml b/res/layout-finger/quickcontact_item_nodata.xml
new file mode 100644
index 0000000..5215e30
--- /dev/null
+++ b/res/layout-finger/quickcontact_item_nodata.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingLeft="12dip"
+    android:paddingRight="12dip"
+    android:scaleType="centerInside"
+    android:focusable="false"
+    android:clickable="false"
+    android:gravity="center_vertical"
+    android:background="@drawable/quickcontact_slider_btn_normal"
+    android:textColor="@android:color/black"
+    android:text="@string/quickcontact_no_data" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bcdb8de..5d275aa 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -465,7 +465,7 @@
     </string>
 
     <!-- Activity title for the activity that lets the user choose which groups of contacts to sync from the server -->
-    
+
 
     <!-- Live folder label for all contacts -->
     <string name="liveFolder_all_label">All contacts</string>
@@ -864,6 +864,9 @@
     <!-- Shown as the header name for a person when the name is missing or unknown. -->
     <string name="quickcontact_missing_name">Unknown</string>
 
+    <!-- Text that is shown in the Badge, when there is no data to display -->
+    <string name="quickcontact_no_data">No data</string>
+
     <!-- The menu item to open the list of accounts -->
     <string name="menu_accounts">Accounts</string>
 
@@ -1109,28 +1112,28 @@
 
     <!-- Text describing that a contact has no information available other than name and photo -->
     <string name="no_contact_details">No additional information for this contact</string>
-    
+
     <!-- Label of the "sort list by" display option -->
     <string name="display_options_sort_list_by">Sort list by</string>
-    
+
     <!-- An allowable value for the "sort list by" contact display option  -->
     <string name="display_options_sort_by_given_name">Given name</string>
-    
+
     <!-- An allowable value for the "sort list by" contact display option  -->
     <string name="display_options_sort_by_family_name">Family name</string>
-           
+
     <!-- Label of the "view names as" display option -->
     <string name="display_options_view_names_as">View contact names as</string>
-    
+
     <!-- An allowable value for the "view names as" contact display option  -->
     <string name="display_options_view_given_name_first">Given name first</string>
-    
+
     <!-- An allowable value for the "view names as" contact display option  -->
     <string name="display_options_view_family_name_first">Family name first</string>
-    
+
     <!-- Gray hint displayed in the search field in Contacts when empty -->
     <string name="search_bar_hint">Search contacts</string>
-    
+
     <!-- Button displayed underneath the list of filtered visible contacts -->
     <string name="search_for_all_contacts">Search for all contacts</string>
 
@@ -1148,12 +1151,12 @@
 
     <!-- Text shown in the contacts app if the background process updating contacts fails because of memory shortage -->
     <string name="upgrade_out_of_memory">Contacts are in the process of being upgraded.
-    \n\nThe upgrade process requires approximately <xliff:g id="size_in_megabytes">%d</xliff:g>Mb of 
-    internal phone storage.\n\nChoose one of the following options:</string>
-    
+    \n\nThe upgrade process requires approximately <xliff:g id="size_in_megabytes">%d</xliff:g>
+    Mb of internal phone storage.\n\nChoose one of the following options:</string>
+
     <!-- Button shown in the contacts app if the background process updating contacts fails because of memory shortage -->
     <string name="upgrade_out_of_memory_uninstall">Uninstall some applications</string>
-    
+
     <!-- Button shown in the contacts app if the background process updating contacts fails because of memory shortage -->
     <string name="upgrade_out_of_memory_retry">Retry upgrade</string>
 
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/EntityDelta.java
index 9eb7779..cdf2e41 100644
--- a/src/com/android/contacts/model/EntityDelta.java
+++ b/src/com/android/contacts/model/EntityDelta.java
@@ -59,7 +59,7 @@
     // TODO: optimize by using contentvalues pool, since we allocate so many of them
 
     private static final String TAG = "EntityDelta";
-    private static final boolean LOGV = true;
+    private static final boolean LOGV = false;
 
     /**
      * Direct values from {@link Entity#getEntityValues()}.
diff --git a/src/com/android/contacts/model/EntitySet.java b/src/com/android/contacts/model/EntitySet.java
index 83fe338..830f8da 100644
--- a/src/com/android/contacts/model/EntitySet.java
+++ b/src/com/android/contacts/model/EntitySet.java
@@ -130,11 +130,13 @@
         // Second pass builds actual operations
         for (EntityDelta delta : this) {
             final int firstBatch = diff.size();
-            backRefs[rawContactIndex++] = firstBatch;
+            final boolean isInsert = delta.isContactInsert();
+            backRefs[rawContactIndex++] = isInsert ? firstBatch : -1;
+
             delta.buildDiff(diff);
 
             // Only create rules for inserts
-            if (!delta.isContactInsert()) continue;
+            if (!isInsert) continue;
 
             // If we are going to split all contacts, there is no point in first combining them
             if (mSplitRawContacts) continue;
@@ -208,18 +210,25 @@
         builder.withValue(AggregationExceptions.TYPE, AggregationExceptions.TYPE_KEEP_SEPARATE);
 
         Long rawContactId1 = get(index1).getValues().getAsLong(RawContacts._ID);
+        int backRef1 = backRefs[index1];
         if (rawContactId1 != null && rawContactId1 >= 0) {
             builder.withValue(AggregationExceptions.RAW_CONTACT_ID1, rawContactId1);
+        } else if (backRef1 >= 0) {
+            builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, backRef1);
         } else {
-            builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID1, backRefs[index1]);
+            return;
         }
 
         Long rawContactId2 = get(index2).getValues().getAsLong(RawContacts._ID);
+        int backRef2 = backRefs[index2];
         if (rawContactId2 != null && rawContactId2 >= 0) {
             builder.withValue(AggregationExceptions.RAW_CONTACT_ID2, rawContactId2);
+        } else if (backRef2 >= 0) {
+            builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, backRef2);
         } else {
-            builder.withValueBackReference(AggregationExceptions.RAW_CONTACT_ID2, backRefs[index2]);
+            return;
         }
+
         diff.add(builder.build());
     }
 
diff --git a/src/com/android/contacts/ui/EditContactActivity.java b/src/com/android/contacts/ui/EditContactActivity.java
index f1be8fb..e37aade 100644
--- a/src/com/android/contacts/ui/EditContactActivity.java
+++ b/src/com/android/contacts/ui/EditContactActivity.java
@@ -1389,6 +1389,9 @@
 
         int value;
         if (!skipAccountTypeCheck) {
+            if (oneSource.accountType == null) {
+                return 1;
+            }
             value = oneSource.accountType.compareTo(twoSource.accountType);
             if (value != 0) {
                 return value;
diff --git a/src/com/android/contacts/ui/QuickContactWindow.java b/src/com/android/contacts/ui/QuickContactWindow.java
index 9c6e7ac..889749e 100644
--- a/src/com/android/contacts/ui/QuickContactWindow.java
+++ b/src/com/android/contacts/ui/QuickContactWindow.java
@@ -173,7 +173,6 @@
     private int mRequestedY;
 
     private boolean mHasValidSocial = false;
-    private boolean mHasData = false;
     private boolean mMakePrimary = false;
 
     private ImageView mArrowUp;
@@ -609,7 +608,7 @@
      * {@link #showInternal()} when all data items are present.
      */
     private void considerShowing() {
-        if (mHasData && !mShowing && !mDismissed) {
+        if (!mShowing && !mDismissed) {
             if (mMode == QuickContact.MODE_MEDIUM && !mHasValidSocial) {
                 // Missing valid social, swap medium for small header
                 mHeader.setVisibility(View.GONE);
@@ -634,7 +633,6 @@
         }
 
         handleData(cursor);
-        mHasData = true;
 
         if (!cursor.isClosed()) {
             cursor.close();
@@ -981,8 +979,8 @@
         /** {@inheritDoc} */
         public Intent getIntent() {
             final Intent intent = new Intent(Intent.ACTION_VIEW, mLookupUri);
-	    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-	    return intent;
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            return intent;
         }
 
         /** {@inheritDoc} */
@@ -1279,9 +1277,12 @@
         // All the mime-types to add.
         final Set<String> containedTypes = new HashSet<String>(mActions.keySet());
 
+        boolean hasData = false;
+
         // First, add PRECEDING_MIMETYPES, which are most common.
         for (String mimeType : PRECEDING_MIMETYPES) {
             if (containedTypes.contains(mimeType)) {
+                hasData = true;
                 mTrack.addView(inflateAction(mimeType), index++);
                 containedTypes.remove(mimeType);
             }
@@ -1293,6 +1294,7 @@
         // Then, add FOLLOWING_MIMETYPES, which are least common.
         for (String mimeType : FOLLOWING_MIMETYPES) {
             if (containedTypes.contains(mimeType)) {
+                hasData = true;
                 mTrack.addView(inflateAction(mimeType), index++);
                 containedTypes.remove(mimeType);
             }
@@ -1301,10 +1303,17 @@
         // Go back to just after PRECEDING_MIMETYPES, and append the rest.
         index = indexAfterPreceding;
         final String[] remainingTypes = containedTypes.toArray(new String[containedTypes.size()]);
+        if (remainingTypes.length > 0) hasData = true;
         Arrays.sort(remainingTypes);
         for (String mimeType : remainingTypes) {
             mTrack.addView(inflateAction(mimeType), index++);
         }
+
+        // When there is no data to display, add a TextView to show the user there's no data
+        if (!hasData) {
+            View view = mInflater.inflate(R.layout.quickcontact_item_nodata, mTrack, false);
+            mTrack.addView(view, index++);
+        }
     }
 
     /**
@@ -1337,6 +1346,10 @@
      * possible recycling during another pass.
      */
     private synchronized void releaseView(View view) {
+        // Only add CheckableImageViews
+        if (!(view instanceof CheckableImageView)) {
+            return;
+        }
         mActionPool.offer(view);
         mActionRecycled++;
     }
diff --git a/tests/src/com/android/contacts/EntitySetTests.java b/tests/src/com/android/contacts/EntitySetTests.java
index edfca6d..037c927 100644
--- a/tests/src/com/android/contacts/EntitySetTests.java
+++ b/tests/src/com/android/contacts/EntitySetTests.java
@@ -358,6 +358,58 @@
         assertEquals("Unexpected exception updates", 2, exceptionCount);
     }
 
+    public void testInsertInsertSeparate() {
+        // This assumes getInsert() will return back an "empty" raw
+        // contact meaning it will contain no actual information
+        final EntityDelta insertFirst = getInsert();
+        final EntityDelta insertSecond = getInsert();
+        final EntitySet set = buildSet(insertFirst, insertSecond);
+
+        // This would normally build a TYPE_KEEP_SEPARATE aggregation exception,
+        // but since the raw contacts won't be added because they are empty,
+        // we should get 0 exceptions back
+        set.splitRawContacts();
+
+        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+        final int exceptionCount = countExceptionUpdates(diff);
+        assertEquals("Unexpected exception updates", 0, exceptionCount);
+    }
+
+    public void testUpdateInsertSeparate() {
+        // This assumes getInsert() will return back an "empty" raw
+        // contact meaning it will contain no actual information
+        final EntityDelta update = getUpdate(CONTACT_FIRST);
+        final EntityDelta insert = getInsert();
+        final EntitySet set = buildSet(update, insert);
+
+        // This would normally build a KEEP_SEPARATE aggregation exception,
+        // but since the insert won't be added because it is empty,
+        // we should get 0 exceptions back
+        set.splitRawContacts();
+
+        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+        final int exceptionCount = countExceptionUpdates(diff);
+        assertEquals("Unexpected exception updates", 0, exceptionCount);
+    }
+
+    public void testUpdateInsertInsertSeparate() {
+        // This assumes getInsert() will return back an "empty" raw
+        // contact meaning it will contain no actual information
+        final EntityDelta update = getUpdate(CONTACT_FIRST);
+        final EntityDelta insertFirst = getInsert();
+        final EntityDelta insertSecond = getInsert();
+        final EntitySet set = buildSet(update, insertFirst, insertSecond);
+
+        // This would normally build a KEEP_SEPARATE aggregation exception,
+        // but since the inserts won't be added because they are empty,
+        // we should get 0 exceptions back
+        set.splitRawContacts();
+
+        final ArrayList<ContentProviderOperation> diff = set.buildDiff();
+        final int exceptionCount = countExceptionUpdates(diff);
+        assertEquals("Unexpected exception updates", 0, exceptionCount);
+    }
+
     public void testMergeDataRemoteInsert() {
         final EntitySet first = buildSet(buildBeforeEntity(CONTACT_BOB, VER_FIRST,
                 buildPhone(PHONE_RED)));