Merge "Move "Linked contacts" and "Saving to" text in editor." into ub-contactsdialer-a-dev
diff --git a/res/menu/edit_contact.xml b/res/menu/edit_contact.xml
index 2ff5f81..256edb6 100644
--- a/res/menu/edit_contact.xml
+++ b/res/menu/edit_contact.xml
@@ -30,11 +30,6 @@
android:title="@string/menu_joinAggregate" />
<item
- android:id="@+id/menu_discard"
- android:alphabeticShortcut="q"
- android:title="@string/menu_discard" />
-
- <item
android:id="@+id/menu_delete"
android:title="@string/menu_deleteContact" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7a51cb5..3f721b3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -207,9 +207,6 @@
<!-- Confirmation dialog contents after users selects to delete a Writable contact. -->
<string name="deleteConfirmation">This contact will be deleted.</string>
- <!-- Menu item to indicate you want to stop editing a contact and NOT save the changes you've made [CHAR LIMIT=30] -->
- <string name="menu_discard">Discard changes</string>
-
<!-- Message displayed in a toast when you try to view the details of a contact that
for some reason doesn't exist anymore. [CHAR LIMIT=NONE]-->
<string name="invalidContactMessage">The contact doesn\'t exist.</string>
@@ -278,6 +275,15 @@
<!-- Toast displayed when saving a contact failed. [CHAR LIMIT=NONE] -->
<string name="contactSavedErrorToast">Couldn\'t save contact changes.</string>
+ <!-- Toast displayed when unlinking a contact failed. [CHAR LIMIT=NONE] -->
+ <string name="contactUnlinkErrorToast">Couldn\'t unlink contact.</string>
+
+ <!-- Toast displayed when joining a contact failed. [CHAR LIMIT=NONE] -->
+ <string name="contactJoinErrorToast">Couldn\'t join contact.</string>
+
+ <!-- Generic error default clause displayed when saving a contact failed. [CHAR LIMIT=NONE] -->
+ <string name="contactGenericErrorToast">Error saving contact.</string>
+
<!-- Toast displayed when saving a contact photo failed. [CHAR LIMIT=NONE] -->
<string name="contactPhotoSavedErrorToast">Couldn\'t save contact photo changes.</string>
diff --git a/src/com/android/contacts/editor/AggregationSuggestionEngine.java b/src/com/android/contacts/editor/AggregationSuggestionEngine.java
index 14da019..4423a61 100644
--- a/src/com/android/contacts/editor/AggregationSuggestionEngine.java
+++ b/src/com/android/contacts/editor/AggregationSuggestionEngine.java
@@ -25,6 +25,7 @@
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;
+import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Nickname;
import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -115,6 +116,7 @@
private ContentObserver mContentObserver;
private Uri mSuggestionsUri;
private int mSuggestionsLimit = 3;
+ private boolean mPruneInvisibleContacts;
public AggregationSuggestionEngine(Context context) {
super("AggregationSuggestions", Process.THREAD_PRIORITY_BACKGROUND);
@@ -150,6 +152,10 @@
mSuggestionsLimit = suggestionsLimit;
}
+ public void setPruneInvisibleContacts (boolean pruneInvisibleContacts) {
+ mPruneInvisibleContacts = pruneInvisibleContacts;
+ }
+
public void setListener(Listener listener) {
mListener = listener;
}
@@ -377,6 +383,27 @@
}
public List<Suggestion> getSuggestions() {
+ final ArrayList<Long> visibleContacts = new ArrayList<>();
+ if (mPruneInvisibleContacts) {
+ final Uri contactFilterUri = Data.CONTENT_URI.buildUpon()
+ .appendQueryParameter(Data.VISIBLE_CONTACTS_ONLY, "true")
+ .build();
+ final ContentResolver contentResolver = mContext.getContentResolver();
+ final Cursor contactCursor = contentResolver.query(contactFilterUri,
+ new String[]{Data.CONTACT_ID}, null, null, null);
+ try {
+ if (contactCursor != null) {
+ while (contactCursor.moveToNext()) {
+ final long contactId = contactCursor.getLong(0);
+ visibleContacts.add(contactId);
+ }
+ }
+ } finally {
+ contactCursor.close();
+ }
+
+ }
+
ArrayList<Suggestion> list = Lists.newArrayList();
if (mDataCursor != null) {
Suggestion suggestion = null;
@@ -384,6 +411,9 @@
mDataCursor.moveToPosition(-1);
while (mDataCursor.moveToNext()) {
long contactId = mDataCursor.getLong(DataQuery.CONTACT_ID);
+ if (mPruneInvisibleContacts && !visibleContacts.contains(contactId)) {
+ continue;
+ }
if (contactId != currentContactId) {
suggestion = new Suggestion();
suggestion.contactId = contactId;
diff --git a/src/com/android/contacts/editor/CompactContactEditorFragment.java b/src/com/android/contacts/editor/CompactContactEditorFragment.java
index 0ca8d35..9698ada 100644
--- a/src/com/android/contacts/editor/CompactContactEditorFragment.java
+++ b/src/com/android/contacts/editor/CompactContactEditorFragment.java
@@ -19,6 +19,7 @@
import com.android.contacts.ContactSaveService;
import com.android.contacts.R;
import com.android.contacts.activities.CompactContactEditorActivity;
+import com.android.contacts.activities.ContactEditorBaseActivity;
import com.android.contacts.common.model.RawContactDelta;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountWithDataSet;
@@ -161,8 +162,27 @@
SAVE_MODE_EXTRA_KEY, saveMode, isEditingUserProfile(),
((Activity) mContext).getClass(),
CompactContactEditorActivity.ACTION_SAVE_COMPLETED, mUpdatedPhotos);
- mContext.startService(intent);
-
+ try {
+ mContext.startService(intent);
+ } catch (Exception exception) {
+ final int resId;
+ switch (saveMode) {
+ case ContactEditorBaseActivity.ContactEditor.SaveMode.SPLIT:
+ resId = R.string.contactUnlinkErrorToast;
+ break;
+ case ContactEditorBaseActivity.ContactEditor.SaveMode.RELOAD:
+ resId = R.string.contactJoinErrorToast;
+ break;
+ case ContactEditorBaseActivity.ContactEditor.SaveMode.CLOSE:
+ resId = R.string.contactSavedErrorToast;
+ break;
+ default:
+ resId = R.string.contactGenericErrorToast;
+ }
+ Toast.makeText(mContext, resId, Toast.LENGTH_SHORT).show();
+ onCancelEditConfirmed();
+ return false;
+ }
return true;
}
@@ -229,7 +249,7 @@
@Override
public void onPhotoEditorViewClicked() {
- if (isMultiAccountContact()) {
+ if (isEditingMultipleRawContacts()) {
final ArrayList<CompactPhotoSelectionFragment.Photo> photos = getContent().getPhotos();
if (photos.size() > 1) {
// For aggregate contacts, the user may select a new super primary photo from among
@@ -260,7 +280,7 @@
private int getPhotoMode() {
if (getContent().isWritablePhotoSet()) {
- return isMultiAccountContact()
+ return isEditingMultipleRawContacts()
? PhotoActionPopup.Modes.MULTIPLE_WRITE_ABLE_PHOTOS
: PhotoActionPopup.Modes.WRITE_ABLE_PHOTO;
}
diff --git a/src/com/android/contacts/editor/CompactRawContactsEditorView.java b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
index 1b2f60b..8a4d479 100644
--- a/src/com/android/contacts/editor/CompactRawContactsEditorView.java
+++ b/src/com/android/contacts/editor/CompactRawContactsEditorView.java
@@ -143,7 +143,7 @@
mContext = context;
mRawContactDeltas = new RawContactDeltaList();
for (RawContactDelta rawContactDelta : rawContactDeltas) {
- if (rawContactDelta.isVisible()) {
+ if (rawContactDelta.isVisible() && rawContactDelta.getRawContactId() > 0) {
mRawContactDeltas.add(rawContactDelta);
}
}
@@ -749,7 +749,7 @@
rawContactDelta.getAccountName(),
rawContactDelta.getAccountType(mAccountTypeManager));
- // Only one of the account header, selector, and raw contact selector should be shown
+ // Either the account header or selector should be shown, not both.
final List<AccountWithDataSet> accounts =
AccountTypeManager.getInstance(getContext()).getAccounts(true);
if (mHasNewContact && !mIsUserProfile) {
@@ -758,11 +758,21 @@
} else {
addAccountHeader(accountInfo);
}
- } else if (rawContactDeltas.size() > 1) {
- addRawContactAccountSelector(rawContactDeltas);
} else {
addAccountHeader(accountInfo);
}
+
+ // The raw contact selector should only display linked raw contacts that can be edited in
+ // the full editor (i.e. they are not newly created raw contacts)
+ Collections.sort(rawContactDeltas, new RawContactDeltaComparator(getContext()));
+ final RawContactAccountListAdapter adapter =
+ new RawContactAccountListAdapter(getContext(), rawContactDeltas);
+ if (adapter.getCount() > 1) {
+ final String accountsSummary = getResources().getString(
+ R.string.compact_editor_linked_contacts_selector_title,
+ adapter.getCount());
+ addRawContactAccountSelector(accountsSummary, adapter);
+ }
}
private void addAccountHeader(Pair<String,String> accountInfo) {
@@ -847,21 +857,16 @@
});
}
- private void addRawContactAccountSelector(final RawContactDeltaList rawContactDeltas) {
+ private void addRawContactAccountSelector(String accountsSummary,
+ final RawContactAccountListAdapter adapter) {
mRawContactContainer.setVisibility(View.VISIBLE);
- Collections.sort(rawContactDeltas, new RawContactDeltaComparator(getContext()));
-
- final String accountsSummary = getResources().getString(
- R.string.compact_editor_linked_contacts_selector_title, rawContactDeltas.size());
mRawContactSummary.setText(accountsSummary);
mRawContactContainer.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final ListPopupWindow popup = new ListPopupWindow(getContext(), null);
- final RawContactAccountListAdapter adapter =
- new RawContactAccountListAdapter(getContext(), rawContactDeltas);
popup.setWidth(mRawContactContainer.getWidth());
popup.setAnchorView(mRawContactContainer);
popup.setAdapter(adapter);
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index 718128b..b091249 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -744,34 +744,21 @@
final MenuItem splitMenu = menu.findItem(R.id.menu_split);
final MenuItem joinMenu = menu.findItem(R.id.menu_join);
final MenuItem helpMenu = menu.findItem(R.id.menu_help);
- final MenuItem discardMenu = menu.findItem(R.id.menu_discard);
final MenuItem sendToVoiceMailMenu = menu.findItem(R.id.menu_send_to_voicemail);
final MenuItem ringToneMenu = menu.findItem(R.id.menu_set_ringtone);
final MenuItem deleteMenu = menu.findItem(R.id.menu_delete);
// Set visibility of menus
- // Discard menu is only available if at least one raw contact is editable
- discardMenu.setVisible(mState != null &&
- mState.getFirstWritableRawContact(mContext) != null);
// help menu depending on whether this is inserting or editing
if (isInsert(mAction) || mRawContactIdToDisplayAlone != -1) {
HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_add);
- discardMenu.setVisible(false);
splitMenu.setVisible(false);
joinMenu.setVisible(false);
deleteMenu.setVisible(false);
} else if (isEdit(mAction)) {
HelpUtils.prepareHelpMenuItem(mContext, helpMenu, R.string.help_url_people_edit);
- // Split only if there is more than one raw contact, it is not a user-profile, and
- // splitting won't result in an empty contact. For the empty contact case, we only guard
- // against this when there is a single read-only contact in the aggregate. If the user
- // has joined >1 read-only contacts together, we allow them to split it,
- // even if they have never added their own information and splitting will create a
- // name only contact.
- final boolean isSingleReadOnlyContact = mHasNewContact && mState.size() == 2;
- splitMenu.setVisible(isMultiAccountContact() && !isEditingUserProfile()
- && !isSingleReadOnlyContact);
+ splitMenu.setVisible(canUnlinkRawContacts());
// Cannot join a user profile
joinMenu.setVisible(!isEditingUserProfile());
deleteMenu.setVisible(!mDisableDeleteMenuOption && !isEditingUserProfile());
@@ -783,7 +770,7 @@
// Save menu is invisible when there's only one read only contact in the editor.
saveMenu.setVisible(!mRawContactDisplayAloneIsReadOnly);
- if (mRawContactIdToDisplayAlone != -1) {
+ if (mRawContactIdToDisplayAlone != -1 || mIsUserProfile) {
sendToVoiceMailMenu.setVisible(false);
ringToneMenu.setVisible(false);
} else {
@@ -812,8 +799,6 @@
switch (item.getItemId()) {
case R.id.menu_save:
return save(SaveMode.CLOSE);
- case R.id.menu_discard:
- return revert();
case R.id.menu_delete:
if (mListener != null) mListener.onDeleteRequested(mLookupUri);
return true;
@@ -973,11 +958,23 @@
return mNewLocalProfile || mIsUserProfile;
}
- protected boolean isMultiAccountContact() {
+ /**
+ * Whether the contact being edited spans multiple raw contacts.
+ * The may also span multiple accounts.
+ */
+ public boolean isEditingMultipleRawContacts() {
return mState.size() > 1;
}
/**
+ * Whether the contact being edited is composed of a single read-only raw contact
+ * aggregated with a newly created writable raw contact.
+ */
+ protected boolean isEditingReadOnlyRawContactWithNewContact() {
+ return mHasNewContact && mState.size() == 2;
+ }
+
+ /**
* Return true if there are any edits to the current contact which need to
* be saved.
*/
@@ -987,6 +984,19 @@
}
/**
+ * We allow unlinking only if there is more than one raw contact, it is not a user-profile,
+ * and unlinking won't result in an empty contact. For the empty contact case, we only guard
+ * against this when there is a single read-only contact in the aggregate. If the user
+ * has joined >1 read-only contacts together, we allow them to unlink it, even if they have
+ * never added their own information and unlinking will create a name only contact.
+ */
+ protected boolean canUnlinkRawContacts() {
+ return isEditingMultipleRawContacts()
+ && !isEditingUserProfile()
+ && !isEditingReadOnlyRawContactWithNewContact();
+ }
+
+ /**
* Determines if changes were made in the editor that need to be saved, while taking into
* account that name changes are not real for read-only contacts.
* See go/editing-read-only-contacts
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index eda5d4f..1104c02 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -514,24 +514,6 @@
inflater.inflate(R.menu.edit_group, menu);
}
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_discard:
- return revert();
- }
- return false;
- }
-
- private boolean revert() {
- if (!hasNameChange() && !hasMembershipChange()) {
- doRevertAction();
- } else {
- CancelEditDialogFragment.show(this);
- }
- return true;
- }
-
private void doRevertAction() {
// When this Fragment is closed we don't want it to auto-save
mStatus = Status.CLOSING;
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index d501e77..bc2ef53 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -1316,6 +1316,7 @@
mAggregationSuggestionEngine.setListener(this);
mAggregationSuggestionEngine.setSuggestionsLimit(getResources().getInteger(
R.integer.quickcontact_suggestions_limit));
+ mAggregationSuggestionEngine.setPruneInvisibleContacts(true);
mAggregationSuggestionEngine.start();
}