Distinguish between editor back button presses and framework stopage

We carry whether the editor fragment is being stopped
because of a back button press or because the framework
stopped the hosting Activity all the way through the various
editor fragment callbacks and the ContactSaveService because
it is not until ContactEditorBaseActivity.onSaveFinished
where we start the next Intent -- starting it causes a
"flash" if recents is clicked and follwed by an immediate
starting of the next editor Activity, which is the bug
that was filed.

With this change, we only use the ContactSaveService
resultIntent to go back to the compact editor on back
presses.  The expected behavior/tested scenarios are
described at go/b21198041

Bug 21198041
Bug 19624360

Change-Id: Ic350e12aa447cff81747e003f504f25100bd5c60
diff --git a/src/com/android/contacts/ContactSaveService.java b/src/com/android/contacts/ContactSaveService.java
index 29a4a7b..9944c77 100644
--- a/src/com/android/contacts/ContactSaveService.java
+++ b/src/com/android/contacts/ContactSaveService.java
@@ -54,6 +54,7 @@
 import com.android.contacts.common.model.RawContactDeltaList;
 import com.android.contacts.common.model.RawContactModifier;
 import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.editor.ContactEditorFragment;
 import com.android.contacts.util.ContactPhotoUtils;
 
 import com.google.common.collect.Lists;
@@ -300,7 +301,7 @@
         Bundle bundle = new Bundle();
         bundle.putParcelable(String.valueOf(rawContactId), updatedPhotoPath);
         return createSaveContactIntent(context, state, saveModeExtraKey, saveMode, isProfile,
-                callbackActivity, callbackAction, bundle);
+                callbackActivity, callbackAction, bundle, /* backPressed =*/ false);
     }
 
     /**
@@ -309,11 +310,13 @@
      * This variant is used when multiple contacts' photos may be updated, as in the
      * Contact Editor.
      * @param updatedPhotos maps each raw-contact's ID to the file-path of the new photo.
+     * @param backPressed whether the save was initiated as a result of a back button press
+     *         or because the framework stopped the editor Activity
      */
     public static Intent createSaveContactIntent(Context context, RawContactDeltaList state,
             String saveModeExtraKey, int saveMode, boolean isProfile,
             Class<? extends Activity> callbackActivity, String callbackAction,
-            Bundle updatedPhotos) {
+            Bundle updatedPhotos, boolean backPressed) {
         Intent serviceIntent = new Intent(
                 context, ContactSaveService.class);
         serviceIntent.setAction(ContactSaveService.ACTION_SAVE_CONTACT);
@@ -333,6 +336,8 @@
             if (updatedPhotos != null) {
                 callbackIntent.putExtra(EXTRA_UPDATED_PHOTOS, (Parcelable) updatedPhotos);
             }
+            callbackIntent.putExtra(ContactEditorFragment.INTENT_EXTRA_SAVE_BACK_PRESSED,
+                    backPressed);
             serviceIntent.putExtra(ContactSaveService.EXTRA_CALLBACK_INTENT, callbackIntent);
         }
         return serviceIntent;
diff --git a/src/com/android/contacts/activities/CompactContactEditorActivity.java b/src/com/android/contacts/activities/CompactContactEditorActivity.java
index fcbb70e..c45c261 100644
--- a/src/com/android/contacts/activities/CompactContactEditorActivity.java
+++ b/src/com/android/contacts/activities/CompactContactEditorActivity.java
@@ -60,7 +60,7 @@
     @Override
     public void onBackPressed() {
         if (mFragment != null) {
-            mFragment.save(ContactEditor.SaveMode.CLOSE);
+            mFragment.save(ContactEditor.SaveMode.CLOSE, /* backPressed =*/ true);
         }
     }
 }
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index a9b75d9..800a267 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -54,7 +54,7 @@
     @Override
     public void onBackPressed() {
         if (mFragment != null) {
-            mFragment.save(ContactEditor.SaveMode.COMPACT);
+            mFragment.save(ContactEditor.SaveMode.COMPACT, /* backPressed =*/ true);
         }
     }
 }
diff --git a/src/com/android/contacts/activities/ContactEditorBaseActivity.java b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
index ec2f9b6..41b0c6b 100644
--- a/src/com/android/contacts/activities/ContactEditorBaseActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
@@ -153,14 +153,17 @@
         /**
          * Saves or creates the contact based on the mode, and if successful
          * finishes the activity.
+         *
+         * @param backPressed whether the save was initiated as a result of a back button press
+         *         or because the framework stopped the editor Activity
          */
