Merge "Put back setting photo" into ub-contactsdialer-a-dev
diff --git a/res/layout/quickcontact_suggestion_card.xml b/res/layout/quickcontact_suggestion_card.xml
index 45e316b..1419bc8 100644
--- a/res/layout/quickcontact_suggestion_card.xml
+++ b/res/layout/quickcontact_suggestion_card.xml
@@ -126,11 +126,11 @@
             android:visibility="gone"/>
 
         <Button
-            android:id="@+id/merge_button"
+            android:id="@+id/link_button"
             style="?android:attr/buttonBarButtonStyle"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:text="@string/quickcontact_suggestion_merge_button"
+            android:text="@string/quickcontact_suggestion_link_button"
             android:textColor="@color/quickcontact_entry_sub_header_text_color"
             android:paddingStart="@dimen/quickcontact_suggestion_card_image_spacing"/>
     </LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 680a984..ed9d468 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -127,7 +127,7 @@
     <string name="menu_sendSMS">Text contact</string>
 
     <!-- Menu item that splits an item from the contact detail into a separate aggregate -->
-    <string name="menu_splitAggregate">Separate</string>
+    <string name="menu_splitAggregate">Unlink</string>
 
     <!-- Menu item that edits the currently selected group [CHAR LIMIT=30] -->
     <string name="menu_editGroup">Edit</string>
@@ -142,13 +142,13 @@
     <string name="menu_new_group_action_bar">Add Group</string>
 
     <!-- Title of the confirmation dialog for separating contacts into multiple instances [CHAR LIMIT=26] -->
-    <string name="splitConfirmation_title">Separate contact?</string>
+    <string name="splitConfirmation_title">Unlink contact?</string>
 
-    <!-- Confirmation dialog for separating contacts into multiple instances [CHAR LIMIT=NONE] -->
-    <string name="splitConfirmation">This contact will be separated into multiple contacts.</string>
+    <!-- Confirmation dialog for unlinking contacts into multiple instances [CHAR LIMIT=NONE] -->
+    <string name="splitConfirmation">This contact will be unlinked into multiple contacts.</string>
 
     <!-- Menu item that joins an aggregate with another aggregate -->
-    <string name="menu_joinAggregate">Merge</string>
+    <string name="menu_joinAggregate">Link</string>
 
     <!-- Menu item (in the action bar) to indicate that changes should be saved [CHAR LIMIT=20] -->
     <string name="menu_save">Save</string>
@@ -169,7 +169,7 @@
     <string name="separatorJoinAggregateAll">All contacts</string>
 
     <!-- Toast shown after two contacts have been joined by a user action. [CHAR LIMIT=NONE] -->
-    <string name="contactsJoinedMessage">Contacts merged</string>
+    <string name="contactsJoinedMessage">Contacts linked</string>
 
     <!-- Toast shown after contacts that the user has selected are deleted by a user action. [CHAR LIMIT=NONE] -->
     <string name="contacts_deleted_toast">Contacts deleted</string>
@@ -186,11 +186,11 @@
     <!-- Warning dialog contents after users selects to delete a contact with ReadOnly and Writable sources. -->
     <string name="readOnlyContactDeleteConfirmation">This contact contains information from multiple accounts. Information from read-only accounts will be hidden in your contacts lists, not deleted.</string>
 
-    <!-- Warning dialog. Shown if user selects a single contact to merge. [CHAR LIMIT=NONE]  -->
-    <string name="batch_merge_single_contact_warning">You need at least two contacts selected to perform a merge.</string>
+    <!-- Warning dialog. Shown if user selects a single contact to link. [CHAR LIMIT=NONE]  -->
+    <string name="batch_link_single_contact_warning">You need at least two contacts selected to perform a link.</string>
 
-    <!-- Confirmation dialog. Shown after user selects to merge contacts. [CHAR LIMIT=NONE]  -->
-    <string name="batch_merge_confirmation">The selected contacts will be merged into a single contact.</string>
+    <!-- Confirmation dialog. Shown after user selects to link contacts. [CHAR LIMIT=NONE]  -->
+    <string name="batch_link_confirmation">The selected contacts will be linked into a single contact.</string>
 
     <!-- Confirmation dialog. Shown after user selects to delete writable contacts. [CHAR LIMIT=NONE]  -->
     <string name="batch_delete_confirmation">The selected contacts will be deleted.</string>
