Pass full res contact photos between the compact and full editors

Bug 19624360
Bug 19655206

Change-Id: I590ec7ecec75a9af95b824f5db9cda8f8aeda675
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index d81867c..266ea46 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -330,6 +330,9 @@
             Intent callbackIntent = new Intent(context, callbackActivity);
             callbackIntent.putExtra(saveModeExtraKey, saveMode);
             callbackIntent.setAction(callbackAction);
+            if (updatedPhotos != null) {
+                callbackIntent.putExtra(EXTRA_UPDATED_PHOTOS, (Parcelable) updatedPhotos);
+            }
             serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
         }
         return serviceIntent;
diff --git a/src/com/android/contacts/activities/ContactEditorBaseActivity.java b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
index 25846bc..acc754e 100644
--- a/src/com/android/contacts/activities/ContactEditorBaseActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
@@ -161,7 +161,7 @@
          * Invoked after the contact is saved.
          */
         void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
-                Uri contactLookupUri);
+                Uri contactLookupUri, Bundle updatedPhotos);
 
         /**
          * Invoked after the contact is joined.
@@ -238,7 +238,8 @@
                     intent.getIntExtra(ContactEditorFragment.SAVE_MODE_EXTRA_KEY,
                             ContactEditor.SaveMode.CLOSE),
                     intent.getBooleanExtra(ContactSaveService.EXTRA_SAVE_SUCCEEDED, false),
-                    intent.getData());
+                    intent.getData(),
+                    (Bundle) intent.getParcelableExtra(ContactSaveService.EXTRA_UPDATED_PHOTOS));
         } else if (ACTION_JOIN_COMPLETED.equals(action)) {
             mFragment.onJoinCompleted(intent.getData());
         }
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index 9a96262..f33f796 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -78,6 +78,10 @@
                 }
                 getContent().setPhoto(bitmap);
 
+                // Clear any previously saved full resolution photos under negative raw contact IDs
+                // so that we will use the newly selected photo, instead of an old one on rotations.
+                removeNewRawContactPhotos();
+
                 // If a new photo was chosen but not yet saved,
                 // we need to update the UI immediately
                 mUpdatedPhotos.putParcelable(String.valueOf(mPhotoRawContactId), uri);
@@ -129,7 +133,6 @@
     private PhotoHandler mPhotoHandler;
     private Uri mPhotoUri;
     private long mPhotoRawContactId;
-    private Bundle mUpdatedPhotos = new Bundle();
     private boolean mShowToastAfterSave = true;
 
     @Override
@@ -139,7 +142,6 @@
         if (savedState != null) {
             mPhotoUri = savedState.getParcelable(KEY_PHOTO_URI);
             mPhotoRawContactId = savedState.getLong(KEY_PHOTO_RAW_CONTACT_ID);
-            mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
         }
     }
 
@@ -157,7 +159,6 @@
     public void onSaveInstanceState(Bundle outState) {
         outState.putParcelable(KEY_PHOTO_URI, mPhotoUri);
         outState.putLong(KEY_PHOTO_RAW_CONTACT_ID, mPhotoRawContactId);
-        outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
         super.onSaveInstanceState(outState);
     }
 
@@ -217,7 +218,19 @@
         // Set up the photo widget
         mPhotoHandler = createPhotoHandler();
         mPhotoRawContactId = editorView.getPhotoRawContactId();
-        if (mUpdatedPhotos.containsKey(String.valueOf(mPhotoRawContactId))) {
+        if (mPhotoRawContactId < 0) {
+            // Since the raw contact IDs for new contacts are random negative numbers
+            // we consider any negative key a match
+            for (String key : mUpdatedPhotos.keySet()) {
+                try {
+                    if (Integer.parseInt(key) < 0) {
+                        editorView.setFullSizePhoto((Uri) mUpdatedPhotos.getParcelable(key));
+                        break;
+                    }
+                } catch (NumberFormatException ignored) {
+                }
+            }
+        } else if (mUpdatedPhotos.containsKey(String.valueOf(mPhotoRawContactId))) {
             editorView.setFullSizePhoto((Uri) mUpdatedPhotos.getParcelable(
                     String.valueOf(mPhotoRawContactId)));
         }
@@ -356,7 +369,7 @@
 
         // Prepare an Intent to start the expanded editor
         final Intent intent = isInsert
-                ? EditorIntents.createInsertContactIntent(mState, getDisplayName())
+                ? EditorIntents.createInsertContactIntent(mState, getDisplayName(), mUpdatedPhotos)
                 : EditorIntents.createEditContactIntent(mLookupUri, getMaterialPalette());
         ImplicitIntentsUtil.startActivityInApp(getActivity(), intent);
 
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index 258747d..5e9a987 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -142,6 +142,8 @@
     // Join Activity
     private static final String KEY_CONTACT_ID_FOR_JOIN = "contactidforjoin";
 
+    private static final String KEY_UPDATED_PHOTOS = "updatedPhotos";
+
     protected static final int REQUEST_CODE_JOIN = 0;
     protected static final int REQUEST_CODE_ACCOUNTS_CHANGED = 1;
     protected static final int REQUEST_CODE_PICK_RINGTONE = 2;
@@ -165,6 +167,12 @@
     public static final String INTENT_EXTRA_MATERIAL_PALETTE = "material_palette";
 
     /**
+     * Intent key to pass a Bundle of raw contact IDs to photos URIs between the compact editor
+     * and the fully expanded one.
+     */
+    public static final String INTENT_EXTRA_UPDATED_PHOTOS = "updated_photos";
+
+    /**
      * Intent extra to specify a {@link ContactEditor.SaveMode}.
      */
     public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
