Show account info for inserts and read-only contact edits

Bug 21637149

Change-Id: I224ab188230f119f49f4ab7ddef4b51c451aa892
diff --git a/src/com/android/contacts/editor/BaseRawContactEditorView.java b/src/com/android/contacts/editor/BaseRawContactEditorView.java
index 01742bb..e99af61 100644
--- a/src/com/android/contacts/editor/BaseRawContactEditorView.java
+++ b/src/com/android/contacts/editor/BaseRawContactEditorView.java
@@ -197,12 +197,8 @@
 
     protected void updateAccountHeaderContentDescription() {
         final StringBuilder builder = new StringBuilder();
-        if (!TextUtils.isEmpty(mAccountType.getText())) {
-            builder.append(mAccountType.getText()).append('\n');
-        }
-        if (!TextUtils.isEmpty(mAccountName.getText())) {
-            builder.append(mAccountName.getText()).append('\n');
-        }
+        builder.append(EditorUiUtils.getAccountInfoContentDescription(
+                mAccountName.getText(), mAccountType.getText()));
         if (mExpandAccountButton.getVisibility() == View.VISIBLE) {
             builder.append(getResources().getString(isCollapsed()
                     ? R.string.content_description_expand_editor
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index 12b3b62..656c5ae 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -209,7 +209,7 @@
         final CompactRawContactsEditorView editorView = getContent();
         editorView.setListener(this);
         editorView.setState(mState, getMaterialPalette(), mViewIdGenerator, mPhotoId, mNameId,
-                mReadOnlyDisplayName);
+                mReadOnlyDisplayName, mHasNewContact, mIsUserProfile);
         if (mReadOnlyDisplayName != null) {
             mReadOnlyNameEditorView = editorView.getDefaultNameEditorView();
         }
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index d12ef6d..ca2aa93 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -24,6 +24,7 @@
 import com.android.contacts.common.model.ValuesDelta;
 import com.android.contacts.common.model.account.AccountType;
 import com.android.contacts.common.model.account.AccountType.EditField;
+import com.android.contacts.common.model.account.AccountWithDataSet;
 import com.android.contacts.common.model.dataitem.DataKind;
 import com.android.contacts.common.util.MaterialColorMapUtils;
 import com.android.contacts.editor.CompactContactEditorFragment.PhotoHandler;
@@ -40,10 +41,12 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
+import android.widget.TextView;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -123,6 +126,9 @@
     private ViewIdGenerator mViewIdGenerator;
     private MaterialColorMapUtils.MaterialPalette mMaterialPalette;
 
+    private View mAccountContainer;
+    private TextView mAccountTypeView;
+    private TextView mAccountNameView;
     private CompactPhotoEditorView mPhoto;
     private ViewGroup mNames;
     private ViewGroup mPhoneticNames;
@@ -162,6 +168,9 @@
         mLayoutInflater = (LayoutInflater)
                 getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
+        mAccountContainer = findViewById(R.id.account_container);
+        mAccountTypeView = (TextView) findViewById(R.id.account_type);
+        mAccountNameView = (TextView) findViewById(R.id.account_name);
         mPhoto = (CompactPhotoEditorView) findViewById(R.id.photo_editor);
         mNames = (LinearLayout) findViewById(R.id.names);
         mPhoneticNames = (LinearLayout) findViewById(R.id.phonetic_names);
@@ -266,7 +275,8 @@
      */
     public void setState(RawContactDeltaList rawContactDeltas,
             MaterialColorMapUtils.MaterialPalette materialPalette, ViewIdGenerator viewIdGenerator,
-            long photoId, long nameId, String readOnlyDisplayName) {
+            long photoId, long nameId, String readOnlyDisplayName, boolean hasNewContact,
+            boolean isUserProfile) {
         mNames.removeAllViews();
         mPhoneticNames.removeAllViews();
         mNicknames.removeAllViews();
@@ -284,6 +294,7 @@
         mMaterialPalette = materialPalette;
 
         vlog("Setting compact editor state from " + rawContactDeltas);
+        addAccountInfo(rawContactDeltas, hasNewContact, readOnlyDisplayName, isUserProfile);
         addPhotoView(rawContactDeltas, viewIdGenerator, photoId, readOnlyDisplayName);
         addStructuredNameView(rawContactDeltas, nameId, readOnlyDisplayName);
         addEditorViews(rawContactDeltas);
@@ -291,6 +302,71 @@
         removeExtraEmptyTextFields(mEmails);
     }
 
+    private void addAccountInfo(RawContactDeltaList rawContactDeltas, boolean hasNewContact,
+            String readOnlyDisplayName, boolean isUserProfile) {
+        // Only show account info for inserts and first time edits of read-only accounts
+        if (!hasNewContact && TextUtils.isEmpty(readOnlyDisplayName)) {
+            vlog("Account info hidden");
+            mAccountContainer.setVisibility(View.GONE);
+            return;
+        }
+
+        // Get the default account
+        final AccountWithDataSet defaultAccountWithDataSet =
+                ContactEditorUtils.getInstance(getContext()).getDefaultAccount();
+        if (defaultAccountWithDataSet == null) {
+            vlog("Account info hidden because default account not set");
+            mAccountContainer.setVisibility(View.GONE);
+            return;
+        }
+
+        // We can assume the first writable raw contact is the newly created one because
+        // inserts have a delta list of size 1 and read-only contacts are should be of size 2
+        RawContactDelta defaultAccountRawContactDelta = null;
+        AccountType accountType = null;
+        for (RawContactDelta rawContactDelta : rawContactDeltas) {
+            if (!rawContactDelta.isVisible()) continue;
+            accountType = rawContactDelta.getAccountType(mAccountTypeManager);
+            if (accountType != null && accountType.areContactsWritable()) {
+                defaultAccountRawContactDelta = rawContactDelta;
+                break;
+            }
+        }
+        if (defaultAccountRawContactDelta == null) {
+            vlog("Account info hidden because no raw contact delta matched");
+            mAccountContainer.setVisibility(View.GONE);
+            return;
+        }
+        if (accountType == null) {
+            vlog("Account info hidden because no account type returned from raw contact delta");
+            mAccountContainer.setVisibility(View.GONE);
+            return;
+        }
+
+        // Get the account information for the default account RawContactDelta
+        final Pair<String,String> accountInfo = EditorUiUtils.getAccountInfo(getContext(),
+                isUserProfile, defaultAccountRawContactDelta.getAccountName(),
+                accountType.getDisplayLabel(getContext()));
+
+        // Set the account information already
+        if (accountInfo == null) {
+            vlog("Account info hidden because no account info could be composed");
+            mAccountContainer.setVisibility(View.GONE);
+            return;
+        }
+        vlog("Account info loaded");
+        if (accountInfo.first == null) {
+            mAccountNameView.setVisibility(View.GONE);
+        } else {
+            mAccountNameView.setVisibility(View.VISIBLE);
+            mAccountNameView.setText(accountInfo.first);
+        }
+        mAccountTypeView.setText(accountInfo.second);
+
+        mAccountContainer.setContentDescription(EditorUiUtils.getAccountInfoContentDescription(
+                accountInfo.first, accountInfo.second));
+    }
+
     private void addPhotoView(RawContactDeltaList rawContactDeltas,
             ViewIdGenerator viewIdGenerator, long photoId, String readOnlyDisplayName) {
         // If we're editing a read-only contact, the display name from the read-only
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index 434ed56..2935ad5 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -124,6 +124,7 @@
 
     private static final String KEY_HAS_NEW_CONTACT = "hasNewContact";
     private static final String KEY_NEW_CONTACT_READY = "newContactDataReady";
+    private static final String KEY_NEW_CONTACT_ACCOUNT_CHANGED = "newContactAccountChanged";
 
     private static final String KEY_IS_EDIT = "isEdit";
     private static final String KEY_EXISTING_CONTACT_READY = "existingContactDataReady";
@@ -348,6 +349,7 @@
     // Whether to show the new contact blank form and if it's corresponding delta is ready.
     protected boolean mHasNewContact;
     protected boolean mNewContactDataReady;
+    protected boolean mNewContactAccountChanged;
 
     // Whether it's an edit of existing contact and if it's corresponding delta is ready.
     protected boolean mIsEdit;
@@ -488,6 +490,7 @@
 
             mHasNewContact = savedState.getBoolean(KEY_HAS_NEW_CONTACT);
             mNewContactDataReady = savedState.getBoolean(KEY_NEW_CONTACT_READY);
+            mNewContactAccountChanged = savedState.getBoolean(KEY_NEW_CONTACT_ACCOUNT_CHANGED);
 
             mIsEdit = savedState.getBoolean(KEY_IS_EDIT);
             mExistingContactDataReady = savedState.getBoolean(KEY_EXISTING_CONTACT_READY);
@@ -613,6 +616,7 @@
         outState.putInt(KEY_STATUS, mStatus);
         outState.putBoolean(KEY_HAS_NEW_CONTACT, mHasNewContact);
         outState.putBoolean(KEY_NEW_CONTACT_READY, mNewContactDataReady);
+        outState.putBoolean(KEY_NEW_CONTACT_ACCOUNT_CHANGED, mNewContactAccountChanged);
         outState.putBoolean(KEY_IS_EDIT, mIsEdit);
         outState.putBoolean(KEY_EXISTING_CONTACT_READY, mExistingContactDataReady);
 
@@ -919,9 +923,10 @@
 
         mStatus = Status.SAVING;
 
-        // Determine if changes were made in the editor that need to be saved
-        // See go/editing-read-only-contacts
-        if (!hasPendingChanges()) {
+        // If the user did nothing else expect change the account type, we must still
+        // consider this as an unsaved change so the new rawcontact is passed back to the
+        // compact editor on inserts.
+        if (!mNewContactAccountChanged && !hasPendingChanges()) {
             if (mLookupUri == null && saveMode == SaveMode.RELOAD) {
                 // We don't have anything to save and there isn't even an existing contact yet.
                 // Nothing to do, simply go back to editing mode
@@ -992,8 +997,8 @@
         if (mReadOnlyNameEditorView == null || mReadOnlyDisplayName == null) {
             return hasPendingRawContactChanges();
         }
-        // We created a new raw contact delta with a default display name. We must test for
-        // pending changes while ignoring the default display name.
+        // We created a new raw contact delta with a default display name.
+        // We must test for pending changes while ignoring the default display name.
         final String displayName = mReadOnlyNameEditorView.getDisplayName();
         if (mReadOnlyDisplayName.equals(displayName)) {
             // The user did not modify the default display name, erase it and
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index 1e06306..4da17fa 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -477,6 +477,7 @@
                         UiClosables.closeQuietly(popup);
                         AccountWithDataSet newAccount = adapter.getItem(position);
                         if (!newAccount.equals(currentAccount)) {
+                            mNewContactAccountChanged = true;
                             rebindEditorsForNewContact(currentState, currentAccount, newAccount);
                         }
                     }
diff --git a/src/com/android/contacts/editor/EditorUiUtils.java b/src/com/android/contacts/editor/EditorUiUtils.java
index f3cf20a..301ce35 100644
--- a/src/com/android/contacts/editor/EditorUiUtils.java
+++ b/src/com/android/contacts/editor/EditorUiUtils.java
@@ -21,6 +21,9 @@
 import static android.provider.ContactsContract.CommonDataKinds.Photo;
 import static android.provider.ContactsContract.CommonDataKinds.StructuredName;
 
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Pair;
 import com.android.contacts.R;
 import com.android.contacts.common.model.dataitem.DataKind;
 import com.google.common.collect.Maps;
@@ -76,4 +79,47 @@
         }
         return id;
     }
+
+    /**
+     * Returns a Pair of the account name and type to display for the given arguments or null
+     * in no account information should be displayed. The account name may also be null.
+     */
+    public static Pair<String,String> getAccountInfo(Context context, boolean isProfile,
+            String accountName, CharSequence accountType) {
+        if (isProfile) {
+            if (TextUtils.isEmpty(accountName)) {
+                return new Pair<>(
+                        /* accountName =*/ null,
+                        context.getString(R.string.local_profile_title));
+            } else {
+                return new Pair<>(
+                        accountName,
+                        context.getString(R.string.external_profile_title, accountType));
+            }
+        } else if (!TextUtils.isEmpty(accountName)) {
+            if (TextUtils.isEmpty(accountType)) {
+                accountType = context.getString(R.string.account_phone);
+            }
+            return new Pair<>(
+                    context.getString(R.string.from_account_format, accountName),
+                    context.getString(R.string.account_type_format, accountType));
+        }
+        return null;
+    }
+
+    /**
+     * Returns a content description String for the container of the account information
+     * returned by {@link #getAccountInfo}.
+     */
+    public static String getAccountInfoContentDescription(CharSequence accountName,
+            CharSequence accountType) {
+        final StringBuilder builder = new StringBuilder();
+        if (!TextUtils.isEmpty(accountType)) {
+            builder.append(accountType).append('\n');
+        }
+        if (!TextUtils.isEmpty(accountName)) {
+            builder.append(accountName).append('\n');
+        }
+        return builder.toString();
+    }
 }
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index d81dc47..11f0c1e 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -28,6 +28,7 @@
 import android.provider.ContactsContract.Data;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Pair;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -189,34 +190,19 @@
         mRawContactId = state.getRawContactId();
 
         // Fill in the account info
-        if (isProfile) {
-            String accountName = state.getAccountName();
-            if (TextUtils.isEmpty(accountName)) {
-                mAccountHeaderNameTextView.setVisibility(View.GONE);
-                mAccountHeaderTypeTextView.setText(R.string.local_profile_title);
-            } else {
-                CharSequence accountType = type.getDisplayLabel(getContext());
-                mAccountHeaderTypeTextView.setText(getContext().getString(
-                        R.string.external_profile_title,
-                        accountType));
-                mAccountHeaderNameTextView.setText(accountName);
-            }
+        final Pair<String,String> accountInfo = EditorUiUtils.getAccountInfo(getContext(),
+                isProfile, state.getAccountName(), type.getDisplayLabel(getContext()));
+        if (accountInfo == null) {
+            // Hide this view so the other text view will be centered vertically
+            mAccountHeaderNameTextView.setVisibility(View.GONE);
         } else {
-            String accountName = state.getAccountName();
-            CharSequence accountType = type.getDisplayLabel(getContext());
-            if (TextUtils.isEmpty(accountType)) {
-                accountType = getContext().getString(R.string.account_phone);
-            }
-            if (!TextUtils.isEmpty(accountName)) {
-                mAccountHeaderNameTextView.setVisibility(View.VISIBLE);
-                mAccountHeaderNameTextView.setText(
-                        getContext().getString(R.string.from_account_format, accountName));
-            } else {
-                // Hide this view so the other text view will be centered vertically
+            if (accountInfo.first == null) {
                 mAccountHeaderNameTextView.setVisibility(View.GONE);
+            } else {
+                mAccountHeaderNameTextView.setVisibility(View.VISIBLE);
+                mAccountHeaderNameTextView.setText(accountInfo.first);
             }
-            mAccountHeaderTypeTextView.setText(
-                    getContext().getString(R.string.account_type_format, accountType));
+            mAccountHeaderTypeTextView.setText(accountInfo.second);
         }
         updateAccountHeaderContentDescription();