@@ -466,11 +466,11 @@
     <!-- The title of the Edit-Contact screen -->
     <string name="edit_contact">Edit contact</string>
 
-    <!-- Shows how many contacts have been merged. The value 1 is not shown but should be translated
+    <!-- Shows how many contacts have been linked. The value 1 is not shown but should be translated
          anyway if we change our mind later -->
-    <plurals name="merge_info">
-        <item quantity="one">not merged</item>
-        <item quantity="other">merged from <xliff:g id="count">%0$d</xliff:g> sources</item>
+    <plurals name="link_info">
+        <item quantity="one">not linked</item>
+        <item quantity="other">linked from <xliff:g id="count">%0$d</xliff:g> sources</item>
     </plurals>
 
     <!-- The message in a confirmation dialog shown when the user selects a
@@ -774,8 +774,8 @@
     <!-- Quick contact display name with phonetic name -->
     <string name="quick_contact_display_name_with_phonetic"><xliff:g id="display_name">%s</xliff:g> (<xliff:g id="phonetic_name">%s</xliff:g>)</string>
 
-    <!-- Button used in quick contact suggestion card to merge selected contacts. [CHAR LIMIT=30]-->
-    <string name="quickcontact_suggestion_merge_button">Merge</string>
+    <!-- Button used in quick contact suggestion card to link selected contacts. [CHAR LIMIT=30]-->
+    <string name="quickcontact_suggestion_link_button">Link</string>
 
     <!-- Suggestions number in quick contact suggestion card [CHAR LIMIT=60] -->
     <plurals name="quickcontact_suggestions_number">
@@ -792,6 +792,6 @@
     <!-- Account type with number in quick contact suggestion card [CHAR LIMIT=30]-->
     <string name="quickcontact_suggestion_account_type"><xliff:g id="account_type">%s</xliff:g><xliff:g id="account_type_number">%s</xliff:g></string>
 
-    <!-- Merged contacts title showing in contact editor UI. [CHAR LIMIT=30]-->
-    <string name="compact_editor_linked_contacts_title">Merged contacts</string>
+    <!-- Linked contacts title showing in contact editor UI. [CHAR LIMIT=30]-->
+    <string name="compact_editor_linked_contacts_title">Linked contacts</string>
 </resources>
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index 058a66c..6c0ff85 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -19,8 +19,6 @@
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.R;
 import com.android.contacts.activities.CompactContactEditorActivity;
-import com.android.contacts.activities.ContactEditorActivity;
-import com.android.contacts.activities.ContactEditorBaseActivity;
 import com.android.contacts.common.model.RawContactDelta;
 import com.android.contacts.common.model.ValuesDelta;
 import com.android.contacts.common.model.account.AccountWithDataSet;
@@ -82,16 +80,6 @@
     }
 
     @Override
-    public void onStop() {
-        super.onStop();
-
-        // If anything was left unsaved, save it now
-        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
-            save(SaveMode.RELOAD);
-        }
-    }
-
-    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (item.getItemId() == android.R.id.home) {
             return revert();
@@ -212,9 +200,7 @@
         if (activity == null || activity.isFinishing()) {
             return;
         }
-        if (!mIsUserProfile) {
-            acquireAggregationSuggestions(activity, rawContactId, valuesDelta);
-        }
+        acquireAggregationSuggestions(activity, rawContactId, valuesDelta);
     }
 
     @Override
diff --git a/src/com/android/contacts/editor/CompactKindSectionView.java b/src/com/android/contacts/editor/CompactKindSectionView.java
index 3ebe27b..fffe464 100644
--- a/src/com/android/contacts/editor/CompactKindSectionView.java
+++ b/src/com/android/contacts/editor/CompactKindSectionView.java
@@ -16,6 +16,13 @@
 
 package com.android.contacts.editor;
 
+import com.android.contacts.R;
+import com.android.contacts.common.model.RawContactDelta;
+import com.android.contacts.common.model.RawContactModifier;
+import com.android.contacts.common.model.ValuesDelta;
+import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.dataitem.DataKind;
+
 import android.content.Context;
 import android.database.Cursor;
 import android.provider.ContactsContract.CommonDataKinds.Event;