@@ -342,6 +350,9 @@
     // Join Activity
     protected long mContactIdForJoin;
 
+    // Full resolution photo URIs
+    protected Bundle mUpdatedPhotos = new Bundle();
+
     //
     // Editor state for {@link ContactEditorView}.
     // (Not saved/restored on rotates)
@@ -474,6 +485,9 @@
 
             // Join Activity
             mContactIdForJoin = savedState.getLong(KEY_CONTACT_ID_FOR_JOIN);
+
+            // Full resolution photo URIs
+            mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
         }
 
         // mState can still be null because it may not have have finished loading before
@@ -594,6 +608,9 @@
         // Join Activity
         outState.putLong(KEY_CONTACT_ID_FOR_JOIN, mContactIdForJoin);
 
+        // Full resolution photo URIs
+        outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
+
         super.onSaveInstanceState(outState);
     }
 
@@ -888,7 +905,8 @@
                 mStatus = Status.EDITING;
                 return true;
             }
-            onSaveCompleted(false, saveMode, /* saveSucceeded =*/ mLookupUri != null, mLookupUri);
+            onSaveCompleted(false, saveMode, /* saveSucceeded =*/ mLookupUri != null, mLookupUri,
+                    /* updatedPhotos =*/ null);
             return true;
         }
 
@@ -902,7 +920,7 @@
             // If we're coming back from the fully expanded editor and this is an insert, just
             // pass any values entered by the user back to the compact editor without doing a save
             final Intent resultIntent = EditorIntents.createCompactInsertContactIntent(
-                    mState, getDisplayName());
+                    mState, getDisplayName(), mUpdatedPhotos);
             mListener.onSaveFinished(resultIntent);
             return true;
         }
@@ -1277,8 +1295,10 @@
                     mIntentExtras.getBoolean(INTENT_EXTRA_NEW_LOCAL_PROFILE);
             mDisableDeleteMenuOption =
                     mIntentExtras.getBoolean(INTENT_EXTRA_DISABLE_DELETE_MENU_OPTION);
