Merge "Use TransactionSafeActivity" into ub-contactsdialer-a-dev
diff --git a/res/layout/contact_editor_accounts_changed_activity_with_picker.xml b/res/layout/contact_editor_accounts_changed_activity_with_picker.xml
index a5aab20..a4f1b0a 100644
--- a/res/layout/contact_editor_accounts_changed_activity_with_picker.xml
+++ b/res/layout/contact_editor_accounts_changed_activity_with_picker.xml
@@ -27,7 +27,12 @@
<TextView android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:padding="15dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
+ android:paddingTop="15dip"
+ android:paddingBottom="15dip"
+ android:paddingLeft="10dip"
+ android:paddingRight="10dip"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<View
@@ -39,6 +44,7 @@
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
+ android:layout_marginLeft="16dip"
android:fadingEdge="none"/>
<View
diff --git a/res/layout/structured_name_editor_view.xml b/res/layout/structured_name_editor_view.xml
index 2984104..830f4d8 100644
--- a/res/layout/structured_name_editor_view.xml
+++ b/res/layout/structured_name_editor_view.xml
@@ -19,44 +19,35 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:minHeight="@dimen/editor_min_line_item_height"
+ android:orientation="horizontal">
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="@dimen/editor_min_line_item_height"
- android:orientation="horizontal">
+ <!-- This isn't used in StructuredNameEditorView. It is only included so that
+ StructuredNameEditorView's base classes don't need extra null checks. -->
+ <include
+ android:id="@+id/spinner"
+ layout="@layout/edit_spinner"
+ android:visibility="gone"/>
- <!-- This isn't used in StructuredNameEditorView. It is only included so that
- StructuredNameEditorView's base classes don't need extra null checks. -->
- <include
- android:id="@+id/spinner"
- layout="@layout/edit_spinner"
- android:visibility="gone" />
+ <ImageView
+ android:id="@+id/kind_icon"
+ android:src="@drawable/ic_person_black_24dp"
+ android:contentDescription="@string/header_name_entry"
+ style="@style/EditKindIconStyle"/>
- <ImageView
- android:id="@+id/kind_icon"
- android:src="@drawable/ic_person_black_24dp"
- android:contentDescription="@string/header_name_entry"
- style="@style/EditKindIconStyle" />
+ <include
+ layout="@layout/edit_field_list_with_anchor_view"/>
- <include
- layout="@layout/edit_field_list_with_anchor_view" />
+ <include
+ android:id="@+id/expansion_view_container"
+ layout="@layout/name_edit_expansion_view"
+ android:visibility="gone"/>
- <include
- android:id="@+id/expansion_view_container"
- layout="@layout/name_edit_expansion_view"
- android:visibility="gone" />
-
- <!-- This isn't used in StructuredNameEditorView. It is only included so that
- StructuredNameEditorView's base classes don't need extra null checks. -->
- <include
- android:id="@+id/delete_button_container"
- layout="@layout/edit_delete_button"
- android:visibility="gone" />
-
- </LinearLayout>
-
- <include layout="@layout/account_type_info"/>
+ <!-- This isn't used in StructuredNameEditorView. It is only included so that
+ StructuredNameEditorView's base classes don't need extra null checks. -->
+ <include
+ android:id="@+id/delete_button_container"
+ layout="@layout/edit_delete_button"
+ android:visibility="gone"/>
</com.android.contacts.editor.StructuredNameEditorView>
diff --git a/res/layout/structured_name_readonly_editor_view.xml b/res/layout/structured_name_readonly_editor_view.xml
new file mode 100644
index 0000000..4778570
--- /dev/null
+++ b/res/layout/structured_name_readonly_editor_view.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/editor_min_line_item_height"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/display_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="4dp"
+ android:layout_marginBottom="6dp"
+ android:singleLine="true"
+ android:textSize="@dimen/editor_form_text_size"
+ android:textColor="?android:attr/textColorSecondary"
+ android:enabled="false"/>
+
+ <include layout="@layout/account_type_info"
+ android:layout_marginStart="12dp" />
+
+</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d992e81..020b999 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -768,6 +768,9 @@
<!-- Content description for the compact contact editor photo overlay which, when clicked, shows a dialog with the options for changing the contact photo. [CHAR LIMIT=30] -->
<string name="compact_editor_change_photo_content_description">Change photo</string>
+ <!-- Toast message displayed when the editor fails to load for a contacts. [CHAR LIMIT=NONE] -->
+ <string name="compact_editor_failed_to_load">Failed to open editor.</string>
+
<!-- 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>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 66ddac6..14dfee2 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -329,7 +329,7 @@
<style name="AccountTypeIconStyle">
<item name="android:layout_width">12dp</item>
<item name="android:layout_height">12dp</item>
- <item name="android:layout_marginStart">2dp</item>
+ <item name="android:layout_marginStart">4dp</item>
<item name="android:layout_marginEnd">4dp</item>
</style>
diff --git a/src/com/android/contacts/activities/ContactEditorBaseActivity.java b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
index 18ff30f..a86196b 100644
--- a/src/com/android/contacts/activities/ContactEditorBaseActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
@@ -273,7 +273,7 @@
@Override
public void onBackPressed() {
if (mFragment != null) {
- mFragment.save(ContactEditor.SaveMode.CLOSE);
+ mFragment.revert();
}
}
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 49d02a8..26add9d 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -1017,8 +1017,7 @@
@Override
public void onImportContactsFromFileAction() {
- ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
- PeopleActivity.class);
+ showImportExportDialogFragment();
}
}
@@ -1195,8 +1194,7 @@
deleteSelectedContacts();
return true;
case R.id.menu_import_export: {
- ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
- PeopleActivity.class);
+ showImportExportDialogFragment();
return true;
}
case R.id.menu_clear_frequents: {
@@ -1225,6 +1223,17 @@
return false;
}
+ private void showImportExportDialogFragment(){
+ final boolean isOnFavoriteTab = mTabPagerAdapter.mCurrentPrimaryItem == mFavoritesFragment;
+ if (isOnFavoriteTab) {
+ ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
+ PeopleActivity.class, ImportExportDialogFragment.EXPORT_MODE_FAVORITES);
+ } else {
+ ImportExportDialogFragment.show(getFragmentManager(), areContactsAvailable(),
+ PeopleActivity.class, ImportExportDialogFragment.EXPORT_MODE_ALL_CONTACTS);
+ }
+ }
+
@Override
public boolean onSearchRequested() { // Search key pressed.
if (!mActionBarAdapter.isSelectionMode()) {
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index d5209cb..e98a8de 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -40,6 +40,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
+import android.widget.Toast;
import java.io.FileNotFoundException;
@@ -353,6 +354,17 @@
rebindEditorsForNewContact(oldState, oldAccount, newAccount);
}
+ @Override
+ public void onBindEditorsFailed() {
+ final Activity activity = getActivity();
+ if (activity != null && !activity.isFinishing()) {
+ Toast.makeText(activity, R.string.compact_editor_failed_to_load,
+ Toast.LENGTH_SHORT).show();
+ activity.setResult(Activity.RESULT_CANCELED);
+ activity.finish();
+ }
+ }
+
private CompactRawContactsEditorView getContent() {
return (CompactRawContactsEditorView) mContent;
}
diff --git a/src/com/android/contacts/editor/CompactKindSectionView.java b/src/com/android/contacts/editor/CompactKindSectionView.java
index 25712d0..a5f159c 100644
--- a/src/com/android/contacts/editor/CompactKindSectionView.java
+++ b/src/com/android/contacts/editor/CompactKindSectionView.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
-import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@@ -27,6 +26,7 @@
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.TextView;
import com.android.contacts.R;
import com.android.contacts.common.model.RawContactDelta;
@@ -34,7 +34,6 @@
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.dataitem.DataKind;
-import com.android.contacts.editor.Editor.EditorListener;
import java.util.ArrayList;
import java.util.List;
@@ -42,25 +41,21 @@
/**
* Version of {@link KindSectionView} that supports multiple RawContactDeltas.
*/
-public class CompactKindSectionView extends LinearLayout implements EditorListener {
+public class CompactKindSectionView extends LinearLayout {
/**
* 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.
+ * marked as super primary.
*/
- private static final class NameEditorListener implements Editor.EditorListener {
+ private static final class StructuredNameEditorListener implements Editor.EditorListener {
private final ValuesDelta mValuesDelta;
private final long mRawContactId;
private final CompactRawContactsEditorView.Listener mListener;
- public NameEditorListener(ValuesDelta valuesDelta, long rawContactId,
+ public StructuredNameEditorListener(ValuesDelta valuesDelta, long rawContactId,
CompactRawContactsEditorView.Listener listener) {
mValuesDelta = valuesDelta;
mRawContactId = rawContactId;
@@ -85,7 +80,11 @@
}
}
- private static final class NicknameEditorListener implements Editor.EditorListener {
+ /**
+ * Clears fields when deletes are requested (on phonetic and nickename fields);
+ * does not change the number of editors.
+ */
+ private static final class OtherNameKindEditorListener implements Editor.EditorListener {
@Override
public void onRequest(int request) {
@@ -97,16 +96,42 @@
}
}
+ /**
+ * Updates empty fields when fields are deleted or turns empty.
+ * Whether a new empty editor is added is controlled by {@link #setShowOneEmptyEditor} and
+ * {@link #setHideWhenEmpty}.
+ */
+ private final class NonNameEditorListener implements Editor.EditorListener {
+
+ @Override
+ public void onRequest(int request) {
+ // If a field has become empty or non-empty, then check if another row
+ // can be added dynamically.
+ if (request == FIELD_TURNED_EMPTY || request == FIELD_TURNED_NON_EMPTY) {
+ updateEmptyEditors(/* shouldAnimate = */ true);
+ }
+ }
+
+ @Override
+ public void onDeleteRequested(Editor editor) {
+ if (mShowOneEmptyEditor && mEditors.getChildCount() == 1) {
+ // If there is only 1 editor in the section, then don't allow the user to
+ // delete it. Just clear the fields in the editor.
+ editor.clearAllFields();
+ } else {
+ editor.deleteEditor();
+ }
+ }
+ }
+
private List<KindSectionData> mKindSectionDataList;
- private boolean mReadOnly;
private ViewIdGenerator mViewIdGenerator;
private CompactRawContactsEditorView.Listener mListener;
- private String mMimeType;
private boolean mShowOneEmptyEditor = false;
private boolean mHideIfEmpty = true;
- private LayoutInflater mInflater;
+ private LayoutInflater mLayoutInflater;
private ViewGroup mEditors;
private ImageView mIcon;
@@ -129,42 +154,22 @@
}
}
- /** {@inheritDoc} */
@Override
protected void onFinishInflate() {
setDrawingCacheEnabled(true);
setAlwaysDrawnWithCacheEnabled(true);
- mInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mLayoutInflater = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
mEditors = (ViewGroup) findViewById(R.id.kind_editors);
mIcon = (ImageView) findViewById(R.id.kind_icon);
}
- @Override
- public void onDeleteRequested(Editor editor) {
- if (mShowOneEmptyEditor && getEditorCount() == 1) {
- // If there is only 1 editor in the section, then don't allow the user to delete it.
- // Just clear the fields in the editor.
- editor.clearAllFields();
- } else {
- editor.deleteEditor();
- }
- }
-
- @Override
- public void onRequest(int request) {
- // If a field has become empty or non-empty, then check if another row
- // can be added dynamically.
- if (request == FIELD_TURNED_EMPTY || request == FIELD_TURNED_NON_EMPTY) {
- updateEmptyEditors(/* shouldAnimate = */ true);
- }
- }
-
/**
* @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.
+ * editor will not be shown until the user enters a value. Note, this does not apply
+ * to name editors since those are always displayed.
*/
public void setShowOneEmptyEditor(boolean showOneEmptyEditor) {
mShowOneEmptyEditor = showOneEmptyEditor;
@@ -172,13 +177,14 @@
/**
* @param hideWhenEmpty If true, the entire section will be hidden if all inputs are empty,
- * otherwise one empty input will always be displayed. Note, this has no effect
- * on name editors since the policy is to always show names.
+ * otherwise one empty input will always be displayed. Note, this does not apply
+ * to name editors since those are always displayed.
*/
public void setHideWhenEmpty(boolean hideWhenEmpty) {
mHideIfEmpty = hideWhenEmpty;
}
+ /** Binds the given group data to every {@link GroupMembershipView}. */
public void setGroupMetaData(Cursor cursor) {
for (int i = 0; i < mEditors.getChildCount(); i++) {
final View view = mEditors.getChildAt(i);
@@ -188,32 +194,39 @@
}
}
- public void setState(List<KindSectionData> kindSectionDataList, boolean readOnly,
+ /**
+ * Binds views for the given {@link KindSectionData} list.
+ *
+ * We create a structured name and phonetic name editor for each {@link DataKind} with a
+ * {@link }StructuredName#CONTENT_ITEM_TYPE} mime type. The number and order of editors are
+ * rendered as they are given to {@link #setState}.
+ *
+ * Empty name editors are never added and at least one structured name editor is always
+ * displayed, even if it is empty.
+ */
+ public void setState(List<KindSectionData> kindSectionDataList,
ViewIdGenerator viewIdGenerator, CompactRawContactsEditorView.Listener listener) {
mKindSectionDataList = kindSectionDataList;
- mReadOnly = readOnly;
mViewIdGenerator = viewIdGenerator;
mListener = listener;
- // Set the icon using the first DataKind (all DataKinds should be the same type)
+ // Set the icon using the first DataKind
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));
mIcon.setImageDrawable(EditorUiUtils.getMimeTypeDrawable(getContext(),
dataKind.mimeType));
- if (mIcon.getDrawable() == null) mIcon.setContentDescription(null);
- mMimeType = dataKind.mimeType;
+ if (mIcon.getDrawable() != null) {
+ mIcon.setContentDescription(dataKind.titleRes == -1 || dataKind.titleRes == 0
+ ? "" : getResources().getString(dataKind.titleRes));
+ }
}
rebuildFromState();
+
updateEmptyEditors(/* shouldAnimate = */ false);
}
- /**
- * Build editors for all current rows.
- */
private void rebuildFromState() {
mEditors.removeAllViews();
@@ -221,45 +234,67 @@
final String mimeType = kindSectionData.getDataKind().mimeType;
if (StructuredName.CONTENT_ITEM_TYPE.equals(mimeType)) {
for (ValuesDelta valuesDelta : kindSectionData.getValuesDeltas()) {
- createNameEditorViews(kindSectionData.getAccountType(),
+ addNameEditorViews(kindSectionData.getAccountType(),
valuesDelta, kindSectionData.getRawContactDelta());
}
} else if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
- createGroupEditorView(kindSectionData.getRawContactDelta(),
+ addGroupEditorView(kindSectionData.getRawContactDelta(),
kindSectionData.getDataKind());
} else {
+ final Editor.EditorListener editorListener = kindSectionData.isNicknameDataKind()
+ ? new OtherNameKindEditorListener() : new NonNameEditorListener();
for (ValuesDelta valuesDelta : kindSectionData.getValuesDeltas()) {
- createEditorView(kindSectionData.getRawContactDelta(),
- kindSectionData.getDataKind(), valuesDelta);
+ addNonNameEditorView(kindSectionData.getRawContactDelta(),
+ kindSectionData.getDataKind(), valuesDelta, editorListener);
}
}
}
}
- private void createNameEditorViews(AccountType accountType,
+ private void addNameEditorViews(AccountType accountType,
ValuesDelta valuesDelta, RawContactDelta rawContactDelta) {
final boolean readOnly = !accountType.areContactsWritable();
+ if (readOnly) {
+ final View nameView = mLayoutInflater.inflate(
+ R.layout.structured_name_readonly_editor_view, mEditors,
+ /* attachToRoot =*/ false);
+
+ // Display name
+ ((TextView) nameView.findViewById(R.id.display_name))
+ .setText(valuesDelta.getDisplayName());
+
+ // Account type info
+ final LinearLayout accountTypeLayout = (LinearLayout)
+ nameView.findViewById(R.id.account_type);
+ accountTypeLayout.setVisibility(View.VISIBLE);
+ ((ImageView) accountTypeLayout.findViewById(R.id.account_type_icon))
+ .setImageDrawable(accountType.getDisplayIcon(getContext()));
+ ((TextView) accountTypeLayout.findViewById(R.id.account_type_name))
+ .setText(accountType.getDisplayLabel(getContext()));
+
+ mEditors.addView(nameView);
+ return;
+ }
+
// Structured name
- final StructuredNameEditorView nameView = (StructuredNameEditorView) mInflater.inflate(
- R.layout.structured_name_editor_view, mEditors, /* attachToRoot =*/ false);
- nameView.setEditorListener(new NameEditorListener(valuesDelta,
+ final StructuredNameEditorView nameView = (StructuredNameEditorView) mLayoutInflater
+ .inflate(R.layout.structured_name_editor_view, mEditors, /* attachToRoot =*/ false);
+ nameView.setEditorListener(new StructuredNameEditorListener(valuesDelta,
rawContactDelta.getRawContactId(), mListener));
nameView.setDeletable(false);
nameView.setValues(
accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_DISPLAY_NAME),
valuesDelta, rawContactDelta, readOnly, mViewIdGenerator);
- if (readOnly) nameView.setAccountType(accountType);
- // Correct start margin since there is another icon in the structured name layout
+ // Correct start margin since there is a second 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);
+ final PhoneticNameEditorView phoneticNameView = (PhoneticNameEditorView) mLayoutInflater
+ .inflate(R.layout.phonetic_name_editor_view, mEditors, /* attachToRoot =*/ false);
+ phoneticNameView.setEditorListener(new OtherNameKindEditorListener());
phoneticNameView.setDeletable(false);
phoneticNameView.setValues(
accountType.getKindForMimetype(DataKind.PSEUDO_MIME_TYPE_PHONETIC_NAME),
@@ -273,57 +308,40 @@
mEditors.addView(phoneticNameView);
}
- private void createGroupEditorView(RawContactDelta rawContactDelta, DataKind dataKind) {
- final GroupMembershipView view = (GroupMembershipView) mInflater.inflate(
+ private void addGroupEditorView(RawContactDelta rawContactDelta, DataKind dataKind) {
+ final GroupMembershipView view = (GroupMembershipView) mLayoutInflater.inflate(
R.layout.item_group_membership, mEditors, /* attachToRoot =*/ false);
view.setKind(dataKind);
view.setEnabled(isEnabled());
view.setState(rawContactDelta);
- // Correct start margin since there is another icon in the group layout
+ // Correct start margin since there is a second icon in the group layout
view.findViewById(R.id.kind_icon).setVisibility(View.GONE);
mEditors.addView(view);
}
- /**
- * Creates an EditorView for the given values delta. This function must be used while
- * constructing the views corresponding to the the object-model. The resulting EditorView is
- * also added to the end of mEditors
- */
- private View createEditorView(RawContactDelta rawContactDelta, DataKind dataKind,
- ValuesDelta valuesDelta) {
+ private View addNonNameEditorView(RawContactDelta rawContactDelta, DataKind dataKind,
+ ValuesDelta valuesDelta, Editor.EditorListener editorListener) {
// Inflate the layout
- final View view;
- final int layoutResId = EditorUiUtils.getLayoutResourceId(dataKind.mimeType);
- try {
- view = mInflater.inflate(layoutResId, mEditors, false);
- } catch (Exception e) {
- throw new RuntimeException("Failed to allocate editor with layout resource ID " +
- layoutResId + " for mime type " + dataKind.mimeType + ": " + e.toString());
- }
+ final View view = mLayoutInflater.inflate(
+ EditorUiUtils.getLayoutResourceId(dataKind.mimeType), mEditors, false);
+ view.setEnabled(isEnabled());
// Hide the types drop downs until the associated edit field is focused
if (view instanceof LabeledEditorView) {
((LabeledEditorView) view).setHideTypeInitially(true);
}
- // Set whether the editor is enabled
- view.setEnabled(isEnabled());
-
if (view instanceof Editor) {
final Editor editor = (Editor) view;
editor.setDeletable(true);
- // 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.setEditorListener(editorListener);
editor.setValues(dataKind, valuesDelta, rawContactDelta, !dataKind.editable,
mViewIdGenerator);
}
mEditors.addView(view);
+
return view;
}
@@ -334,9 +352,43 @@
* then the entire section is hidden.
*/
public void updateEmptyEditors(boolean shouldAnimate) {
- if (mKindSectionDataList.get(0).isNameDataKind()) {
+ final boolean isNameKindSection = mKindSectionDataList.get(0).isNameDataKind();
+ final boolean isGroupKindSection = GroupMembership.CONTENT_ITEM_TYPE.equals(
+ mKindSectionDataList.get(0).getDataKind().mimeType);
+
+ if (isNameKindSection) {
+ // The name kind section is always visible
+ setVisibility(VISIBLE);
+
updateEmptyNameEditors(shouldAnimate);
+ } else if (isGroupKindSection) {
+ // Check whether metadata has been bound for all group views
+ for (int i = 0; i < mEditors.getChildCount(); i++) {
+ final View view = mEditors.getChildAt(i);
+ if (view instanceof GroupMembershipView
+ && !((GroupMembershipView) view).wasGroupMetaDataBound()) {
+ setVisibility(GONE);
+ return;
+ }
+ }
+ // Check that the user has selected to display all fields
+ if (mHideIfEmpty) {
+ setVisibility(GONE);
+ return;
+ }
+ setVisibility(VISIBLE);
+
+ // We don't check the emptiness of the group views
} else {
+ // Determine if the entire kind section should be visible
+ final int editorCount = mEditors.getChildCount();
+ final List<View> emptyEditors = getEmptyEditors();
+ if (editorCount == emptyEditors.size() && mHideIfEmpty) {
+ setVisibility(GONE);
+ return;
+ }
+ setVisibility(VISIBLE);
+
updateEmptyNonNameEditors(shouldAnimate);
}
}
@@ -346,6 +398,7 @@
for (int i = 0; i < mEditors.getChildCount(); i++) {
final View view = mEditors.getChildAt(i);
+ if (!(view instanceof Editor)) continue; // Skip read-only names
final Editor editor = (Editor) view;
if (view instanceof StructuredNameEditorView) {
// We always show one empty structured name view
@@ -365,25 +418,17 @@
} else {
// For phonetic names and nicknames, which can't be added, just show or hide them
if (mHideIfEmpty && editor.isEmpty()) {
- hideView(view, shouldAnimate);
+ hideView(view);
} else {
- showView(view, shouldAnimate);
+ showView(view, /* shouldAnimate =*/ false); // Animation here causes jank
}
}
}
}
private void updateEmptyNonNameEditors(boolean shouldAnimate) {
- // Update whether the entire section is visible or not
- final int editorCount = getEditorCount();
- final List<View> emptyEditors = getEmptyEditors();
- if (editorCount == emptyEditors.size() && mHideIfEmpty) {
- setVisibility(GONE);
- return;
- }
- setVisibility(VISIBLE);
-
// Prune excess empty editors
+ final List<View> emptyEditors = getEmptyEditors();
if (emptyEditors.size() > 1) {
// If there is more than 1 empty editor, then remove it from the list of editors.
int deleted = 0;
@@ -403,29 +448,27 @@
}
// 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.
+ if (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)
+ || (dataKind.typeOverallMax == mEditors.getChildCount()
+ && dataKind.typeOverallMax != 0)
// We have already reached the maximum number of empty editors, don't add any more.
|| emptyEditors.size() == 1) {
return;
}
// Add a new empty editor
if (mShowOneEmptyEditor) {
- final RawContactDelta rawContactDelta = mKindSectionDataList.get(0).getRawContactDelta();
+ final RawContactDelta rawContactDelta =
+ mKindSectionDataList.get(0).getRawContactDelta();
final ValuesDelta values = RawContactModifier.insertChild(rawContactDelta, dataKind);
- final View view = createEditorView(rawContactDelta, dataKind, values);
+ final View view = addNonNameEditorView(rawContactDelta, dataKind, values,
+ new NonNameEditorListener());
showView(view, shouldAnimate);
}
}
- private void hideView(View view, boolean shouldAnimate) {
- if (shouldAnimate) {
- EditorAnimator.getInstance().hideEditorView(view);
- } else {
- view.setVisibility(View.GONE);
- }
+ private void hideView(View view) {
+ view.setVisibility(View.GONE);
}
private void deleteView(View view, boolean shouldAnimate) {
@@ -440,35 +483,20 @@
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);
}
}
- /**
- * Returns a list of empty editor views in this section.
- */
private List<View> getEmptyEditors() {
- List<View> emptyEditorViews = new ArrayList<View>();
+ final List<View> emptyEditors = new ArrayList<>();
for (int i = 0; i < mEditors.getChildCount(); i++) {
final View view = mEditors.getChildAt(i);
if (view instanceof Editor && ((Editor) view).isEmpty()) {
- emptyEditorViews.add(view);
+ emptyEditors.add(view);
}
}
- return emptyEditorViews;
- }
-
- private int getEditorCount() {
- return mEditors.getChildCount();
- }
-
- /**
- * Returns the mime type the kind being edited in this section.
- */
- public String getMimeType() {
- return mMimeType;
+ return emptyEditors;
}
}
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 8ca6389..9d81276 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -34,6 +34,8 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -102,6 +104,11 @@
*/
public void onRebindEditorsForNewContact(RawContactDelta oldState,
AccountWithDataSet oldAccount, AccountWithDataSet newAccount);
+
+ /**
+ * Invoked when no editors could be bound for the contact.
+ */
+ public void onBindEditorsFailed();
}
/** Used to sort entire kind sections. */
@@ -130,7 +137,7 @@
* <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>
- * <li>Group membership is palced at the end</li>
+ * <li>Group membership is placed at the end</li>
* </ol>
*/
private static final class MimeTypeComparator implements Comparator<String> {
@@ -138,13 +145,13 @@
private static final List<String> MIME_TYPE_ORDER = Arrays.asList(new String[] {
StructuredName.CONTENT_ITEM_TYPE,
Nickname.CONTENT_ITEM_TYPE,
+ Organization.CONTENT_ITEM_TYPE,
Phone.CONTENT_ITEM_TYPE,
SipAddress.CONTENT_ITEM_TYPE,
Email.CONTENT_ITEM_TYPE,
StructuredPostal.CONTENT_ITEM_TYPE,
Im.CONTENT_ITEM_TYPE,
Website.CONTENT_ITEM_TYPE,
- Organization.CONTENT_ITEM_TYPE,
Event.CONTENT_ITEM_TYPE,
Relation.CONTENT_ITEM_TYPE,
Note.CONTENT_ITEM_TYPE,
@@ -240,13 +247,43 @@
}
// The primary account name should be before all others
- if (isRawContactDelta1Primary) return 1;
- if (isRawContactDelta2Primary) return -1;
+ if (isRawContactDelta1Primary) return -1;
+ if (isRawContactDelta2Primary) return 1;
return mRawContactDeltaComparator.compare(rawContactDelta1, rawContactDelta2);
}
}
+ public static class SavedState extends BaseSavedState {
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+
+ private boolean mIsExpanded;
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ private SavedState(Parcel in) {
+ super(in);
+ mIsExpanded = in.readInt() != 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ super.writeToParcel(out, flags);
+ out.writeInt(mIsExpanded ? 1 : 0);
+ }
+ }
+
private CompactRawContactsEditorView.Listener mListener;
private AccountTypeManager mAccountTypeManager;
@@ -277,6 +314,7 @@
private Map<String,List<CompactKindSectionView>> mKindSectionViewsMap = new HashMap<>();
private View mMoreFields;
+ private boolean mIsExpanded;
private long mPhotoRawContactId;
public CompactRawContactsEditorView(Context context) {
@@ -322,19 +360,7 @@
@Override
public void onClick(View view) {
if (view.getId() == R.id.more_fields) {
- // Stop hiding empty editors and allow the user to enter values for all kinds now
- for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
- final CompactKindSectionView kindSectionView =
- (CompactKindSectionView) mKindSectionViews.getChildAt(i);
- kindSectionView.setHideWhenEmpty(false);
- // 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);
- }
-
+ showMoreFields();
updateMoreFieldsButton();
}
}
@@ -348,6 +374,28 @@
}
}
+ @Override
+ public Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ final SavedState savedState = new SavedState(superState);
+ savedState.mIsExpanded = mIsExpanded;
+ return savedState;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ if(!(state instanceof SavedState)) {
+ super.onRestoreInstanceState(state);
+ return;
+ }
+ final SavedState savedState = (SavedState) state;
+ super.onRestoreInstanceState(savedState.getSuperState());
+ mIsExpanded = savedState.mIsExpanded;
+ if (mIsExpanded && !mKindSectionDataMap.isEmpty()) {
+ showMoreFields();
+ }
+ }
+
/**
* Pass through to {@link CompactPhotoEditorView#setPhotoHandler}.
*/
@@ -398,6 +446,12 @@
for (CompactKindSectionView kindSectionView : kindSectionViews) {
kindSectionView.setGroupMetaData(groupMetaData);
}
+
+ // Groups metadata may be set after we restore expansion state so just do it again
+ if (mIsExpanded) {
+ showMoreFields();
+ }
+ updateMoreFieldsButton();
}
public void setState(RawContactDeltaList rawContactDeltas,
@@ -423,11 +477,13 @@
// Parse the given raw contact deltas
if (rawContactDeltas == null || rawContactDeltas.isEmpty()) {
elog("No raw contact deltas");
+ if (mListener != null) mListener.onBindEditorsFailed();
return;
}
parseRawContactDeltas(rawContactDeltas, mPrimaryAccount);
- if (mKindSectionDataMap == null || mKindSectionDataMap.isEmpty()) {
+ if (mKindSectionDataMap.isEmpty()) {
elog("No kind section data parsed from RawContactDelta(s)");
+ if (mListener != null) mListener.onBindEditorsFailed();
return;
}
@@ -437,6 +493,7 @@
addAccountInfo();
addPhotoView();
addKindSectionViews();
+
updateMoreFieldsButton();
}
@@ -509,10 +566,9 @@
new KindSectionData(accountType, dataKind, rawContactDelta);
kindSectionDataList.add(kindSectionData);
- // Note we must create a nickname entry on inserts
+ // Note we must create nickname entries
if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)
- && kindSectionData.getValuesDeltas().isEmpty()
- && mHasNewContact) {
+ && kindSectionData.getValuesDeltas().isEmpty()) {
RawContactModifier.insertChild(rawContactDelta, dataKind);
}
@@ -659,10 +715,6 @@
private Pair<KindSectionData,ValuesDelta> getPrimaryKindSectionData(long id) {
final String mimeType = Photo.CONTENT_ITEM_TYPE;
final List<KindSectionData> kindSectionDataList = mKindSectionDataMap.get(mimeType);
- if (kindSectionDataList == null || kindSectionDataList.isEmpty()) {
- wlog("photo: no kind section data parsed");
- return null;
- }
KindSectionData resultKindSectionData = null;
ValuesDelta resultValuesDelta = null;
@@ -779,12 +831,22 @@
Collections.sort(kindSectionDataList, new EditorComparator(getContext()));
}
- kindSectionView.setState(kindSectionDataList, /* readOnly =*/ false, mViewIdGenerator,
- mListener);
+ kindSectionView.setState(kindSectionDataList, mViewIdGenerator, mListener);
return kindSectionView;
}
+ private void showMoreFields() {
+ // Stop hiding empty editors and allow the user to enter values for all kinds now
+ for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
+ final CompactKindSectionView kindSectionView =
+ (CompactKindSectionView) mKindSectionViews.getChildAt(i);
+ kindSectionView.setHideWhenEmpty(false);
+ kindSectionView.updateEmptyEditors(/* shouldAnimate =*/ true);
+ }
+ mIsExpanded = true;
+ }
+
private void updateMoreFieldsButton() {
// If any kind section views are hidden then show the link
for (int i = 0; i < mKindSectionViews.getChildCount(); i++) {
diff --git a/src/com/android/contacts/editor/EditorIntents.java b/src/com/android/contacts/editor/EditorIntents.java
index ca8d5ae..26279df 100644
--- a/src/com/android/contacts/editor/EditorIntents.java
+++ b/src/com/android/contacts/editor/EditorIntents.java
@@ -110,7 +110,6 @@
* Returns an Intent to start the fully expanded {@link ContactEditorActivity} for a
* new contact.
*/
- // TODO: Delete this if we don't need it to load the full editor for read only accounts
public static Intent createInsertContactIntent(RawContactDeltaList rawContactDeltaList,
String displayName, String phoneticName, boolean isNewLocalProfile) {
final Intent intent = new Intent(ContactEditorBaseActivity.ACTION_INSERT,
diff --git a/src/com/android/contacts/editor/GroupMembershipView.java b/src/com/android/contacts/editor/GroupMembershipView.java
index f1d9db9..b13da62 100644
--- a/src/com/android/contacts/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/editor/GroupMembershipView.java
@@ -202,6 +202,11 @@
}
}
+ /** Whether {@link #setGroupMetaData} has been invoked yet. */
+ public boolean wasGroupMetaDataBound() {
+ return mGroupMetaData != null;
+ }
+
public void setState(RawContactDelta state) {
mState = state;
mAccountType = mState.getAccountType();
diff --git a/src/com/android/contacts/editor/KindSectionData.java b/src/com/android/contacts/editor/KindSectionData.java
index 7b383fb..d46001a 100644
--- a/src/com/android/contacts/editor/KindSectionData.java
+++ b/src/com/android/contacts/editor/KindSectionData.java
@@ -98,8 +98,11 @@
}
public boolean isNameDataKind() {
- return StructuredName.CONTENT_ITEM_TYPE.equals(mDataKind.mimeType)
- || Nickname.CONTENT_ITEM_TYPE.equals(mDataKind.mimeType);
+ return StructuredName.CONTENT_ITEM_TYPE.equals(mDataKind.mimeType);
+ }
+
+ public boolean isNicknameDataKind() {
+ return Nickname.CONTENT_ITEM_TYPE.equals(mDataKind.mimeType);
}
public RawContactDelta getRawContactDelta() {
diff --git a/src/com/android/contacts/editor/LabeledEditorView.java b/src/com/android/contacts/editor/LabeledEditorView.java
index 931d7cf..244b682 100644
--- a/src/com/android/contacts/editor/LabeledEditorView.java
+++ b/src/com/android/contacts/editor/LabeledEditorView.java
@@ -378,6 +378,9 @@
if (mIsDeletable) mDeleteContainer.setVisibility(View.VISIBLE);
}
mWasEmpty = isEmpty;
+
+ // Update the label text color
+ mEditTypeAdapter.notifyDataSetChanged();
}
}