@@ -30,14 +37,6 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import com.android.contacts.R;
-import com.android.contacts.common.model.RawContactDelta;
-import com.android.contacts.common.model.RawContactDeltaList;
-import com.android.contacts.common.model.RawContactModifier;
-import com.android.contacts.common.model.ValuesDelta;
-import com.android.contacts.common.model.account.AccountType;
-import com.android.contacts.common.model.dataitem.DataKind;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -152,6 +151,7 @@
     private ViewIdGenerator mViewIdGenerator;
     private CompactRawContactsEditorView.Listener mListener;
 
+    private boolean mIsUserProfile;
     private boolean mShowOneEmptyEditor = false;
     private boolean mHideIfEmpty = true;
 
@@ -190,6 +190,10 @@
         mIcon = (ImageView) findViewById(R.id.kind_icon);
     }
 
+    public void setIsUserProfile(boolean isUserProfile) {
+        mIsUserProfile = isUserProfile;
+    }
+
     /**
      * @param showOneEmptyEditor If true, we will always show one empty editor, otherwise an empty
      *         editor will not be shown until the user enters a value.  Note, this does not apply
@@ -364,8 +368,11 @@
         // Structured name
         final StructuredNameEditorView nameView = (StructuredNameEditorView) mLayoutInflater
                 .inflate(R.layout.structured_name_editor_view, mEditors, /* attachToRoot =*/ false);
