Reconcile with jb-release nakasi-factoryrom-release

Change-Id: I3b1537c86c60cde239ddc283531ee4735aa97046
diff --git a/res/layout-sw580dp/search_header.xml b/res/layout-sw580dp/search_header.xml
index cf09190..85f0169 100644
--- a/res/layout-sw580dp/search_header.xml
+++ b/res/layout-sw580dp/search_header.xml
@@ -16,9 +16,10 @@
 
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:id="@+id/totalContactsText"
     android:minHeight="@dimen/contact_filter_header_min_height"
-    android:paddingTop="10dip"
-    android:textAppearance="?android:attr/textAppearanceSmall"
-    android:textColor="?android:attr/textColorTertiary"
-    android:textStyle="bold" />
+    android:paddingTop="24dip"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textColor="?android:attr/textColorTertiary" />
diff --git a/res/layout/search_header.xml b/res/layout/search_header.xml
index 44e4632..6907a62 100644
--- a/res/layout/search_header.xml
+++ b/res/layout/search_header.xml
@@ -16,8 +16,11 @@
 
 <TextView
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:id="@+id/totalContactsText"
     android:minHeight="@dimen/contact_filter_header_min_height"
-    android:paddingTop="10dip"
-    android:textAppearance="?android:attr/textAppearanceSmall"
-    android:textColor="?android:attr/textColorSecondary" />
\ No newline at end of file
+    android:paddingTop="24dip"
+    android:gravity="center_horizontal"
+    android:textAppearance="?android:attr/textAppearanceLarge"
+    android:textColor="?android:attr/textColorSecondary" />
diff --git a/res/mipmap-hdpi/ic_launcher_contacts.png b/res/mipmap-hdpi/ic_launcher_contacts.png
index fa60a53..e0136f6 100644
--- a/res/mipmap-hdpi/ic_launcher_contacts.png
+++ b/res/mipmap-hdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/mipmap-hdpi/ic_launcher_shortcut_contact.png b/res/mipmap-hdpi/ic_launcher_shortcut_contact.png
index c867181..e132cd0 100644
--- a/res/mipmap-hdpi/ic_launcher_shortcut_contact.png
+++ b/res/mipmap-hdpi/ic_launcher_shortcut_contact.png
Binary files differ
diff --git a/res/mipmap-hdpi/ic_launcher_shortcut_directdial.png b/res/mipmap-hdpi/ic_launcher_shortcut_directdial.png
index c515815..f6ec866 100644
--- a/res/mipmap-hdpi/ic_launcher_shortcut_directdial.png
+++ b/res/mipmap-hdpi/ic_launcher_shortcut_directdial.png
Binary files differ
diff --git a/res/mipmap-hdpi/ic_launcher_shortcut_directmessage.png b/res/mipmap-hdpi/ic_launcher_shortcut_directmessage.png
index a347fa1..c8eb467 100644
--- a/res/mipmap-hdpi/ic_launcher_shortcut_directmessage.png
+++ b/res/mipmap-hdpi/ic_launcher_shortcut_directmessage.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_contacts.png b/res/mipmap-mdpi/ic_launcher_contacts.png
index b50d7dd..3d490c3 100644
--- a/res/mipmap-mdpi/ic_launcher_contacts.png
+++ b/res/mipmap-mdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_shortcut_contact.png b/res/mipmap-mdpi/ic_launcher_shortcut_contact.png
index dd3c8ff..218c915 100644
--- a/res/mipmap-mdpi/ic_launcher_shortcut_contact.png
+++ b/res/mipmap-mdpi/ic_launcher_shortcut_contact.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_shortcut_directdial.png b/res/mipmap-mdpi/ic_launcher_shortcut_directdial.png
index 1dfe8cc..50278c3 100644
--- a/res/mipmap-mdpi/ic_launcher_shortcut_directdial.png
+++ b/res/mipmap-mdpi/ic_launcher_shortcut_directdial.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher_shortcut_directmessage.png b/res/mipmap-mdpi/ic_launcher_shortcut_directmessage.png
index c7dc525..698971b 100644
--- a/res/mipmap-mdpi/ic_launcher_shortcut_directmessage.png
+++ b/res/mipmap-mdpi/ic_launcher_shortcut_directmessage.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_contacts.png b/res/mipmap-xhdpi/ic_launcher_contacts.png
index 4b7eaaa..dde3cbb 100644
--- a/res/mipmap-xhdpi/ic_launcher_contacts.png
+++ b/res/mipmap-xhdpi/ic_launcher_contacts.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_shortcut_contact.png b/res/mipmap-xhdpi/ic_launcher_shortcut_contact.png
index baeb41f..8a5e25a 100644
--- a/res/mipmap-xhdpi/ic_launcher_shortcut_contact.png
+++ b/res/mipmap-xhdpi/ic_launcher_shortcut_contact.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_shortcut_directdial.png b/res/mipmap-xhdpi/ic_launcher_shortcut_directdial.png
index 39d039a..e060bc5 100644
--- a/res/mipmap-xhdpi/ic_launcher_shortcut_directdial.png
+++ b/res/mipmap-xhdpi/ic_launcher_shortcut_directdial.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher_shortcut_directmessage.png b/res/mipmap-xhdpi/ic_launcher_shortcut_directmessage.png
index 7dd5d39..3222dc8 100644
--- a/res/mipmap-xhdpi/ic_launcher_shortcut_directmessage.png
+++ b/res/mipmap-xhdpi/ic_launcher_shortcut_directmessage.png
Binary files differ
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e24a7c3..8292a56 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -349,7 +349,7 @@
     <string name="foundTooManyContacts">More than <xliff:g id="count">%d</xliff:g> found.</string>
 
     <!-- Displayed at the top of the contacts showing the zero total number of contacts found when "Only contacts with phones" not selected. [CHAR LIMIT=30] -->