-            mMaterialPalette =
-                    mIntentExtras.getParcelable(INTENT_EXTRA_MATERIAL_PALETTE);
+            mMaterialPalette = mIntentExtras.getParcelable(INTENT_EXTRA_MATERIAL_PALETTE);
+            if (mIntentExtras.containsKey(INTENT_EXTRA_UPDATED_PHOTOS)) {
+                mUpdatedPhotos = mIntentExtras.getParcelable(INTENT_EXTRA_UPDATED_PHOTOS);
+            }
         }
     }
 
@@ -1301,12 +1321,12 @@
 
     @Override
     public void onJoinCompleted(Uri uri) {
-        onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri);
+        onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri, /* updatedPhotos =*/ null);
     }
 
     @Override
     public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
-            Uri contactLookupUri) {
+            Uri contactLookupUri, Bundle updatedPhotos) {
         if (hadChanges) {
             if (saveSucceeded) {
                 if (saveMode != SaveMode.JOIN && showToastAfterSave()) {
@@ -1329,10 +1349,10 @@
                     } else if (saveMode == SaveMode.COMPACT) {
                         if (isInsert(getActivity().getIntent())) {
                             resultIntent = EditorIntents.createCompactInsertContactIntent(
-                                    mState, getDisplayName());
+                                    mState, getDisplayName(), updatedPhotos);
                         } else {
                             resultIntent = EditorIntents.createCompactEditContactIntent(
-                                    lookupUri, getMaterialPalette());
+                                    lookupUri, getMaterialPalette(), updatedPhotos);
                         }
                     } else {
                         resultIntent = null;
@@ -1564,6 +1584,25 @@
     abstract protected void joinAggregate(long contactId);
 
     //
+    // Photos
+    //
+
+    /**
+     * Removes the full resolution photo URIs for new raw contacts (identified by negative raw
+     * contact IDs) from the member Bundle of updated photos.
+     */
+    protected void removeNewRawContactPhotos() {
+        for (String key : mUpdatedPhotos.keySet()) {
+            try {
+                if (Integer.parseInt(key) < 0) {
+                    mUpdatedPhotos.remove(key);
+                }
+            } catch (NumberFormatException ignored) {
+            }
+        }
+    }
+
+    //
     // Utility methods
     //
 
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 791e20d..133d9eb 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -88,7 +88,6 @@
      */
     private PhotoHandler mCurrentPhotoHandler;
     private Uri mCurrentPhotoUri;
-    private Bundle mUpdatedPhotos = new Bundle();
 
     public ContactEditorFragment() {
     }
@@ -114,7 +113,6 @@
             mRawContactIdRequestingPhoto = savedState.getLong(
                     KEY_RAW_CONTACT_ID_REQUESTING_PHOTO);
             mCurrentPhotoUri = savedState.getParcelable(KEY_CURRENT_PHOTO_URI);
-            mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
         }
     }
 
@@ -532,6 +530,10 @@
     @Override
     protected boolean doSaveAction(int saveMode) {
         // Save contact and reload the compact editor after saving.
+        // Note, the full resolution photos Bundle must be passed to the ContactSaveService
+        // and then passed along in the result Intent in order for the compact editor to
+        // receive it, instead of mUpdatedPhotos being accessed directly in onSaveCompleted,
+        // because we clear mUpdatedPhotos after starting the save service below.
         Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
                 SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
                 ((Activity) mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED,
@@ -549,7 +551,6 @@
         outState.putSerializable(KEY_EXPANDED_EDITORS, mExpandedEditors);
         outState.putLong(KEY_RAW_CONTACT_ID_REQUESTING_PHOTO, mRawContactIdRequestingPhoto);
         outState.putParcelable(KEY_CURRENT_PHOTO_URI, mCurrentPhotoUri);
-        outState.putParcelable(KEY_UPDATED_PHOTOS, mUpdatedPhotos);
         super.onSaveInstanceState(outState);
     }
 
@@ -604,6 +605,12 @@
             Log.w(TAG, "The contact that requested the photo is no longer present.");
         }
 