-        nameView.setEditorListener(new StructuredNameEditorListener(valuesDelta,
-                rawContactDelta.getRawContactId(), mListener));
+        if (!mIsUserProfile) {
+            // Don't set super primary for the me contact
+            nameView.setEditorListener(new StructuredNameEditorListener(
+                    valuesDelta, rawContactDelta.getRawContactId(), mListener));
+        }
         nameView.setDeletable(false);
         nameView.setValues(
                 accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 88894ec..9d5ff55 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -30,9 +30,7 @@
 import com.android.contacts.util.UiClosables;
 
 import android.content.ContentUris;
-import android.content.ContentValues;
 import android.content.Context;
-import android.content.Intent;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -68,16 +66,15 @@
 import android.widget.ListPopupWindow;
 import android.widget.TextView;
 
-import java.io.FileNotFoundException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 import java.util.TreeSet;
 
 /**
@@ -124,7 +121,7 @@
         public void onEditorsBound();
 
         /**
-         * Invoked when a rawcontact from merged contacts is selected in editor.
+         * Invoked when a rawcontact from linked contacts is selected in editor.
          */
         public void onRawContactSelected(Uri uri, long rawContactId, boolean isReadOnly);
 
@@ -169,8 +166,12 @@
             // For email addresses, we don't want to truncate at end, which might cut off the domain
             // name.
             final TextView text2 = (TextView) resultView.findViewById(android.R.id.text2);
-            text2.setText(accountName);
-            text2.setEllipsize(TextUtils.TruncateAt.MIDDLE);
+            if (TextUtils.isEmpty(accountName)) {
+                text2.setVisibility(View.GONE);
+            } else {
+                text2.setText(accountName);
+                text2.setEllipsize(TextUtils.TruncateAt.MIDDLE);
+            }
 
             final ImageView icon = (ImageView) resultView.findViewById(android.R.id.icon);
             icon.setImageDrawable(accountType.getDisplayIcon(mContext));
@@ -502,7 +503,7 @@
     }
 
     public void removePhoto() {
-        mPhotoValuesDelta.setFromTemplate(false);
+        mPhotoValuesDelta.setFromTemplate(true);
         mPhotoValuesDelta.put(Photo.PHOTO, (byte[]) null);
 
         mPhotoView.removePhoto();
@@ -516,11 +517,15 @@
     }
 
     public void updatePhoto(Uri photoUri) {
-        // Unset primary for all photos
-        unsetSuperPrimary();
+        mPhotoValuesDelta.setFromTemplate(false);
 
-        // Mark the currently displayed photo as primary
-        mPhotoValuesDelta.setSuperPrimary(true);
+        if (!mIsUserProfile) {
+            // Unset primary for all photos
+            unsetSuperPrimary();
+
+            // Mark the currently displayed photo as primary
+            mPhotoValuesDelta.setSuperPrimary(true);
+        }
 
         // Even though high-res photos cannot be saved by passing them via
         // an EntityDeltaList (since they cause the Bundle size limit to be
@@ -618,9 +623,6 @@
      * UI.
      */
     public void setPrimaryPhoto(CompactPhotoSelectionFragment.Photo photo) {
-        // Unset primary for all photos
-        unsetSuperPrimary();
-
         // Find the values delta to mark as primary
         final KindSectionDataList kindSectionDataList =
                 mKindSectionDataMap.get(Photo.CONTENT_ITEM_TYPE);
@@ -638,7 +640,13 @@
         }
         final ValuesDelta valuesDelta = valuesDeltaList.get(photo.valuesDeltaListIndex);
         valuesDelta.setFromTemplate(false);
-        valuesDelta.setSuperPrimary(true);
+
+        if (!mIsUserProfile) {
+            // Unset primary for all other photos
+            unsetSuperPrimary();
+
+            valuesDelta.setSuperPrimary(true);
+        }
 
         // Update the UI
         mPhotoView.setPhoto(valuesDelta, mMaterialPalette);
@@ -880,6 +888,8 @@
     private void addRawContactAccountSelector(final RawContactDeltaList rawContactDeltas) {
         mRawContactContainer.setVisibility(View.VISIBLE);
 
+        Collections.sort(rawContactDeltas, new RawContactDeltaComparator(getContext()));
+
         final String accountsSummary = getRawContactsAccountsSummary(
                 getContext(), rawContactDeltas);
         mRawContactSummary.setText(accountsSummary);
@@ -929,7 +939,7 @@
 
     private static String getRawContactsAccountsSummary(
             Context context, RawContactDeltaList rawContactDeltas) {
-        final Map<String, Integer> accountTypeNumber = new HashMap<>();
+        final LinkedHashMap<String, Integer> accountTypeNumber = new LinkedHashMap<>();
         for (RawContactDelta rawContactDelta : rawContactDeltas) {
             if (rawContactDelta.isVisible()) {
                 final AccountType accountType = rawContactDelta.getRawContactAccountType(context);
@@ -944,7 +954,7 @@
             }
         }
 
-        final Set<String> linkedAccounts = new HashSet<>();
+        final LinkedHashSet<String> linkedAccounts = new LinkedHashSet<>();
         for (String accountTypeLabel : accountTypeNumber.keySet()) {
             final String number = context.getResources().getQuantityString(
                     R.plurals.quickcontact_suggestion_account_type_number,
@@ -1006,6 +1016,14 @@
                 continue;
             }
 
+            // Don't show more than one group editor on the compact editor.
+            // Groups will still be editable for each raw contact individually on the full editor.
+            if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)
+                    && kindSectionDataList.size() > 1) {
+                vlog("kind: " + i + " " + mimeType + " dropped");
+                continue;
+            }
+
             if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
                 vlog("kind: " + i + " " + mimeType + ": " + kindSectionDataList.size() +
                         " kindSectionData(s)");
@@ -1034,6 +1052,7 @@
         final CompactKindSectionView kindSectionView = (CompactKindSectionView)
                 mLayoutInflater.inflate(R.layout.compact_item_kind_section, viewGroup,
                         /* attachToRoot =*/ false);
+        kindSectionView.setIsUserProfile(mIsUserProfile);
 
         if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
                 || Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index 1e18e2c..718128b 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -643,13 +643,7 @@
     @Override
     public void onStop() {
         super.onStop();
-
         UiClosables.closeQuietly(mAggregationSuggestionPopup);
-
-        // If anything was left unsaved, save it now but keep the editor open.
-        if (!getActivity().isChangingConfigurations() && mStatus == Status.EDITING) {
-            save(SaveMode.RELOAD);
-        }
     }
 
     @Override
@@ -1368,7 +1362,7 @@
             }
             mPhotoId = mIntentExtras.getLong(INTENT_EXTRA_PHOTO_ID);
             mRawContactIdToDisplayAlone = mIntentExtras.getLong(
-                    INTENT_EXTRA_RAW_CONTACT_ID_TO_DISPLAY_ALONE);
+                    INTENT_EXTRA_RAW_CONTACT_ID_TO_DISPLAY_ALONE, -1);
             mRawContactDisplayAloneIsReadOnly = mIntentExtras.getBoolean(
                     INTENT_EXTRA_RAW_CONTACT_DISPLAY_ALONE_IS_READ_ONLY);
         }
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index c602a1d..a3830ef 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -114,7 +114,7 @@
             mCurrentPhotoUri = savedState.getParcelable(KEY_CURRENT_PHOTO_URI);
             mUpdatedPhotos = savedState.getParcelable(KEY_UPDATED_PHOTOS);
             mRawContactIdToDisplayAlone = savedState.getLong(
-                    ContactEditorBaseFragment.INTENT_EXTRA_RAW_CONTACT_ID_TO_DISPLAY_ALONE);
+                    ContactEditorBaseFragment.INTENT_EXTRA_RAW_CONTACT_ID_TO_DISPLAY_ALONE, -1);
         }
     }
 