-    <string name="listFoundAllContactsZero">None found.</string>
+    <string name="listFoundAllContactsZero">No contacts</string>
 
     <!-- Displayed at the top of the contacts showing the total number of contacts found when typing search query -->
     <plurals name="searchFoundContacts">
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index ab2ac41..10579f3 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -84,22 +84,25 @@
     private boolean mLoadGroupMetaData;
     private boolean mLoadStreamItems;
     private boolean mLoadInvitableAccountTypes;
+    private boolean mPostViewNotification;
     private Result mContact;
     private ForceLoadContentObserver mObserver;
     private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
 
-    public ContactLoader(Context context, Uri lookupUri) {
-        this(context, lookupUri, false, false, false);
+    public ContactLoader(Context context, Uri lookupUri, boolean postViewNotification) {
+        this(context, lookupUri, false, false, false, postViewNotification);
     }
 
     public ContactLoader(Context context, Uri lookupUri, boolean loadGroupMetaData,
-            boolean loadStreamItems, boolean loadInvitableAccountTypes) {
+            boolean loadStreamItems, boolean loadInvitableAccountTypes,
+            boolean postViewNotification) {
         super(context);
         mLookupUri = lookupUri;
         mRequestedUri = lookupUri;
         mLoadGroupMetaData = loadGroupMetaData;
         mLoadStreamItems = loadStreamItems;
         mLoadInvitableAccountTypes = loadInvitableAccountTypes;
+        mPostViewNotification = postViewNotification;
     }
 
     /**
@@ -1236,8 +1239,10 @@
                         mLookupUri, true, mObserver);
             }
 
-            // inform the source of the data that this contact is being looked at
-            postViewNotificationToSyncAdapter();
+            if (mPostViewNotification) {
+                // inform the source of the data that this contact is being looked at
+                postViewNotificationToSyncAdapter();
+            }
         }
 
         super.deliverResult(mContact);
@@ -1301,11 +1306,13 @@
      */
     public void upgradeToFullContact() {
         // Everything requested already? Nothing to do, so let's bail out
-        if (mLoadGroupMetaData && mLoadInvitableAccountTypes && mLoadStreamItems) return;
+        if (mLoadGroupMetaData && mLoadInvitableAccountTypes && mLoadStreamItems
+                && mPostViewNotification) return;
 
         mLoadGroupMetaData = true;
         mLoadInvitableAccountTypes = true;
         mLoadStreamItems = true;
+        mPostViewNotification = true;
 
         // Cache the current result, so that we only load the "missing" parts of the contact.
         cacheResult();
diff --git a/src/com/android/contacts/ViewNotificationService.java b/src/com/android/contacts/ViewNotificationService.java
index a0890f2..a85c780 100644
--- a/src/com/android/contacts/ViewNotificationService.java
+++ b/src/com/android/contacts/ViewNotificationService.java
@@ -40,7 +40,7 @@
 
         // We simply need to start a Loader here. When its done, it will send out the
         // View-Notification automatically.
-        final ContactLoader contactLoader = new ContactLoader(this, intent.getData());
+        final ContactLoader contactLoader = new ContactLoader(this, intent.getData(), true);
         contactLoader.registerListener(0, new OnLoadCompleteListener<ContactLoader.Result>() {
             @Override
             public void onLoadComplete(Loader<Result> loader, Result data) {
diff --git a/src/com/android/contacts/activities/AttachPhotoActivity.java b/src/com/android/contacts/activities/AttachPhotoActivity.java
index 5a26ea2..7ae6e1e 100644
--- a/src/com/android/contacts/activities/AttachPhotoActivity.java
+++ b/src/com/android/contacts/activities/AttachPhotoActivity.java
@@ -149,7 +149,7 @@
     // although this is convenient, it isn't quite as robust as using LoaderManager... for
     // instance, the loader doesn't persist across Activity restarts.
     private void loadContact(Uri contactUri, final Listener listener) {
-        final ContactLoader loader = new ContactLoader(this, contactUri);
+        final ContactLoader loader = new ContactLoader(this, contactUri, true);
         loader.registerListener(0, new OnLoadCompleteListener<ContactLoader.Result>() {
             @Override
             public void onLoadComplete(
diff --git a/src/com/android/contacts/detail/ContactLoaderFragment.java b/src/com/android/contacts/detail/ContactLoaderFragment.java
index 25c60d6..242b12b 100644
--- a/src/com/android/contacts/detail/ContactLoaderFragment.java
+++ b/src/com/android/contacts/detail/ContactLoaderFragment.java
@@ -185,7 +185,8 @@
         public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
             Uri lookupUri = args.getParcelable(LOADER_ARG_CONTACT_URI);
             return new ContactLoader(mContext, lookupUri, true /* loadGroupMetaData */,
-                    true /* loadStreamItems */, true /* load invitable account types */);
+                    true /* loadStreamItems */, true /* load invitable account types */,
+                    true /* postViewNotification */);
         }
 
         @Override
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index cd9d98b..962a46b 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -23,7 +23,6 @@
 import com.android.contacts.activities.ContactEditorAccountsChangedActivity;
 import com.android.contacts.activities.ContactEditorActivity;
 import com.android.contacts.activities.JoinContactActivity;
-import com.android.contacts.activities.PhotoSelectionActivity;
 import com.android.contacts.detail.PhotoSelectionHandler;
 import com.android.contacts.editor.AggregationSuggestionEngine.Suggestion;
 import com.android.contacts.editor.Editor.EditorListener;
@@ -66,6 +65,7 @@
 import android.provider.ContactsContract.CommonDataKinds.Event;
 import android.provider.ContactsContract.CommonDataKinds.Organization;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Photo;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Groups;
@@ -104,7 +104,6 @@
     private static final String KEY_URI = "uri";
     private static final String KEY_ACTION = "action";
     private static final String KEY_EDIT_STATE = "state";
-    private static final String KEY_RAW_CONTACT_ID_REQUESTING_PHOTO = "photorequester";
     private static final String KEY_VIEW_ID_GENERATOR = "viewidgenerator";
     private static final String KEY_CURRENT_PHOTO_FILE = "currentphotofile";
     private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
@@ -190,8 +189,7 @@
     private static final int REQUEST_CODE_JOIN = 0;
     private static final int REQUEST_CODE_ACCOUNTS_CHANGED = 1;
 
-    private long mRawContactIdRequestingPhoto = -1;
-    private PhotoSelectionHandler mPhotoSelectionHandler;
+    private PhotoHandler mCurrentPhotoHandler;
 
     private final EntityDeltaComparator mComparator = new EntityDeltaComparator();
 
@@ -409,8 +407,6 @@
         } else {
             // Read state from savedState. No loading involved here
             mState = savedState.<EntityDeltaList> getParcelable(KEY_EDIT_STATE);
-            mRawContactIdRequestingPhoto = savedState.getLong(
-                    KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
             mViewIdGenerator = savedState.getParcelable(KEY_VIEW_ID_GENERATOR);
             mCurrentPhotoFile = savedState.getString(KEY_CURRENT_PHOTO_FILE);
             mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
@@ -806,9 +802,9 @@
                 return;
             }
         }
-        mPhotoSelectionHandler = new PhotoHandler(mContext, editor, mode, state);
+        final PhotoHandler photoHandler = new PhotoHandler(mContext, editor, mode, state);
         editor.getPhotoEditor().setEditorListener(
-                (PhotoHandler.PhotoEditorListener) mPhotoSelectionHandler.getListener());
+                (PhotoHandler.PhotoEditorListener) photoHandler.getListener());
     }
 
     private void bindGroupMetaData() {
@@ -1087,7 +1083,6 @@
 
     public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
             Uri contactLookupUri) {
-        Log.d(TAG, "onSaveCompleted(" + saveMode + ", " + contactLookupUri);
         if (hadChanges) {
             if (saveSucceeded) {
                 if (saveMode != SaveMode.JOIN) {
@@ -1541,7 +1536,6 @@
             outState.putParcelable(KEY_EDIT_STATE, mState);
         }
 
-        outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
         outState.putParcelable(KEY_VIEW_ID_GENERATOR, mViewIdGenerator);
         outState.putString(KEY_CURRENT_PHOTO_FILE, mCurrentPhotoFile);
         outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
@@ -1563,7 +1557,7 @@
         }
 
         // See if the photo selection handler handles this result.
-        if (mPhotoSelectionHandler != null && mPhotoSelectionHandler.handlePhotoActivityResult(
+        if (mCurrentPhotoHandler != null && mCurrentPhotoHandler.handlePhotoActivityResult(
                 requestCode, resultCode, data)) {
             return;
         }
@@ -1643,19 +1637,31 @@
      * Returns true if there is currently more than one photo on screen.
      */
     private boolean hasMoreThanOnePhoto() {
-        int count = mContent.getChildCount();
         int countWithPicture = 0;
-        for (int i = 0; i < count; i++) {
-            final View childView = mContent.getChildAt(i);
-            if (childView instanceof BaseRawContactEditorView) {
-                final BaseRawContactEditorView editor = (BaseRawContactEditorView) childView;
-                if (editor.hasSetPhoto()) {
+        final int numEntities = mState.size();
+        for (int i = 0; i < numEntities; i++) {
+            final EntityDelta entity = mState.get(i);
+            final ValuesDelta values = entity.getValues();
+            if (values.isVisible()) {
+                final ValuesDelta primary = entity.getPrimaryEntry(Photo.CONTENT_ITEM_TYPE);
+                if (primary.getAsByteArray(Photo.PHOTO) != null) {
                     countWithPicture++;
-                    if (countWithPicture > 1) return true;
+                } else {
+                    final long rawContactId = values.getAsLong(RawContacts._ID);
+                    final String path = mUpdatedPhotos.getString(String.valueOf(rawContactId));
+                    if (path != null) {
+                        final File file = new File(path);
+                        if (file.exists()) {
+                            countWithPicture++;
+                        }
+                    }
+                }
+
+                if (countWithPicture > 1) {
+                    return true;
                 }
             }
         }
-
         return false;
     }
 
@@ -1667,7 +1673,7 @@
         @Override
         public Loader<ContactLoader.Result> onCreateLoader(int id, Bundle args) {
             mLoaderStartTime = SystemClock.elapsedRealtime();
-            return new ContactLoader(mContext, mLookupUri);
+            return new ContactLoader(mContext, mLookupUri, true);
         }
 
         @Override
@@ -1758,7 +1764,7 @@
 
         @Override
         public void startPhotoActivity(Intent intent, int requestCode, String photoFile) {
-            mRawContactIdRequestingPhoto = mEditor.getRawContactId();
+            mCurrentPhotoHandler = this;
             mStatus = Status.SUB_ACTIVITY;
             mCurrentPhotoFile = photoFile;
             ContactEditorFragment.this.startActivityForResult(intent, requestCode);
@@ -1798,6 +1804,7 @@
                         photoEditor.setSuperPrimary(editor == mEditor);
                     }
                 }
+                bindEditors();
             }
 
             /**
@@ -1810,12 +1817,14 @@
                 // Prevent bitmap from being restored if rotate the device.
                 // (only if we first chose a new photo before removing it)
                 mUpdatedPhotos.remove(String.valueOf(mRawContactId));
+                bindEditors();
             }
 
             @Override
             public void onPhotoSelected(Bitmap bitmap) {
-                setPhoto(mRawContactIdRequestingPhoto, bitmap, mCurrentPhotoFile);
-                mRawContactIdRequestingPhoto = -1;
+                setPhoto(mCurrentPhotoHandler.mRawContactId, bitmap, mCurrentPhotoFile);
+                mCurrentPhotoHandler = null;
+                bindEditors();
             }
 
             @Override
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 9c71ee2..7c93a26 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -562,7 +562,7 @@
             if (mLookupUri == null) {
                 Log.wtf(TAG, "Lookup uri wasn't initialized. Loader was started too early");
             }
-            return new ContactLoader(getApplicationContext(), mLookupUri);
+            return new ContactLoader(getApplicationContext(), mLookupUri, false);
         }
     };
 
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index 6b56470..3283efd 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -116,7 +116,7 @@
             return;
         }
         final ContactLoader contactLoader = new ContactLoader(context, contactUri, false, true,
-                false);
+                false, true);
         contactLoader.registerListener(0,
                 new ContactLoader.OnLoadCompleteListener<ContactLoader.Result>() {
                     @Override
diff --git a/tests/src/com/android/contacts/ContactLoaderTest.java b/tests/src/com/android/contacts/ContactLoaderTest.java
index f88b64e..5c215f9 100644
--- a/tests/src/com/android/contacts/ContactLoaderTest.java
+++ b/tests/src/com/android/contacts/ContactLoaderTest.java
@@ -75,7 +75,7 @@
     }
 
     private ContactLoader.Result assertLoadContact(Uri uri) {
-        final ContactLoader loader = new ContactLoader(mMockContext, uri);
+        final ContactLoader loader = new ContactLoader(mMockContext, uri, true);
         return getLoaderResultSynchronously(loader);
     }