+        // For inserts where the raw contact ID is a negative number, we must clear any previously
+        // saved full resolution photos under negative raw contact IDs so that the compact editor
+        // will use the newly selected photo, instead of an old one.
+        if (isInsert(getActivity().getIntent()) && rawContact < 0) {
+            removeNewRawContactPhotos();
+        }
         mUpdatedPhotos.putParcelable(String.valueOf(rawContact), photoUri);
     }
 
diff --git a/src/com/android/contacts/editor/EditorIntents.java b/src/com/android/contacts/editor/EditorIntents.java
index 39c14e5..3fb2145 100644
--- a/src/com/android/contacts/editor/EditorIntents.java
+++ b/src/com/android/contacts/editor/EditorIntents.java
@@ -24,6 +24,7 @@
 import android.content.ContentValues;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Bundle;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.text.TextUtils;
@@ -43,9 +44,10 @@
      * existing contact.
      */
     public static Intent createCompactEditContactIntent(Uri contactLookupUri,
-            MaterialPalette materialPalette) {
+            MaterialPalette materialPalette, Bundle updatedPhotos) {
         final Intent intent = new Intent(Intent.ACTION_EDIT, contactLookupUri);
         putMaterialPalette(intent, materialPalette);
+        putUpdatedPhotos(intent, updatedPhotos);
         return intent;
     }
 
@@ -54,7 +56,7 @@
      */
     public static Intent createCompactInsertContactIntent() {
         return createCompactInsertContactIntent(/* rawContactDeltaList =*/ null,
-                /* displayName =*/ null);
+                /* displayName =*/ null, /* updatedPhotos =*/ null);
     }
 
     /**
@@ -62,11 +64,12 @@
      * the field values specified by rawContactDeltaList pre-populate in the form.
      */
     public static Intent createCompactInsertContactIntent(RawContactDeltaList rawContactDeltaList,
-            String displayName) {
+            String displayName, Bundle updatedPhotos) {
         final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
         if (rawContactDeltaList != null || displayName != null) {
             putRawContactDeltaValues(intent, rawContactDeltaList, displayName);
         }
+        putUpdatedPhotos(intent, updatedPhotos);
         return intent;
     }
 
@@ -105,11 +108,12 @@
      * existing contact.
      */
     public static Intent createInsertContactIntent(RawContactDeltaList rawContactDeltaList,
-            String displayName) {
+            String displayName, Bundle updatedPhotos) {
         final Intent intent = new Intent(ContactEditorBaseActivity.ACTION_INSERT,
                 Contacts.CONTENT_URI);
         addContactIntentFlags(intent);
         putRawContactDeltaValues(intent, rawContactDeltaList, displayName);
+        putUpdatedPhotos(intent, updatedPhotos);
         return intent;
     }
 
@@ -126,6 +130,12 @@
         }
     }
 
+    private static void putUpdatedPhotos(Intent intent, Bundle updatedPhotos) {
+        if (updatedPhotos != null && !updatedPhotos.isEmpty()) {
+            intent.putExtra(ContactEditorBaseFragment.INTENT_EXTRA_UPDATED_PHOTOS, updatedPhotos);
+        }
+    }
+
     private static void putRawContactDeltaValues(Intent intent,
             RawContactDeltaList rawContactDeltaList, String displayName) {
         // Pass on all the data that has been entered so far
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 3584fa8..2c2d36f 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -2177,8 +2177,10 @@
 
     private Intent getEditContactIntent() {
         return EditorIntents.createCompactEditContactIntent(
-                mContactData.getLookupUri(), mHasComputedThemeColor
-                        ? new MaterialPalette(mColorFilterColor, mStatusBarColor) : null);
+                mContactData.getLookupUri(),
+                mHasComputedThemeColor
+                        ? new MaterialPalette(mColorFilterColor, mStatusBarColor) : null,
+                /* updatedPhotos =*/ null);
     }
 
     private void editContact() {