-        boolean save(int saveMode);
+        boolean save(int saveMode, boolean backPressed);
 
         /**
          * Invoked after the contact is saved.
          */
         void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
-                Uri contactLookupUri, Bundle updatedPhotos);
+                Uri contactLookupUri, Bundle updatedPhotos, boolean backPressed);
 
         /**
          * Invoked after the contact is joined.
@@ -238,7 +241,9 @@
                             ContactEditor.SaveMode.CLOSE),
                     intent.getBooleanExtra(ContactSaveService.EXTRA_SAVE_SUCCEEDED, false),
                     intent.getData(),
-                    (Bundle) intent.getParcelableExtra(ContactSaveService.EXTRA_UPDATED_PHOTOS));
+                    (Bundle) intent.getParcelableExtra(ContactSaveService.EXTRA_UPDATED_PHOTOS),
+                    intent.getBooleanExtra(ContactEditorFragment.INTENT_EXTRA_SAVE_BACK_PRESSED,
+                            false));
         } else if (ACTION_JOIN_COMPLETED.equals(action)) {
             mFragment.onJoinCompleted(intent.getData());
         }
@@ -268,11 +273,15 @@
 
         @Override
         public void onSaveFinished(Intent resultIntent) {
+            final boolean backPressed = resultIntent == null ? false : resultIntent.getBooleanExtra(
+                    ContactEditorBaseFragment.INTENT_EXTRA_SAVE_BACK_PRESSED, false);
             if (mFinishActivityOnSaveCompleted) {
                 setResult(resultIntent == null ? RESULT_CANCELED : RESULT_OK, resultIntent);
             } else if (resultIntent != null) {
-                ImplicitIntentsUtil.startActivityInApp(ContactEditorBaseActivity.this,
-                        resultIntent);
+                if (backPressed) {
+                    ImplicitIntentsUtil.startActivityInApp(ContactEditorBaseActivity.this,
+                            resultIntent);
+                }
             }
             finish();
         }
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index c7d7cac..10efe10 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -188,7 +188,7 @@
 
         // If anything was left unsaved, save it now
         if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
-            save(SaveMode.RELOAD);
+            save(SaveMode.RELOAD, /* backPressed =*/ false);
         }
     }
 
@@ -297,12 +297,12 @@
     }
 
     @Override
-    protected boolean doSaveAction(int saveMode) {
+    protected boolean doSaveAction(int saveMode, boolean backPressed) {
         // Save contact. No need to pass the palette since we are finished editing after the save.
         final Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
                 SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
                 ((Activity) mContext).getClass(),
-                CompactContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos);
+                CompactContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos, backPressed);
         mContext.startService(intent);
 
         return true;
@@ -350,7 +350,7 @@
             mShowToastAfterSave = false;
 
             // Save whatever is in the form
-            save(SaveMode.RELOAD);
+            save(SaveMode.RELOAD, /* backPressed =*/ false);
         }
 
         // Prepare an Intent to start the expanded editor
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index 529bc4e..52076f7 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -178,6 +178,12 @@
     public static final String SAVE_MODE_EXTRA_KEY = "saveMode";
 
     /**
+     * Intent extra to specify whether the save was initiated as a result of a back button press
+     * or because the framework stopped the editor Activity.
+     */
+    public static final String INTENT_EXTRA_SAVE_BACK_PRESSED = "saveBackPressed";
+
+    /**
      * Callbacks for Activities that host contact editors Fragments.
      */
     public interface Listener {
@@ -775,7 +781,7 @@
         switch (item.getItemId()) {
             case android.R.id.home:
             case R.id.menu_done:
-                return save(SaveMode.CLOSE);
+                return save(SaveMode.CLOSE, /* backPressed =*/ true);
             case R.id.menu_discard:
                 return revert();
             case R.id.menu_delete:
@@ -831,7 +837,7 @@
         }
 
         mState.markRawContactsForSplitting();
-        save(SaveMode.SPLIT);;
+        save(SaveMode.SPLIT, /* backPressed =*/ false);
     }
 
     private boolean doSplitContactAction() {
@@ -854,7 +860,7 @@
             return true;
         }
 
-        return save(SaveMode.JOIN);
+        return save(SaveMode.JOIN, /* backPressed =*/ false);
     }
 
     private void doPickRingtone() {
@@ -886,7 +892,7 @@
     }
 
     @Override
