Merge "Implementation of business logic for voicemail status."
diff --git a/res/layout-sw580dp/contact_detail_fragment.xml b/res/layout-sw580dp/contact_detail_fragment.xml
index 3849277..cd559fe 100644
--- a/res/layout-sw580dp/contact_detail_fragment.xml
+++ b/res/layout-sw580dp/contact_detail_fragment.xml
@@ -48,12 +48,11 @@
/>
</com.android.contacts.widget.InterpolatingLayout>
- <!-- "Copy to my contacts"- button -->
+ <!-- "QuickFix"- button (Copy to local contact, add to group) -->
<Button
- android:id="@+id/copyLocal"
+ android:id="@+id/contact_quick_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/menu_copyContact"
android:visibility="gone"
android:layout_gravity="right"
android:layout_marginRight="40dip"
diff --git a/res/layout-w470dp/contact_detail_fragment.xml b/res/layout-w470dp/contact_detail_fragment.xml
index 64fec60..42266d5 100644
--- a/res/layout-w470dp/contact_detail_fragment.xml
+++ b/res/layout-w470dp/contact_detail_fragment.xml
@@ -58,12 +58,11 @@
android:lineSpacingMultiplier="0.92"/>
</ScrollView>
- <!-- "Copy to my contacts"- button -->
+ <!-- "QuickFix"- button (Copy to local contact, add to group) -->
<Button
- android:id="@+id/copyLocal"
+ android:id="@+id/contact_quick_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/menu_copyContact"
android:visibility="gone"
android:layout_gravity="right"
android:layout_marginRight="40dip"
diff --git a/res/layout/contact_detail_fragment.xml b/res/layout/contact_detail_fragment.xml
index d16771c..581dc03 100644
--- a/res/layout/contact_detail_fragment.xml
+++ b/res/layout/contact_detail_fragment.xml
@@ -46,12 +46,11 @@
</ScrollView>
- <!-- "Copy to my contacts"- button -->
+ <!-- "QuickFix"- button (Copy to local contact, add to group) -->
<Button
- android:id="@+id/copyLocal"
+ android:id="@+id/contact_quick_fix"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/menu_copyContact"
android:visibility="gone"
android:layout_gravity="right"
android:layout_marginRight="40dip"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f3b1b21..547f3e7 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1445,9 +1445,15 @@
<string name="aggregation_suggestion_edit_dialog_message">Switch to editing
the selected contact? Information you entered so far will be copied.</string>
- <!-- The menu item (or button) that creates a local copy of a corporate contact. [CHAR LIMIT=40]-->
+ <!-- The button that creates a local copy of a corporate contact. [CHAR LIMIT=40]-->
<string name="menu_copyContact">Copy to my contacts</string>
+ <!-- The button that adds a contact to the predefined group "My Contacts" (as this is
+ mostly interesting for Google-contacts, this should have the same description as the
+ function of GMail/Contacts on the Web
+ [CHAR LIMIT=40] -->
+ <string name="add_to_my_contacts">Add to "My Contacts"</string>
+
<!-- The description of the directory where the contact was found [CHAR LIMIT=100]-->
<string name="contact_directory_description">Directory <xliff:g id="type" example="Corporate Directory">%1$s</xliff:g></string>
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 677b73a..1921063 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -32,6 +32,10 @@
import com.android.contacts.model.AccountType.EditType;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.DataKind;
+import com.android.contacts.model.EntityDelta;
+import com.android.contacts.model.EntityDelta.ValuesDelta;
+import com.android.contacts.model.EntityDeltaList;
+import com.android.contacts.model.EntityModifier;
import com.android.contacts.util.Constants;
import com.android.contacts.util.DataStatus;
import com.android.contacts.util.DateUtils;
@@ -76,6 +80,7 @@
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.DisplayNameSources;
+import android.provider.ContactsContract.Intents.UI;
import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.StatusUpdates;
@@ -127,13 +132,18 @@
private ViewAdapter mAdapter;
private Uri mPrimaryPhoneUri = null;
- private Button mCopyGalToLocalButton;
+ private Button mQuickFixButton;
+ private QuickFix mQuickFix;
private final ArrayList<Long> mWritableRawContactIds = new ArrayList<Long>();
private int mNumPhoneNumbers = 0;
private String mDefaultCountryIso;
private boolean mContactDataDisplayed;
private boolean mContactPhotoDisplayedInHeader = true;
+ private final QuickFix[] mPotentialQuickFixes = new QuickFix[] {
+ new MakeLocalCopyQuickFix(),
+ new AddToMyContactsQuickFix() };
+
/**
* Device capability: Set during buildEntries and used in the long-press context menu
*/
@@ -247,11 +257,11 @@
mAlphaLayer = mView.findViewById(R.id.alpha_overlay);
mTouchInterceptLayer = mView.findViewById(R.id.touch_intercept_overlay);
- mCopyGalToLocalButton = (Button) mView.findViewById(R.id.copyLocal);
- mCopyGalToLocalButton.setOnClickListener(new OnClickListener() {
+ mQuickFixButton = (Button) mView.findViewById(R.id.contact_quick_fix);
+ mQuickFixButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- makePersonalCopy();
+ mQuickFix.execute();
}
});
@@ -382,22 +392,47 @@
}
mListView.setEmptyView(mEmptyView);
- // Configure copy gal button
- if (mContactData.isDirectoryEntry()) {
- final int exportSupport = mContactData.getDirectoryExportSupport();
- if (exportSupport == Directory.EXPORT_SUPPORT_ANY_ACCOUNT
- || exportSupport == Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY) {
- mCopyGalToLocalButton.setVisibility(View.VISIBLE);
- } else {
- mCopyGalToLocalButton.setVisibility(View.GONE);
- }
- } else {
- mCopyGalToLocalButton.setVisibility(View.GONE);
- }
+ configureQuickFix();
mView.setVisibility(View.VISIBLE);
}
+ /*
+ * Sets {@link #mQuickFix} to a useful action and configures the visibility of
+ * {@link #mQuickFixButton}
+ */
+ private void configureQuickFix() {
+ mQuickFix = null;
+
+ for (QuickFix fix : mPotentialQuickFixes) {
+ if (fix.isApplicable()) {
+ mQuickFix = fix;
+ break;
+ }
+ }
+
+ // Configure the button
+ if (mQuickFix == null) {
+ mQuickFixButton.setVisibility(View.GONE);
+ } else {
+ mQuickFixButton.setVisibility(View.VISIBLE);
+ mQuickFixButton.setText(mQuickFix.getTitle());
+ }
+ }
+
+ /** @return default group id or -1 if no group or several groups are marked as default */
+ private long getDefaultGroupId(List<GroupMetaData> groups) {
+ long defaultGroupId = -1;
+ for (GroupMetaData group : groups) {
+ if (group.isDefaultGroup()) {
+ // two default groups? return neither
+ if (defaultGroupId != -1) return -1;
+ defaultGroupId = group.getGroupId();
+ }
+ }
+ return defaultGroupId;
+ }
+
/**
* Build up the entries to display on the screen.
*/
@@ -1339,41 +1374,6 @@
}
}
- private void makePersonalCopy() {
- if (mListener == null) {
- return;
- }
-
- int exportSupport = mContactData.getDirectoryExportSupport();
- switch (exportSupport) {
- case Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY: {
- createCopy(new Account(mContactData.getDirectoryAccountName(),
- mContactData.getDirectoryAccountType()));
- break;
- }
- case Directory.EXPORT_SUPPORT_ANY_ACCOUNT: {
- final ArrayList<Account> accounts =
- AccountTypeManager.getInstance(mContext).getAccounts(true);
- if (accounts.isEmpty()) {
- createCopy(null);
- return; // Don't show a dialog.
- }
-
- // In the common case of a single writable account, auto-select
- // it without showing a dialog.
- if (accounts.size() == 1) {
- createCopy(accounts.get(0));
- return; // Don't show a dialog.
- }
-
- final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment();
- dialog.setTargetFragment(this, 0);
- dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG);
- break;
- }
- }
- }
-
@Override
public void onAccountSelectorCancelled() {
}
@@ -1451,6 +1451,154 @@
return false;
}
+ /**
+ * Base class for QuickFixes. QuickFixes quickly fix issues with the Contact without
+ * requiring the user to go to the editor. Example: Add to My Contacts.
+ */
+ private static abstract class QuickFix {
+ public abstract boolean isApplicable();
+ public abstract String getTitle();
+ public abstract void execute();
+ }
+
+ private class AddToMyContactsQuickFix extends QuickFix {
+ @Override
+ public boolean isApplicable() {
+ // Only local contacts
+ if (mContactData == null || mContactData.isDirectoryEntry()) return false;
+
+ // Only if exactly one raw contact
+ if (mContactData.getEntities().size() != 1) return false;
+
+ // test if the default group is assigned
+ final List<GroupMetaData> groups = mContactData.getGroupMetaData();
+
+ // For accounts without group support, groups is null
+ if (groups == null) return false;
+
+ // remember the default group id. no default group? bail out early
+ final long defaultGroupId = getDefaultGroupId(groups);
+ if (defaultGroupId == -1) return false;
+
+ final Entity rawContactEntity = mContactData.getEntities().get(0);
+ final String accountType =
+ rawContactEntity.getEntityValues().getAsString(RawContacts.ACCOUNT_TYPE);
+ final AccountTypeManager accountTypes =
+ AccountTypeManager.getInstance(mContext);
+ final AccountType type = accountTypes.getAccountType(accountType);
+ // Offline or non-writeable account? Nothing to fix
+ if (type == null || type.readOnly) return false;
+
+ // Check whether the contact is in the default group
+ boolean isInDefaultGroup = false;
+ for (NamedContentValues subValue : rawContactEntity.getSubValues()) {
+ final String mimeType = subValue.values.getAsString(Data.MIMETYPE);
+
+ if (GroupMembership.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ final Long groupId =
+ subValue.values.getAsLong(GroupMembership.GROUP_ROW_ID);
+ if (groupId == defaultGroupId) {
+ isInDefaultGroup = true;
+ break;
+ }
+ }
+ }
+
+ return !isInDefaultGroup;
+ }
+
+ @Override
+ public String getTitle() {
+ return getString(R.string.add_to_my_contacts);
+ }
+
+ @Override
+ public void execute() {
+ final long defaultGroupId = getDefaultGroupId(mContactData.getGroupMetaData());
+ // there should always be a default group (otherwise the button would be invisible),
+ // but let's be safe here
+ if (defaultGroupId == -1) return;
+
+ // add the group membership to the current state
+ final EntityDeltaList contactDeltaList = EntityDeltaList.fromIterator(
+ mContactData.getEntities().iterator());
+ final EntityDelta rawContactEntityDelta = contactDeltaList.get(0);
+
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
+ final ValuesDelta values = rawContactEntityDelta.getValues();
+ final String accountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
+ final AccountType type = accountTypes.getAccountType(accountType);
+ final DataKind groupMembershipKind = type.getKindForMimetype(
+ GroupMembership.CONTENT_ITEM_TYPE);
+ final ValuesDelta entry = EntityModifier.insertChild(rawContactEntityDelta,
+ groupMembershipKind);
+ entry.put(GroupMembership.GROUP_ROW_ID, defaultGroupId);
+
+ // and fire off the intent. we don't need a callback, as the database listener
+ // should update the ui
+ final Intent intent = ContactSaveService.createSaveContactIntent(getActivity(),
+ contactDeltaList, "", 0, getActivity().getClass(),
+ UI.LIST_ALL_CONTACTS_ACTION);
+ getActivity().startService(intent);
+ }
+ }
+
+ private class MakeLocalCopyQuickFix extends QuickFix {
+ @Override
+ public boolean isApplicable() {
+ // Not a directory contact? Nothing to fix here
+ if (mContactData == null || !mContactData.isDirectoryEntry()) return false;
+
+ // No export support? Too bad
+ if (mContactData.getDirectoryExportSupport() == Directory.EXPORT_SUPPORT_NONE) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public String getTitle() {
+ return getString(R.string.menu_copyContact);
+ }
+
+ @Override
+ public void execute() {
+ if (mListener == null) {
+ return;
+ }
+
+ int exportSupport = mContactData.getDirectoryExportSupport();
+ switch (exportSupport) {
+ case Directory.EXPORT_SUPPORT_SAME_ACCOUNT_ONLY: {
+ createCopy(new Account(mContactData.getDirectoryAccountName(),
+ mContactData.getDirectoryAccountType()));
+ break;
+ }
+ case Directory.EXPORT_SUPPORT_ANY_ACCOUNT: {
+ final ArrayList<Account> accounts =
+ AccountTypeManager.getInstance(mContext).getAccounts(true);
+ if (accounts.isEmpty()) {
+ createCopy(null);
+ return; // Don't show a dialog.
+ }
+
+ // In the common case of a single writable account, auto-select
+ // it without showing a dialog.
+ if (accounts.size() == 1) {
+ createCopy(accounts.get(0));
+ return; // Don't show a dialog.
+ }
+
+ final SelectAccountDialogFragment dialog = new SelectAccountDialogFragment();
+ dialog.setTargetFragment(ContactDetailFragment.this, 0);
+ dialog.show(getFragmentManager(), SelectAccountDialogFragment.TAG);
+ break;
+ }
+ }
+ }
+ }
+
public static interface Listener {
/**
* User clicked a single item (e.g. mail)