Merge "Try to show the "right" name on the compact contact editor"
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index 199d21f..f25d01a 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -19,16 +19,15 @@
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.AccountTypeManager;
import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.RawContactDeltaList;
+import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.util.ImplicitIntentsUtil;
import com.android.contacts.common.util.MaterialColorMapUtils;
import com.android.contacts.detail.PhotoSelectionHandler;
-import com.android.contacts.editor.Editor.EditorListener;
import com.android.contacts.util.ContactPhotoUtils;
import android.app.Activity;
@@ -38,7 +37,6 @@
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
-import android.provider.Contacts;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
@@ -221,28 +219,6 @@
mPhotoRawContactId = editorView.getPhotoRawContactId();
editorView.setPhotoHandler(mPhotoHandler);
- // Attach the aggregation suggestion engine to the structured name field
- final StructuredNameEditorView nameEditorView = editorView.getStructuredNameEditorView();
- if (nameEditorView != null) {
- nameEditorView.setEditorListener(new EditorListener() {
- @Override
- public void onRequest(int request) {
- final Activity activity = getActivity();
- if (activity == null || activity.isFinishing()) {
- return;
- }
- if (request == EditorListener.FIELD_CHANGED && !mIsUserProfile) {
- acquireAggregationSuggestions(activity, nameEditorView.getRawContactId(),
- nameEditorView.getValues());
- }
- }
-
- @Override
- public void onDeleteRequested(Editor editor) {
- }
- });
- }
-
// The editor is ready now so make it visible
editorView.setEnabled(isEnabled());
editorView.setVisibility(View.VISIBLE);
@@ -397,6 +373,17 @@
ImplicitIntentsUtil.startActivityInApp(getActivity(), intent);
}
+ @Override
+ public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta) {
+ final Activity activity = getActivity();
+ if (activity == null || activity.isFinishing()) {
+ return;
+ }
+ if (!mIsUserProfile) {
+ acquireAggregationSuggestions(activity, rawContactId, valuesDelta);
+ }
+ }
+
private CompactRawContactsEditorView getContent() {
return (CompactRawContactsEditorView) mContent;
}
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 1287d47..cb605c6 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -64,6 +64,54 @@
* Invoked when the compact editor should be expanded to show all fields.
*/
public void onExpandEditor();
+
+ /**
+ * Invoked when the structured name editor field has changed.
+ *
+ * @param rawContactId The raw contact ID from the underlying {@link RawContactDelta}.
+ * @param valuesDelta The values from the underlying {@link RawContactDelta}.
+ */
+ public void onNameFieldChanged(long rawContactId, ValuesDelta valuesDelta);
+ }
+
+ /**
+ * Marks a name as super primary when it is changed.
+ *
+ * This is for the case when two or more raw contacts with names are joined where neither is
+ * marked as super primary. If the user hits back (which causes a save) after changing the
+ * name that was arbitrarily displayed, we want that to be the name that is used.
+ *
+ * Should only be set when a super primary name does not already exist since we only show
+ * one name field.
+ */
+ static final class NameEditorListener implements Editor.EditorListener {
+
+ private final ValuesDelta mValuesDelta;
+ private final long mRawContactId;
+ private final Listener mListener;
+
+ public NameEditorListener(ValuesDelta valuesDelta, long rawContactId,
+ Listener listener) {
+ mValuesDelta = valuesDelta;
+ mRawContactId = rawContactId;
+ mListener = listener;
+ }
+
+ @Override
+ public void onRequest(int request) {
+ if (request == Editor.EditorListener.FIELD_CHANGED) {
+ mValuesDelta.setSuperPrimary(true);
+ if (mListener != null) {
+ mListener.onNameFieldChanged(mRawContactId, mValuesDelta);
+ }
+ } else if (request == Editor.EditorListener.FIELD_TURNED_EMPTY) {
+ mValuesDelta.setSuperPrimary(false);
+ }
+ }
+
+ @Override
+ public void onDeleteRequested(Editor editor) {
+ }
}
private Listener mListener;
@@ -83,6 +131,9 @@
private ViewGroup mOther;
private View mMoreFields;
+ // The ValuesDelta for the non super primary name that was displayed to the user.
+ private ValuesDelta mNameValuesDelta;
+
private long mPhotoRawContactId;
public CompactRawContactsEditorView(Context context) {
@@ -122,6 +173,13 @@
@Override
public void onClick(View view) {
if (view.getId() == R.id.more_fields && mListener != null ) {
+ // We mark the name that was displayed as super primary before expanding
+ // so that a save on the expanded editor (without a name change) does not
+ // cause the displayed name to change.
+ if (mNameValuesDelta != null) {
+ mNameValuesDelta.setSuperPrimary(true);
+ }
+
mListener.onExpandEditor();
}
}
@@ -208,14 +266,14 @@
/* valuesDelta =*/ null, ViewIdGenerator.NO_VIEW_INDEX));
mMaterialPalette = materialPalette;
- addHeaderView(rawContactDeltas, viewIdGenerator);
+ addPhotoView(rawContactDeltas, viewIdGenerator);
addStructuredNameView(rawContactDeltas);
addEditorViews(rawContactDeltas);
removeExtraEmptyTextFields(mPhoneNumbers);
removeExtraEmptyTextFields(mEmails);
}
- private void addHeaderView(RawContactDeltaList rawContactDeltas,
+ private void addPhotoView(RawContactDeltaList rawContactDeltas,
ViewIdGenerator viewIdGenerator) {
for (RawContactDelta rawContactDelta : rawContactDeltas) {
if (!rawContactDelta.isVisible()) {
@@ -243,24 +301,68 @@
private void addStructuredNameView(RawContactDeltaList rawContactDeltas) {
for (RawContactDelta rawContactDelta : rawContactDeltas) {
- if (!rawContactDelta.isVisible()) {
- continue;
- }
+ if (!rawContactDelta.isVisible()) continue;
final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
// Make sure we have a structured name
RawContactModifier.ensureKindExists(
rawContactDelta, accountType, StructuredName.CONTENT_ITEM_TYPE);
+ // Note use of pseudo mime type to get the DataKind and StructuredName to get value
final DataKind dataKind = accountType.getKindForMimetype(
+ DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
+ if (dataKind == null || !dataKind.editable) continue;
+
+ final ValuesDelta superPrimaryValuesDelta = getNonEmptySuperPrimaryValuesDeltas(
+ rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind);
+ if (superPrimaryValuesDelta != null) {
+ // Our first preference is for a non-empty super primary name
+ mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
+ superPrimaryValuesDelta, rawContactDelta, /* nameEditorListener =*/ null));
+ return;
+ }
+ }
+ // We didn't find a super primary name
+ for (RawContactDelta rawContactDelta : rawContactDeltas) {
+ if (!rawContactDelta.isVisible()) continue;
+ final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
+
+ final DataKind dataKind = accountType.getKindForMimetype(
+ DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
+ if (dataKind == null || !dataKind.editable) continue;
+
+ final List<ValuesDelta> nonEmptyValuesDeltas = getNonEmptyValuesDeltas(
+ rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind);
+ if (nonEmptyValuesDeltas != null && !nonEmptyValuesDeltas.isEmpty()) {
+ // Take the first non-empty name, also make it super primary before expanding to the
+ // full editor (see #onCLick) so that name does not change if the user saves from
+ // the fully expanded editor.
+ mNameValuesDelta = nonEmptyValuesDeltas.get(0);
+ final NameEditorListener nameEditorListener = new NameEditorListener(
+ mNameValuesDelta, rawContactDelta.getRawContactId(), mListener);
+ mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
+ mNameValuesDelta, rawContactDelta, nameEditorListener));
+ return;
+ }
+ }
+ for (RawContactDelta rawContactDelta : rawContactDeltas) {
+ if (!rawContactDelta.isVisible()) continue;
+ final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
+
+ final DataKind dataKind = accountType.getKindForMimetype(
+ DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME);
+ if (dataKind == null || !dataKind.editable) continue;
+
+ // Fall back to the first entry
+ final ArrayList<ValuesDelta> valuesDeltas = rawContactDelta.getMimeEntries(
StructuredName.CONTENT_ITEM_TYPE);
- if (dataKind != null) {
- final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(dataKind.mimeType);
- if (valuesDelta != null) {
- mNames.addView(inflateStructuredNameEditorView(
- mNames, accountType, valuesDelta, rawContactDelta));
- return;
- }
+ if (valuesDeltas != null && !valuesDeltas.isEmpty()) {
+ mNameValuesDelta = valuesDeltas.get(0);
+ final NameEditorListener nameEditorListener = new NameEditorListener(
+ mNameValuesDelta, rawContactDelta.getRawContactId(), mListener);
+ mNames.addView(inflateStructuredNameEditorView(mNames, accountType,
+ mNameValuesDelta, rawContactDelta, nameEditorListener));
+ return;
}
}
}
@@ -281,20 +383,24 @@
if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)
|| StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)
|| GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
- // Photos and name are handled separately; group membership is not supported
+ // Photos and structured names are handled separately and
+ // group membership is not supported
continue;
} else if (DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
- // Use the StructuredName mime type to get values
- if (hasNonEmptyPrimaryValuesDelta(
+ // Only add phonetic names if there is a non-empty one. Note the use of
+ // StructuredName mimeType below, even though we matched a pseudo mime type.
+ if (hasNonEmptyValuesDelta(
rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind)) {
- final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(
- StructuredName.CONTENT_ITEM_TYPE);
- mPhoneticNames.addView(inflatePhoneticNameEditorView(
- mPhoneticNames, accountType, valuesDelta, rawContactDelta));
+ for (ValuesDelta valuesDelta : getNonEmptyValuesDeltas(
+ rawContactDelta, StructuredName.CONTENT_ITEM_TYPE, dataKind)) {
+ mPhoneticNames.addView(inflatePhoneticNameEditorView(
+ mPhoneticNames, accountType, valuesDelta, rawContactDelta));
+ }
}
} else if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ // Only add nicknames if there is a non-empty one
if (hasNonEmptyValuesDelta(rawContactDelta, mimeType, dataKind)) {
- mNicknames.addView(inflateNicknameEditorView(
+ mNicknames.addView(inflateKindSectionView(
mNicknames, dataKind, rawContactDelta));
}
} else if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
@@ -357,7 +463,18 @@
return !getNonEmptyValuesDeltas(rawContactDelta, mimeType, dataKind).isEmpty();
}
- private static List<ValuesDelta> getNonEmptyValuesDeltas(RawContactDelta rawContactDelta,
+ private static ValuesDelta getNonEmptySuperPrimaryValuesDeltas(RawContactDelta rawContactDelta,
+ String mimeType, DataKind dataKind) {
+ for (ValuesDelta valuesDelta : getNonEmptyValuesDeltas(
+ rawContactDelta, mimeType, dataKind)) {
+ if (valuesDelta.isSuperPrimary()) {
+ return valuesDelta;
+ }
+ }
+ return null;
+ }
+
+ static List<ValuesDelta> getNonEmptyValuesDeltas(RawContactDelta rawContactDelta,
String mimeType, DataKind dataKind) {
final List<ValuesDelta> result = new ArrayList<>();
if (rawContactDelta == null) {
@@ -385,28 +502,14 @@
return result;
}
- private static boolean hasNonEmptyPrimaryValuesDelta(RawContactDelta rawContactDelta,
- String mimeType, DataKind dataKind) {
- final ValuesDelta valuesDelta = rawContactDelta.getPrimaryEntry(mimeType);
- if (valuesDelta == null) {
- return false;
- }
- for (EditField editField : dataKind.fieldList) {
- final String column = editField.column;
- final String value = valuesDelta == null ? null : valuesDelta.getAsString(column);
- log(Log.VERBOSE, "Field (primary) " + column + " empty=" + TextUtils.isEmpty(value) +
- " value=" + value);
- if (!TextUtils.isEmpty(value)) {
- return true;
- }
- }
- return false;
- }
-
private StructuredNameEditorView inflateStructuredNameEditorView(ViewGroup viewGroup,
- AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
+ AccountType accountType, ValuesDelta valuesDelta, RawContactDelta rawContactDelta,
+ NameEditorListener nameEditorListener) {
final StructuredNameEditorView result = (StructuredNameEditorView) mLayoutInflater.inflate(
R.layout.structured_name_editor_view, viewGroup, /* attachToRoot =*/ false);
+ if (nameEditorListener != null) {
+ result.setEditorListener(nameEditorListener);
+ }
result.setValues(
accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
valuesDelta,
@@ -429,19 +532,6 @@
return result;
}
- private KindSectionView inflateNicknameEditorView(ViewGroup viewGroup, DataKind dataKind,
- RawContactDelta rawContactDelta) {
- final KindSectionView result = (KindSectionView) mLayoutInflater.inflate(
- R.layout.item_kind_section, viewGroup, /* attachToRoot =*/ false);
- result.setState(
- dataKind,
- rawContactDelta,
- /* readOnly =*/ false,
- /* showOneEmptyEditor =*/ false,
- mViewIdGenerator);
- return result;
- }
-
private KindSectionView inflateKindSectionView(ViewGroup viewGroup, DataKind dataKind,
RawContactDelta rawContactDelta) {
final KindSectionView result = (KindSectionView) mLayoutInflater.inflate(
diff --git a/src/com/android/contacts/editor/ContactEditorFragment.java b/src/com/android/contacts/editor/ContactEditorFragment.java
index eb2de3a..96aaecd 100644
--- a/src/com/android/contacts/editor/ContactEditorFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorFragment.java
@@ -22,6 +22,8 @@
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.text.TextUtils;
import android.util.Log;
@@ -241,18 +243,49 @@
if (editor instanceof RawContactEditorView) {
final Activity activity = getActivity();
final RawContactEditorView rawContactEditor = (RawContactEditorView) editor;
- EditorListener listener = new EditorListener() {
+ final ValuesDelta nameValuesDelta = rawContactEditor.getNameEditor().getValues();
+ final EditorListener structuredNameListener = new EditorListener() {
@Override
public void onRequest(int request) {
- if (activity.isFinishing()) { // Make sure activity is still running.
+ // Make sure the activity is running
+ if (activity.isFinishing()) {
return;
}
- if (request == EditorListener.FIELD_CHANGED && !isEditingUserProfile()) {
- acquireAggregationSuggestions(activity,
- rawContactEditor.getNameEditor().getRawContactId(),
- rawContactEditor.getNameEditor().getValues());
- } else if (request == EditorListener.EDITOR_FOCUS_CHANGED) {
+ if (request == EditorListener.EDITOR_FOCUS_CHANGED) {
+ adjustNameFieldsHintDarkness(rawContactEditor);
+ return;
+ }
+ if (!isEditingUserProfile()) {
+ if (request == EditorListener.FIELD_CHANGED) {
+ if (!nameValuesDelta.isSuperPrimary()) {
+ unsetSuperPrimaryForAllNameEditors();
+ nameValuesDelta.setSuperPrimary(true);
+ }
+ acquireAggregationSuggestions(activity,
+ rawContactEditor.getNameEditor().getRawContactId(),
+ rawContactEditor.getNameEditor().getValues());
+ } else if (request == EditorListener.FIELD_TURNED_EMPTY) {
+ if (nameValuesDelta.isSuperPrimary()) {
+ nameValuesDelta.setSuperPrimary(false);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onDeleteRequested(Editor removedEditor) {
+ }
+ };
+ final EditorListener otherNamesListener = new EditorListener() {
+
+ @Override
+ public void onRequest(int request) {
+ // Make sure the activity is running
+ if (activity.isFinishing()) {
+ return;
+ }
+ if (request == EditorListener.EDITOR_FOCUS_CHANGED) {
adjustNameFieldsHintDarkness(rawContactEditor);
}
}
@@ -267,19 +300,19 @@
nameEditor.requestFocus();
mRequestFocus = false;
}
- nameEditor.setEditorListener(listener);
+ nameEditor.setEditorListener(structuredNameListener);
if (!TextUtils.isEmpty(mDefaultDisplayName)) {
nameEditor.setDisplayName(mDefaultDisplayName);
}
final TextFieldsEditorView phoneticNameEditor =
rawContactEditor.getPhoneticNameEditor();
- phoneticNameEditor.setEditorListener(listener);
+ phoneticNameEditor.setEditorListener(otherNamesListener);
rawContactEditor.setAutoAddToDefaultGroup(mAutoAddToDefaultGroup);
final TextFieldsEditorView nickNameEditor =
rawContactEditor.getNickNameEditor();
- nickNameEditor.setEditorListener(listener);
+ nickNameEditor.setEditorListener(otherNamesListener);
if (isAggregationSuggestionRawContactId(rawContactId)) {
acquireAggregationSuggestions(activity,
@@ -305,6 +338,23 @@
updatedExpandedEditorsMap();
}
+ private void unsetSuperPrimaryForAllNameEditors() {
+ for (int i = 0; i < mContent.getChildCount(); i++) {
+ final View view = mContent.getChildAt(i);
+ if (view instanceof RawContactEditorView) {
+ final RawContactEditorView rawContactEditorView = (RawContactEditorView) view;
+ final StructuredNameEditorView nameEditorView =
+ rawContactEditorView.getNameEditor();
+ if (nameEditorView != null) {
+ final ValuesDelta valuesDelta = nameEditorView.getValues();
+ if (valuesDelta != null) {
+ valuesDelta.setSuperPrimary(false);
+ }
+ }
+ }
+ }
+ }
+
/**
* Adjust how dark the hint text should be on all the names' text fields.
*