-    public boolean save(int saveMode) {
+    public boolean save(int saveMode, boolean backPressed) {
         if (!hasValidState() || mStatus != Status.EDITING) {
             return false;
         }
@@ -908,7 +914,7 @@
             }
             onSaveCompleted(/* hadChanges =*/ false, saveMode,
                     /* saveSucceeded =*/ mLookupUri != null, mLookupUri,
-                    /* updatedPhotos =*/ null);
+                    /* updatedPhotos =*/ null, backPressed);
             return true;
         }
 
@@ -917,23 +923,24 @@
         // Store account as default account, only if this is a new contact
         saveDefaultAccountIfNecessary();
 
-        if (isInsert(getActivity().getIntent())
-                && saveMode == SaveMode.COMPACT && mListener != null) {
+        if (isInsert(getActivity().getIntent()) && saveMode == SaveMode.COMPACT
+                && mListener != null && backPressed) {
             // 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(), getPhoneticName(), mUpdatedPhotos);
+            resultIntent.putExtra(INTENT_EXTRA_SAVE_BACK_PRESSED, backPressed);
             mListener.onSaveFinished(resultIntent);
             return true;
         }
         // Otherwise this is an edit or a back press so do an actual save
-        return doSaveAction(saveMode);
+        return doSaveAction(saveMode, backPressed);
     }
 
     /**
      * Persist the accumulated editor deltas.
      */
-    abstract protected boolean doSaveAction(int saveMode);
+    abstract protected boolean doSaveAction(int saveMode, boolean backPressed);
 
     //
     // State accessor methods
@@ -1326,12 +1333,13 @@
 
     @Override
     public void onJoinCompleted(Uri uri) {
-        onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri, /* updatedPhotos =*/ null);
+        onSaveCompleted(false, SaveMode.RELOAD, uri != null, uri, /* updatedPhotos =*/ null,
+                /* backPressed =*/ false);
     }
 
     @Override
     public void onSaveCompleted(boolean hadChanges, int saveMode, boolean saveSucceeded,
-            Uri contactLookupUri, Bundle updatedPhotos) {
+            Uri contactLookupUri, Bundle updatedPhotos, boolean backPressed) {
         if (hadChanges) {
             if (saveSucceeded) {
                 if (saveMode != SaveMode.JOIN && mShowToastAfterSave) {
@@ -1342,36 +1350,41 @@
             }
         }
         switch (saveMode) {
-            case SaveMode.CLOSE:
-            case SaveMode.COMPACT:
+            case SaveMode.CLOSE: {
                 final Intent resultIntent;
-                if (!saveSucceeded || contactLookupUri == null) {
-                    resultIntent = saveMode == SaveMode.COMPACT
-                            ? EditorIntents.createCompactInsertContactIntent(
-                                    mState, getDisplayName(), getPhoneticName(), updatedPhotos)
-                            : null;
-                } else {
+                if (saveSucceeded && contactLookupUri != null) {
                     final Uri lookupUri = maybeConvertToLegacyLookupUri(
                             mContext, contactLookupUri, mLookupUri);
-                    if (saveMode == SaveMode.CLOSE) {
-                        resultIntent = ImplicitIntentsUtil.composeQuickContactIntent(lookupUri,
-                                QuickContactActivity.MODE_FULLY_EXPANDED);
-                    } else if (saveMode == SaveMode.COMPACT) {
-                        resultIntent = isInsert(getActivity().getIntent())
-                                ? EditorIntents.createCompactInsertContactIntent(
-                                        mState, getDisplayName(), getPhoneticName(), updatedPhotos)
-                                : EditorIntents.createCompactEditContactIntent(
-                                        lookupUri, getMaterialPalette(), updatedPhotos);
-                    } else {
-                        resultIntent = null;
-                    }
+                    resultIntent = ImplicitIntentsUtil.composeQuickContactIntent(lookupUri,
+                            QuickContactActivity.MODE_FULLY_EXPANDED);
+                    resultIntent.putExtra(INTENT_EXTRA_SAVE_BACK_PRESSED, backPressed);
+                } else {
+                    resultIntent = null;
                 }
-
-                // It is already saved, so prevent that it is saved again
                 mStatus = Status.CLOSING;
                 if (mListener != null) mListener.onSaveFinished(resultIntent);
                 break;
-
+            }
+            case SaveMode.COMPACT: {
+                if (!hadChanges && !backPressed && isInsert(getActivity().getIntent())) {
+                    // Reload the empty editor when the Contacts app is resumed
+                    mStatus = Status.EDITING;
+                } else if (backPressed) {
+                    final Uri lookupUri = maybeConvertToLegacyLookupUri(
+                            mContext, contactLookupUri, mLookupUri);
+                    final Intent resultIntent = isInsert(getActivity().getIntent())
+                            ? EditorIntents.createCompactInsertContactIntent(
+                                    mState, getDisplayName(), getPhoneticName(), updatedPhotos)
+                            : EditorIntents.createCompactEditContactIntent(
+                                    lookupUri, getMaterialPalette(), updatedPhotos);
+                    resultIntent.putExtra(INTENT_EXTRA_SAVE_BACK_PRESSED, true);
+                    mStatus = Status.CLOSING;
+                    if (mListener != null) mListener.onSaveFinished(resultIntent);
+                } else {
+                    reloadFullEditor(contactLookupUri);
+                }
+                break;
+            }
             case SaveMode.RELOAD:
             case SaveMode.JOIN:
                 if (saveSucceeded && contactLookupUri != null) {
@@ -1379,14 +1392,7 @@
                     if (saveMode == SaveMode.JOIN && hasValidState()) {
                         showJoinAggregateActivity(contactLookupUri);
                     }
-
-                    // If this was in INSERT, we are changing into an EDIT now.
-                    // If it already was an EDIT, we are changing to the new Uri now
-                    // Either way, open the editor with all input fields displayed.
-                    mState = new RawContactDeltaList();
-                    load(ContactEditorBaseActivity.ACTION_EDIT, contactLookupUri, null);
-                    mStatus = Status.LOADING;
-                    getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
+                    reloadFullEditor(contactLookupUri);
                 }
                 break;
 
@@ -1401,6 +1407,13 @@
         }
     }
 
+    private void reloadFullEditor(Uri contactLookupUri) {
+        mState = new RawContactDeltaList();
+        load(ContactEditorBaseActivity.ACTION_EDIT, contactLookupUri, null);
+        mStatus = Status.LOADING;
+        getLoaderManager().restartLoader(LOADER_DATA, null, mDataLoaderListener);
+    }
+
     /**
      * Shows a list of aggregates that can be joined into the currently viewed aggregate.
      *
@@ -1536,7 +1549,7 @@
         }
 
         mState.setJoinWithRawContacts(rawContactIds);
-        save(SaveMode.RELOAD);
+        save(SaveMode.RELOAD, /* backPressed =*/ false);
     }
 
     @Override
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 4cda73d..e9b3715 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -118,7 +118,7 @@
 
         // If anything was left unsaved, save it now and return to the compact editor.
         if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
