am 192a01c6: Phonetic names must be displayed next to structured names (E7)
* commit '192a01c63c836a7a6ac3e75d8cc14e764f34a42b':
Phonetic names must be displayed next to structured names (E7)
diff --git a/src/com/android/contacts/editor/CompactKindSectionView.java b/src/com/android/contacts/editor/CompactKindSectionView.java
index 8959c18..50ef405 100644
--- a/src/com/android/contacts/editor/CompactKindSectionView.java
+++ b/src/com/android/contacts/editor/CompactKindSectionView.java
@@ -17,8 +17,9 @@
package com.android.contacts.editor;
import android.content.Context;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
-import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -35,8 +36,6 @@
import com.android.contacts.editor.Editor.EditorListener;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.List;
/**
@@ -44,26 +43,6 @@
*/
public class CompactKindSectionView extends LinearLayout implements EditorListener {
- /** Sorts google account types before others. */
- private static final class KindSectionComparator implements Comparator<KindSectionData> {
-
- private RawContactDeltaComparator mRawContactDeltaComparator;
-
- private KindSectionComparator(Context context) {
- mRawContactDeltaComparator = new RawContactDeltaComparator(context);
- }
-
- @Override
- public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
- if (kindSectionData1 == kindSectionData2) return 0;
- if (kindSectionData1 == null) return -1;
- if (kindSectionData2 == null) return 1;
-
- return mRawContactDeltaComparator.compare(kindSectionData1.getRawContactDelta(),
- kindSectionData2.getRawContactDelta());
- }
- }
-
/**
* Marks a name as super primary when it is changed.
*
@@ -74,7 +53,7 @@
* 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 static final class NameEditorListener implements Editor.EditorListener {
private final ValuesDelta mValuesDelta;
private final long mRawContactId;
@@ -101,13 +80,23 @@
@Override
public void onDeleteRequested(Editor editor) {
+ editor.clearAllFields();
}
}
- private ViewGroup mEditors;
- private ImageView mIcon;
+ private static final class NicknameEditorListener implements Editor.EditorListener {
- private List<KindSectionData> mKindSectionDatas;
+ @Override
+ public void onRequest(int request) {
+ }
+
+ @Override
+ public void onDeleteRequested(Editor editor) {
+ editor.clearAllFields();
+ }
+ }
+
+ private List<KindSectionData> mKindSectionDataList;
private boolean mReadOnly;
private ViewIdGenerator mViewIdGenerator;
private CompactRawContactsEditorView.Listener mListener;
@@ -117,6 +106,8 @@
private boolean mHideIfEmpty = true;
private LayoutInflater mInflater;
+ private ViewGroup mEditors;
+ private ImageView mIcon;
public CompactKindSectionView(Context context) {
this(context, /* attrs =*/ null);
@@ -135,8 +126,6 @@
mEditors.getChildAt(i).setEnabled(enabled);
}
}
- // TODO: why is this necessary?
- updateEmptyEditors(/* shouldAnimate = */ true);
}
/** {@inheritDoc} */
@@ -172,8 +161,9 @@
}
/**
- * @param showOneEmptyEditor If true, we will always show one empty, otherwise an empty editor
- * will not be shown until the user enters a value.
+ * @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 has no effect
+ * on name editors since the policy is to always show names.
*/
public void setShowOneEmptyEditor(boolean showOneEmptyEditor) {
mShowOneEmptyEditor = showOneEmptyEditor;
@@ -181,23 +171,23 @@
/**
* @param hideWhenEmpty If true, the entire section will be hidden if all inputs are empty,
- * otherwise one empty input will always be displayed.
+ * otherwise one empty input will always be displayed. Note, this has no effect
+ * on name editors since the policy is to always show names.
*/
public void setHideWhenEmpty(boolean hideWhenEmpty) {
mHideIfEmpty = hideWhenEmpty;
}
- public void setState(List<KindSectionData> kindSectionDatas, boolean readOnly,
+ public void setState(List<KindSectionData> kindSectionDataList, boolean readOnly,
ViewIdGenerator viewIdGenerator, CompactRawContactsEditorView.Listener listener) {
- mKindSectionDatas = kindSectionDatas;
- Collections.sort(mKindSectionDatas, new KindSectionComparator(getContext()));
+ mKindSectionDataList = kindSectionDataList;
mReadOnly = readOnly;
mViewIdGenerator = viewIdGenerator;
mListener = listener;
// Set the icon using the first DataKind (all DataKinds should be the same type)
- final DataKind dataKind = mKindSectionDatas.isEmpty()
- ? null : mKindSectionDatas.get(0).getDataKind();
+ final DataKind dataKind = mKindSectionDataList.isEmpty()
+ ? null : mKindSectionDataList.get(0).getDataKind();
if (dataKind != null) {
mIcon.setContentDescription(dataKind.titleRes == -1 || dataKind.titleRes == 0
? "" : getResources().getString(dataKind.titleRes));
@@ -217,20 +207,10 @@
private void rebuildFromState() {
mEditors.removeAllViews();
- // Check if we are displaying anything here
- boolean hasValuesDeltas = false;
- for (KindSectionData kindSectionData : mKindSectionDatas) {
- if (kindSectionData.hasValuesDeltas()) {
- hasValuesDeltas = true;
- break;
- }
- }
- if (!hasValuesDeltas) return;
-
- for (KindSectionData kindSectionData : mKindSectionDatas) {
+ for (KindSectionData kindSectionData : mKindSectionDataList) {
if (StructuredName.CONTENT_ITEM_TYPE.equals(kindSectionData.getDataKind().mimeType)) {
for (ValuesDelta valuesDelta : kindSectionData.getValuesDeltas()) {
- createStructuredNameEditorView(kindSectionData.getAccountType(),
+ createNameEditorViews(kindSectionData.getAccountType(),
valuesDelta, kindSectionData.getRawContactDelta());
}
} else {
@@ -242,21 +222,41 @@
}
}
- private void createStructuredNameEditorView(AccountType accountType,
+ private void createNameEditorViews(AccountType accountType,
ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
- final StructuredNameEditorView view = (StructuredNameEditorView) mInflater.inflate(
- R.layout.structured_name_editor_view, mEditors, /* attachToRoot =*/ false);
- view.setEditorListener(new NameEditorListener(valuesDelta,
- rawContactDelta.getRawContactId(), mListener));
- view.findViewById(R.id.kind_icon).setVisibility(View.GONE);
- view.setDeletable(false);
final boolean readOnly = !accountType.areContactsWritable();
- view.setValues(accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
+
+ // Structured name
+ final StructuredNameEditorView nameView = (StructuredNameEditorView) mInflater.inflate(
+ R.layout.structured_name_editor_view, mEditors, /* attachToRoot =*/ false);
+ nameView.setEditorListener(new NameEditorListener(valuesDelta,
+ rawContactDelta.getRawContactId(), mListener));
+ nameView.setDeletable(false);
+ nameView.setValues(
+ accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
valuesDelta, rawContactDelta, readOnly, mViewIdGenerator);
- if (readOnly) {
- view.setAccountType(accountType);
- }
- mEditors.addView(view);
+ if (readOnly) nameView.setAccountType(accountType);
+
+ // Correct start margin since there is another icon in the structured name layout
+ nameView.findViewById(R.id.kind_icon).setVisibility(View.GONE);
+ mEditors.addView(nameView);
+
+ // Phonetic name
+ if (readOnly) return;
+
+ final PhoneticNameEditorView phoneticNameView = (PhoneticNameEditorView) mInflater.inflate(
+ R.layout.phonetic_name_editor_view, mEditors, /* attachToRoot =*/ false);
+ phoneticNameView.setDeletable(false);
+ phoneticNameView.setValues(
+ accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME),
+ valuesDelta, rawContactDelta, readOnly, mViewIdGenerator);
+
+ // Fix the start margin for phonetic name views
+ final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ layoutParams.setMargins(0, 0, 0, 0);
+ phoneticNameView.setLayoutParams(layoutParams);
+ mEditors.addView(phoneticNameView);
}
/**
@@ -281,21 +281,18 @@
((LabeledEditorView) view).setHideTypeInitially(true);
}
- // Fix the start margin for phonetic name views
- if (view instanceof PhoneticNameEditorView) {
- final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- layoutParams.setMargins(0, 0, 0, 0);
- view.setLayoutParams(layoutParams);
- }
-
// Set whether the editor is enabled
view.setEnabled(isEnabled());
if (view instanceof Editor) {
final Editor editor = (Editor) view;
editor.setDeletable(true);
- editor.setEditorListener(this);
+ // TODO: it's awkward to be doing something special for nicknames here
+ if (Nickname.CONTENT_ITEM_TYPE.equals(dataKind.mimeType)) {
+ editor.setEditorListener(new NicknameEditorListener());
+ } else {
+ editor.setEditorListener(this);
+ }
editor.setValues(dataKind, valuesDelta, rawContactDelta, !dataKind.editable,
mViewIdGenerator);
}
@@ -310,10 +307,46 @@
* then the entire section is hidden.
*/
public void updateEmptyEditors(boolean shouldAnimate) {
- if (mKindSectionDatas.isEmpty()) return;
- final DataKind dataKind = mKindSectionDatas.get(0).getDataKind();
- final RawContactDelta rawContactDelta = mKindSectionDatas.get(0).getRawContactDelta();
+ if (mKindSectionDataList.get(0).isNameDataKind()) {
+ updateEmptyNameEditors(shouldAnimate);
+ } else {
+ updateEmptyNonNameEditors(shouldAnimate);
+ }
+ }
+ private void updateEmptyNameEditors(boolean shouldAnimate) {
+ boolean isEmptyNameEditorVisible = false;
+
+ for (int i = 0; i < mEditors.getChildCount(); i++) {
+ final View view = mEditors.getChildAt(i);
+ final Editor editor = (Editor) view;
+ if (view instanceof StructuredNameEditorView) {
+ // We always show one empty structured name view
+ if (editor.isEmpty()) {
+ if (isEmptyNameEditorVisible) {
+ // If we're already showing an empty editor then hide any other empties
+ if (mHideIfEmpty) {
+ view.setVisibility(View.GONE);
+ }
+ } else {
+ isEmptyNameEditorVisible = true;
+ }
+ } else {
+ showView(view, shouldAnimate);
+ isEmptyNameEditorVisible = true;
+ }
+ } else {
+ // For phonetic names and nicknames, which can't be added, just show or hide them
+ if (mHideIfEmpty && editor.isEmpty()) {
+ hideView(view, shouldAnimate);
+ } else {
+ showView(view, shouldAnimate);
+ }
+ }
+ }
+ }
+
+ private void updateEmptyNonNameEditors(boolean shouldAnimate) {
// Update whether the entire section is visible or not
final int editorCount = getEditorCount();
final List<View> emptyEditors = getEmptyEditors();
@@ -323,36 +356,28 @@
}
setVisibility(VISIBLE);
- // Update the number of empty editors
+ // Prune excess empty editors
if (emptyEditors.size() > 1) {
// If there is more than 1 empty editor, then remove it from the list of editors.
int deleted = 0;
- for (final View emptyEditorView : emptyEditors) {
+ for (final View view : emptyEditors) {
// If no child {@link View}s are being focused on within this {@link View}, then
- // remove this empty editor. We can assume that at least one empty editor has focus.
- // One way to get two empty editors is by deleting characters from a non-empty
- // editor, in which case this editor has focus. Another way is if there is more
- // values delta so we must also count number of editors deleted.
-
- // TODO: we must not delete the editor for the "primary" account. It's working
- // because the primary account is always the last one when the account is changed
- // in the editor but it is a bit brittle to rely on that (though that is what is
- // happening in LMP).
- if (emptyEditorView.findFocus() == null) {
- final Editor editor = (Editor) emptyEditorView;
- if (shouldAnimate) {
- editor.deleteEditor();
- } else {
- mEditors.removeView(emptyEditorView);
- }
+ // remove this empty editor. We can assume that at least one empty editor has
+ // focus. One way to get two empty editors is by deleting characters from a
+ // non-empty editor, in which case this editor has focus. Another way is if
+ // there is more values delta so we must also count number of editors deleted.
+ if (view.findFocus() == null) {
+ deleteView(view, shouldAnimate);
deleted++;
- if (deleted == emptyEditors.size() -1) break;
+ if (deleted == emptyEditors.size() - 1) break;
}
}
return;
}
- if (dataKind == null // There is nothing we can do.
- || mReadOnly // We don't show empty editors for read only data kinds.
+ // Determine if we should add a new empty editor
+ final DataKind dataKind = mKindSectionDataList.get(0).getDataKind();
+ if (mReadOnly // We don't show empty editors for read only data kinds.
+ || dataKind == null // There is nothing we can do.
// We have already reached the maximum number of editors, don't add any more.
|| (dataKind.typeOverallMax == editorCount && dataKind.typeOverallMax != 0)
// We have already reached the maximum number of empty editors, don't add any more.
@@ -361,12 +386,37 @@
}
// Add a new empty editor
if (mShowOneEmptyEditor) {
+ final RawContactDelta rawContactDelta = mKindSectionDataList.get(0).getRawContactDelta();
final ValuesDelta values = RawContactModifier.insertChild(rawContactDelta, dataKind);
- final View editorView = createEditorView(rawContactDelta, dataKind, values);
- if (shouldAnimate) {
- editorView.setVisibility(View.GONE);
- EditorAnimator.getInstance().showFieldFooter(editorView);
- }
+ final View view = createEditorView(rawContactDelta, dataKind, values);
+ showView(view, shouldAnimate);
+ }
+ }
+
+ private void hideView(View view, boolean shouldAnimate) {
+ if (shouldAnimate) {
+ EditorAnimator.getInstance().hideEditorView(view);
+ } else {
+ view.setVisibility(View.GONE);
+ }
+ }
+
+ private void deleteView(View view, boolean shouldAnimate) {
+ if (shouldAnimate) {
+ final Editor editor = (Editor) view;
+ editor.deleteEditor();
+ } else {
+ mEditors.removeView(view);
+ }
+ }
+
+ private void showView(View view, boolean shouldAnimate) {
+ if (shouldAnimate) {
+ view.setVisibility(View.GONE);
+ // TODO: still need this since we have animateLayoutChanges="true" on the parent layout?
+ EditorAnimator.getInstance().showFieldFooter(view);
+ } else {
+ view.setVisibility(View.VISIBLE);
}
}
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 8f268b4..540bf1a 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -61,6 +61,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -75,7 +76,8 @@
private static final String TAG = "CompactEditorView";
- private static final MimeTypeComparator MIME_TYPE_COMPARATOR = new MimeTypeComparator();
+ private static final KindSectionDataMapEntryComparator
+ KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR = new KindSectionDataMapEntryComparator();
/**
* Callbacks for hosts of {@link CompactRawContactsEditorView}s.
@@ -101,19 +103,38 @@
AccountWithDataSet oldAccount, AccountWithDataSet newAccount);
}
- /** Used to sort kind sections. */
- private static final class MimeTypeComparator implements
+ /** Used to sort entire kind sections. */
+ private static final class KindSectionDataMapEntryComparator implements
Comparator<Map.Entry<String,List<KindSectionData>>> {
- // Order of kinds roughly matches quick contacts; we diverge in the following ways:
- // 1) all names are together at the top (in quick contacts the nickname and phonetic name
- // are in the about card)
- // 2) IM is moved up after addresses
- // 3) SIP addresses are moved to below phone numbers
+ final MimeTypeComparator mMimeTypeComparator = new MimeTypeComparator();
+
+ @Override
+ public int compare(Map.Entry<String, List<KindSectionData>> entry1,
+ Map.Entry<String, List<KindSectionData>> entry2) {
+ if (entry1 == entry2) return 0;
+ if (entry1 == null) return -1;
+ if (entry2 == null) return 1;
+
+ final String mimeType1 = entry1.getKey();
+ final String mimeType2 = entry2.getKey();
+
+ return mMimeTypeComparator.compare(mimeType1, mimeType2);
+ }
+ }
+
+ /**
+ * Sorts kinds roughly the same as quick contacts; we diverge in the following ways:
+ * <ol>
+ * <li>All names are together at the top.</li>
+ * <li>IM is moved up after addresses</li>
+ * <li>SIP addresses are moved to below phone numbers</li>
+ * </ol>
+ */
+ private static final class MimeTypeComparator implements Comparator<String> {
+
private static final List<String> MIME_TYPE_ORDER = Arrays.asList(new String[] {
StructuredName.CONTENT_ITEM_TYPE,
- DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME,
- DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME,
Nickname.CONTENT_ITEM_TYPE,
Phone.CONTENT_ITEM_TYPE,
SipAddress.CONTENT_ITEM_TYPE,
@@ -128,14 +149,10 @@
});
@Override
- public int compare(Map.Entry<String, List<KindSectionData>> entry1,
- Map.Entry<String, List<KindSectionData>> entry2) {
- if (entry1 == entry2) return 0;
- if (entry1 == null) return -1;
- if (entry2 == null) return 1;
-
- final String mimeType1 = entry1.getKey();
- final String mimeType2 = entry2.getKey();
+ public int compare(String mimeType1, String mimeType2) {
+ if (mimeType1 == mimeType2) return 0;
+ if (mimeType1 == null) return -1;
+ if (mimeType2 == null) return 1;
int index1 = MIME_TYPE_ORDER.indexOf(mimeType1);
int index2 = MIME_TYPE_ORDER.indexOf(mimeType2);
@@ -149,6 +166,84 @@
}
}
+ /**
+ * Sorts primary accounts and google account types before others.
+ */
+ private static final class EditorComparator implements Comparator<KindSectionData> {
+
+ private RawContactDeltaComparator mRawContactDeltaComparator;
+
+ private EditorComparator(Context context) {
+ mRawContactDeltaComparator = new RawContactDeltaComparator(context);
+ }
+
+ @Override
+ public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
+ if (kindSectionData1 == kindSectionData2) return 0;
+ if (kindSectionData1 == null) return -1;
+ if (kindSectionData2 == null) return 1;
+
+ final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
+ final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
+
+ if (rawContactDelta1 == rawContactDelta2) return 0;
+ if (rawContactDelta1 == null) return -1;
+ if (rawContactDelta2 == null) return 1;
+
+ return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
+ }
+ }
+
+ /**
+ * Sorts primary account names first, followed by google account types, and other account
+ * types last. For names from the same account we order structured names before nicknames,
+ * but still keep names from the same account together.
+ */
+ private static final class NameEditorComparator implements Comparator<KindSectionData> {
+
+ private RawContactDeltaComparator mRawContactDeltaComparator;
+ private MimeTypeComparator mMimeTypeComparator;
+ private RawContactDelta mPrimaryRawContactDelta;
+
+ private NameEditorComparator(Context context, RawContactDelta primaryRawContactDelta) {
+ mRawContactDeltaComparator = new RawContactDeltaComparator(context);
+ mMimeTypeComparator = new MimeTypeComparator();
+ mPrimaryRawContactDelta = primaryRawContactDelta;
+ }
+
+ @Override
+ public int compare(KindSectionData kindSectionData1, KindSectionData kindSectionData2) {
+ if (kindSectionData1 == kindSectionData2) return 0;
+ if (kindSectionData1 == null) return -1;
+ if (kindSectionData2 == null) return 1;
+
+ final RawContactDelta rawContactDelta1 = kindSectionData1.getRawContactDelta();
+ final RawContactDelta rawContactDelta2 = kindSectionData2.getRawContactDelta();
+
+ if (rawContactDelta1 == rawContactDelta2) return 0;
+ if (rawContactDelta1 == null) return -1;
+ if (rawContactDelta2 == null) return 1;
+
+ final boolean isRawContactDelta1Primary =
+ mPrimaryRawContactDelta.equals(rawContactDelta1);
+ final boolean isRawContactDelta2Primary =
+ mPrimaryRawContactDelta.equals(rawContactDelta2);
+
+ // If both names are from the primary account, sort my by mime type
+ if (isRawContactDelta1Primary && isRawContactDelta2Primary) {
+ final String mimeType1 = kindSectionData1.getDataKind().mimeType;
+ final String mimeType2 = kindSectionData2.getDataKind().mimeType;
+ return mMimeTypeComparator.compare(mimeType1, mimeType2);
+ }
+
+ // The primary account name should be before all others
+ if (isRawContactDelta1Primary) return 1;
+ if (isRawContactDelta2Primary) return -1;
+
+ return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
+ }
+ }
+
private CompactRawContactsEditorView.Listener mListener;
private AccountTypeManager mAccountTypeManager;
@@ -228,8 +323,9 @@
final CompactKindSectionView kindSectionView =
(CompactKindSectionView) mKindSectionViews.getChildAt(i);
kindSectionView.setHideWhenEmpty(false);
- // Prevent the user from adding new names
- if (!StructuredName.CONTENT_ITEM_TYPE.equals(kindSectionView.getMimeType())) {
+ // Except the user is never allowed to add new names
+ final String mimeType = kindSectionView.getMimeType();
+ if (!StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
kindSectionView.setShowOneEmptyEditor(true);
}
kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ false);
@@ -284,14 +380,11 @@
}
public View getAggregationAnchorView() {
- // TODO: since there may be more than one structured name now we should return the one
- // being edited instead of just the first one.
- for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
- final CompactKindSectionView kindSectionView =
- (CompactKindSectionView) mKindSectionViews.getChildAt(i);
- if (!StructuredName.CONTENT_ITEM_TYPE.equals(kindSectionView.getMimeType())) {
- return kindSectionView.findViewById(R.id.anchor_view);
- }
+ // The kind section for the primary account is sorted to the front
+ final List<KindSectionData> kindSectionDataList = getKindSectionDataList(
+ StructuredName.CONTENT_ITEM_TYPE);
+ if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
+ return mKindSectionViews.getChildAt(0).findViewById(R.id.anchor_view);
}
return null;
}
@@ -321,8 +414,7 @@
elog("No raw contact deltas");
return;
}
- vlog("state: setting state from " + rawContactDeltas.size() + " RawContactDelta(s)");
- parseRawContactDeltas(rawContactDeltas);
+ parseRawContactDeltas(rawContactDeltas, mPrimaryAccount);
if (mKindSectionDataMap == null || mKindSectionDataMap.isEmpty()) {
elog("No kind section data parsed from RawContactDelta(s)");
return;
@@ -337,14 +429,15 @@
updateMoreFieldsButton();
}
- private void parseRawContactDeltas(RawContactDeltaList rawContactDeltas) {
- if (mPrimaryAccount != null) {
+ private void parseRawContactDeltas(RawContactDeltaList rawContactDeltas,
+ AccountWithDataSet primaryAccount) {
+ if (primaryAccount != null) {
// Use the first writable contact that matches the primary account
for (RawContactDelta rawContactDelta : rawContactDeltas) {
if (!rawContactDelta.isVisible()) continue;
final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
if (accountType == null || !accountType.areContactsWritable()) continue;
- if (matchesPrimaryAccount(rawContactDelta)) {
+ if (matchesAccount(primaryAccount, rawContactDelta)) {
vlog("parse: matched primary account raw contact");
mPrimaryRawContactDelta = rawContactDelta;
break;
@@ -363,20 +456,22 @@
}
}
}
+
if (mPrimaryRawContactDelta != null) {
RawContactModifier.ensureKindExists(mPrimaryRawContactDelta,
mPrimaryRawContactDelta.getAccountType(mAccountTypeManager),
StructuredName.CONTENT_ITEM_TYPE);
-
RawContactModifier.ensureKindExists(mPrimaryRawContactDelta,
mPrimaryRawContactDelta.getAccountType(mAccountTypeManager),
Photo.CONTENT_ITEM_TYPE);
}
// Build the kind section data list map
- for (RawContactDelta rawContactDelta : rawContactDeltas) {
+ vlog("parse: " + rawContactDeltas.size() + " rawContactDelta(s)");
+ for (int j = 0; j < rawContactDeltas.size(); j++) {
+ final RawContactDelta rawContactDelta = rawContactDeltas.get(j);
+ vlog("parse: " + j + " rawContactDelta" + rawContactDelta);
if (rawContactDelta == null || !rawContactDelta.isVisible()) continue;
- vlog("parse: " + rawContactDelta);
final AccountType accountType = rawContactDelta.getAccountType(mAccountTypeManager);
if (accountType == null) continue;
final List<DataKind> dataKinds = accountType.getSortedDataKinds();
@@ -384,20 +479,42 @@
vlog("parse: " + dataKindSize + " dataKinds(s)");
for (int i = 0; i < dataKindSize; i++) {
final DataKind dataKind = dataKinds.get(i);
- if (dataKind == null || !dataKind.editable) continue;
+ if (dataKind == null || !dataKind.editable) {
+ vlog("parse: " + i + " " + dataKind.mimeType + " dropped read-only");
+ continue;
+ }
+ final String mimeType = dataKind.mimeType;
+
+ // Skip psuedo mime types
+ if (DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)
+ || DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(mimeType)) {
+ vlog("parse: " + i + " " + dataKind.mimeType + " dropped pseudo type");
+ continue;
+ }
+
final List<KindSectionData> kindSectionDataList =
- getKindSectionDataList(dataKind.mimeType);
+ getKindSectionDataList(mimeType);
final KindSectionData kindSectionData =
new KindSectionData(accountType, dataKind, rawContactDelta);
kindSectionDataList.add(kindSectionData);
+
+ // Note we must create a nickname entry on inserts
+ if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
+ && kindSectionData.getValuesDeltas().isEmpty()
+ && mHasNewContact) {
+ RawContactModifier.insertChild(rawContactDelta, dataKind);
+ }
+
vlog("parse: " + i + " " + dataKind.mimeType + " " +
- (kindSectionData.hasValuesDeltas()
- ? kindSectionData.getValuesDeltas().size() : 0) + " value(s)");
+ kindSectionData.getValuesDeltas().size() + " value(s)");
}
}
}
private List<KindSectionData> getKindSectionDataList(String mimeType) {
+ // Put structured names and nicknames together
+ mimeType = Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
+ ? StructuredName.CONTENT_ITEM_TYPE : mimeType;
List<KindSectionData> kindSectionDataList = mKindSectionDataMap.get(mimeType);
if (kindSectionDataList == null) {
kindSectionDataList = new ArrayList<>();
@@ -406,11 +523,13 @@
return kindSectionDataList;
}
- /** Whether the given RawContactDelta is from the primary account. */
- private boolean matchesPrimaryAccount(RawContactDelta rawContactDelta) {
- return Objects.equals(mPrimaryAccount.name, rawContactDelta.getAccountName())
- && Objects.equals(mPrimaryAccount.type, rawContactDelta.getAccountType())
- && Objects.equals(mPrimaryAccount.dataSet, rawContactDelta.getDataSet());
+ /** Whether the given RawContactDelta belong to the given account. */
+ private boolean matchesAccount(AccountWithDataSet accountWithDataSet,
+ RawContactDelta rawContactDelta) {
+ if (accountWithDataSet == null) return false;
+ return Objects.equals(accountWithDataSet.name, rawContactDelta.getAccountName())
+ && Objects.equals(accountWithDataSet.type, rawContactDelta.getAccountType())
+ && Objects.equals(accountWithDataSet.dataSet, rawContactDelta.getDataSet());
}
private void addAccountInfo() {
@@ -513,7 +632,7 @@
// If we're editing a read-only contact we want to display the photo from the
// read-only contact in a photo editor backed by the new raw contact
- // that was created. The new raw contact is the first writable one.
+ // that was created.
if (mHasNewContact) {
mPhotoRawContactId = mPrimaryRawContactDelta == null
? null : mPrimaryRawContactDelta.getRawContactId();
@@ -584,7 +703,7 @@
private void addKindSectionViews() {
// Sort the kinds
final TreeSet<Map.Entry<String,List<KindSectionData>>> entries =
- new TreeSet<>(MIME_TYPE_COMPARATOR);
+ new TreeSet<>(KIND_SECTION_DATA_MAP_ENTRY_COMPARATOR);
entries.addAll(mKindSectionDataMap.entrySet());
vlog("kind: " + entries.size() + " kindSection(s)");
@@ -602,13 +721,12 @@
}
// Ignore mime types that we don't handle
- if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)
- || DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME.equals(mimeType)) {
+ if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
vlog("kind: " + i + " " + mimeType + " dropped");
continue;
}
- if (kindSectionDataList != null) {
+ if (kindSectionDataList != null && !kindSectionDataList.isEmpty()) {
vlog("kind: " + i + " " + mimeType + ": " + kindSectionDataList.size() +
" kindSectionData(s)");
@@ -625,18 +743,23 @@
mLayoutInflater.inflate(R.layout.compact_item_kind_section, viewGroup,
/* attachToRoot =*/ false);
- if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)
- || Phone.CONTENT_ITEM_TYPE.equals(mimeType)
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)
|| Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
- // Names, phone numbers, and email addresses are always displayed.
- // Phone numbers and email addresses are the only types you add new values
- // to initially.
+ // Phone numbers and email addresses are always displayed,
+ // even if they are empty
kindSectionView.setHideWhenEmpty(false);
}
- // Prevent the user from adding any new names
- if (!StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
- kindSectionView.setShowOneEmptyEditor(true);
+ // Since phone numbers and email addresses displayed even if they are empty,
+ // they will be the only types you add new values to initially for new contacts
+ kindSectionView.setShowOneEmptyEditor(true);
+
+ // Sort so the editors wind up in the order we want
+ if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ Collections.sort(kindSectionDataList, new NameEditorComparator(getContext(),
+ mPrimaryRawContactDelta));
+ } else {
+ Collections.sort(kindSectionDataList, new EditorComparator(getContext()));
}
kindSectionView.setState(kindSectionDataList, /* readOnly =*/ false, mViewIdGenerator,
diff --git a/src/com/android/contacts/editor/KindSectionData.java b/src/com/android/contacts/editor/KindSectionData.java
index 6455ff5..7b383fb 100644
--- a/src/com/android/contacts/editor/KindSectionData.java
+++ b/src/com/android/contacts/editor/KindSectionData.java
@@ -22,10 +22,10 @@
import com.android.contacts.common.model.account.AccountType.EditField;
import com.android.contacts.common.model.dataitem.DataKind;
+import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.text.TextUtils;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -44,23 +44,13 @@
mAccountType = accountType;
mDataKind = dataKind;
mRawContactDelta = rawContactDelta;
-
- // Note that for phonetic names we use the structured name mime type to look up values
- final String mimeType = DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME.equals(dataKind.mimeType)
- ? StructuredName.CONTENT_ITEM_TYPE : dataKind.mimeType;
- mValuesDeltas = mRawContactDelta.hasMimeEntries(mimeType)
- ? mRawContactDelta.getMimeEntries(mimeType)
- : Collections.EMPTY_LIST;
+ mValuesDeltas = mRawContactDelta.getMimeEntries(dataKind.mimeType, /* lazyCreate= */ true);
}
public AccountType getAccountType() {
return mAccountType;
}
- public boolean hasValuesDeltas() {
- return !mValuesDeltas.isEmpty();
- }
-
public List<ValuesDelta> getValuesDeltas() {
return mValuesDeltas;
}
@@ -107,6 +97,11 @@
return mDataKind;
}
+ public boolean isNameDataKind() {
+ return StructuredName.CONTENT_ITEM_TYPE.equals(mDataKind.mimeType)
+ || Nickname.CONTENT_ITEM_TYPE.equals(mDataKind.mimeType);
+ }
+
public RawContactDelta getRawContactDelta() {
return mRawContactDelta;
}
@@ -116,6 +111,6 @@
KindSectionData.class.getSimpleName(),
mAccountType.accountType,
mAccountType.dataSet,
- hasValuesDeltas() ? getValuesDeltas().size() : "null");
+ getValuesDeltas().size());
}
}
\ No newline at end of file