@@ -123,7 +123,7 @@
         super.load(action, lookupUri, intentExtras);
         if (intentExtras != null) {
             mRawContactIdToDisplayAlone = intentExtras.getLong(
-                    ContactEditorBaseFragment.INTENT_EXTRA_RAW_CONTACT_ID_TO_DISPLAY_ALONE);
+                    ContactEditorBaseFragment.INTENT_EXTRA_RAW_CONTACT_ID_TO_DISPLAY_ALONE, -1);
         }
     }
 
diff --git a/src/com/android/contacts/interactions/JoinContactsDialogFragment.java b/src/com/android/contacts/interactions/JoinContactsDialogFragment.java
index a9a1aa9..e5fd890 100644
--- a/src/com/android/contacts/interactions/JoinContactsDialogFragment.java
+++ b/src/com/android/contacts/interactions/JoinContactsDialogFragment.java
@@ -65,13 +65,13 @@
         if (contactIds.size() <= 1) {
             return new AlertDialog.Builder(getActivity())
                     .setIconAttribute(android.R.attr.alertDialogIcon)
-                    .setMessage(R.string.batch_merge_single_contact_warning)
+                    .setMessage(R.string.batch_link_single_contact_warning)
                     .setPositiveButton(android.R.string.ok, null)
                     .create();
         }
         return new AlertDialog.Builder(getActivity())
                 .setIconAttribute(android.R.attr.alertDialogIcon)
-                .setMessage(R.string.batch_merge_confirmation)
+                .setMessage(R.string.batch_link_confirmation)
                 .setNegativeButton(android.R.string.cancel, null)
                 .setPositiveButton(android.R.string.ok,
                         new DialogInterface.OnClickListener() {
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 39cf0ec..2f37387 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -253,7 +253,7 @@
     private ImageView mSuggestionExpansionButton;
     private LinearLayout mSuggestionList;
     private View mSuggestionSeparator;
-    private Button mSuggestionsMergeButton;
+    private Button mSuggestionsLinkButton;
     private boolean mIsSuggestionListCollapsed;
     private long mPreviousSuggestionForContactId = 0;
 
@@ -916,7 +916,7 @@
         mSuggestionExpansionButton = (ImageView) findViewById(R.id.expand_suggestion_button);
         mSuggestionSeparator = findViewById(R.id.title_separator2);
         mSuggestionList = (LinearLayout) findViewById(R.id.suggestion_list);
-        mSuggestionsMergeButton = (Button) findViewById(R.id.merge_button);
+        mSuggestionsLinkButton = (Button) findViewById(R.id.link_button);
         if (savedInstanceState != null) {
             mIsSuggestionListCollapsed = savedInstanceState.getBoolean(
                     KEY_IS_SUGGESTION_LIST_COLLAPSED, true);
@@ -928,7 +928,7 @@
         }
 
         mSuggestionExpansionButton.setClickable(true);
-        mSuggestionsMergeButton.setOnClickListener(new OnClickListener() {
+        mSuggestionsLinkButton.setOnClickListener(new OnClickListener() {
             @Override
             public void onClick(View view) {
                 // Join selected contacts.
@@ -1321,8 +1321,10 @@
         } else {
             expandSuggestionList();
         }
-        mSuggestionCardView.setVisibility(View.GONE);
-        mSuggestionList.removeAllViews();
+        if (mPreviousSuggestionForContactId != mContactData.getId()) {
+            mSuggestionCardView.setVisibility(View.GONE);
+            mSuggestionList.removeAllViews();
+        }
 
         if (mAggregationSuggestionEngine == null) {
             mAggregationSuggestionEngine = new AggregationSuggestionEngine(this);