-            save(SaveMode.COMPACT);
+            save(SaveMode.COMPACT, /* backPressed =*/ false);
         }
     }
 
@@ -133,7 +133,7 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         // Override the home/done options to return to the compact editor
         if (item.getItemId() == android.R.id.home || item.getItemId() == R.id.menu_done) {
-            return save(SaveMode.COMPACT);
+            return save(SaveMode.COMPACT, /* backPressed =*/ true);
         }
         return super.onOptionsItemSelected(item);
     }
@@ -539,7 +539,7 @@
     }
 
     @Override
-    protected boolean doSaveAction(int saveMode) {
+    protected boolean doSaveAction(int saveMode, boolean backPressed) {
         // 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
@@ -548,7 +548,7 @@
         Intent intent = ContactSaveService.createSaveContactIntent(mContext, mState,
                 SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
                 ((Activity) mContext).getClass(), ContactEditorActivity.ACTION_SAVE_COMPLETED,
-                mUpdatedPhotos);
+                mUpdatedPhotos, backPressed);
         mContext.startService(intent);
 
         // Don't try to save the same photos twice.
diff --git a/src/com/android/contacts/quickcontact/InvisibleContactUtil.java b/src/com/android/contacts/quickcontact/InvisibleContactUtil.java
index 3609fbc..de70424 100644
--- a/src/com/android/contacts/quickcontact/InvisibleContactUtil.java
+++ b/src/com/android/contacts/quickcontact/InvisibleContactUtil.java
@@ -94,7 +94,7 @@
         final Intent intent = ContactSaveService.createSaveContactIntent(
                 context,
                 contactDeltaList, "", 0, false, QuickContactActivity.class,
-                Intent.ACTION_VIEW, null);
+                Intent.ACTION_VIEW, null, /* backPressed =*/ false);
         context.startService(intent);
     }