Merge "Attach aggregation listener to super primary name field" into mnc-dev
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/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index bab6e88..17e52a7 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -173,7 +173,7 @@
         final int defaultYear = calendar.get(Calendar.YEAR);
 
         // Check whether the year is optional
-        final boolean isYearOptional = getType().isYearOptional();
+        final boolean isYearOptional = getType() != null && getType().isYearOptional();
 
         if (!isYearOptional && !TextUtils.isEmpty(oldValue)) {
             final ParsePosition position = new ParsePosition(0);
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);
     }