Show dialog if multiple candidates exist
In GB we show a list of phone number to call in Favorites
screen, while we don't now.
Also refrain PhoneNumberInteraction from showing a dialog
by itself but let a nested class do instead. showDialog() is now
obsolete and we should use DialogFragment instead.
Bug: 4743008
Change-Id: I202963c2f03424f07ee386bd9713fde4091a0ae2
diff --git a/src/com/android/contacts/CallContactActivity.java b/src/com/android/contacts/CallContactActivity.java
index 77bf20c..b7c472a 100644
--- a/src/com/android/contacts/CallContactActivity.java
+++ b/src/com/android/contacts/CallContactActivity.java
@@ -32,12 +32,9 @@
*/
public class CallContactActivity extends ContactsActivity implements OnDismissListener {
- private PhoneNumberInteraction mPhoneNumberInteraction;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mPhoneNumberInteraction = new PhoneNumberInteraction(this, false, this);
Uri contactUri = getIntent().getData();
if (contactUri == null) {
@@ -51,7 +48,7 @@
}
if (Contacts.CONTENT_ITEM_TYPE.equals(getContentResolver().getType(contactUri))) {
- mPhoneNumberInteraction.startInteraction(contactUri);
+ PhoneNumberInteraction.startInteractionForPhoneCall(this, contactUri);
} else {
startActivity(new Intent(Intent.ACTION_CALL_PRIVILEGED, contactUri));
finish();
@@ -64,14 +61,4 @@
finish();
}
}
-
- @Override
- protected Dialog onCreateDialog(int id, Bundle args) {
- return mPhoneNumberInteraction.onCreateDialog(id, args);
- }
-
- @Override
- protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
- mPhoneNumberInteraction.onPrepareDialog(id, dialog, args);
- }
}
diff --git a/src/com/android/contacts/Collapser.java b/src/com/android/contacts/Collapser.java
index 5b5d5a0..3b2f2a9 100644
--- a/src/com/android/contacts/Collapser.java
+++ b/src/com/android/contacts/Collapser.java
@@ -43,7 +43,7 @@
/**
* Collapses a list of Collapsible items into a list of collapsed items. Items are collapsed
- * if {@link Collapsible#shouldCollapseWith(Object)} returns strue, and are collapsed
+ * if {@link Collapsible#shouldCollapseWith(Object)} returns true, and are collapsed
* through the {@Link Collapsible#collapseWith(Object)} function implemented by the data item.
*
* @param list List of Objects of type <T extends Collapsible<T>> to be collapsed.
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index 931b600..ed80eb1 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -94,9 +94,6 @@
*/
private int mLastManuallySelectedTab;
- // TODO: It would be great to eventually remove all interactions and replace by DialogFragments
- private PhoneNumberInteraction mPhoneNumberCallInteraction;
-
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
@@ -395,13 +392,6 @@
}
}
- private PhoneNumberInteraction getPhoneNumberCallInteraction() {
- if (mPhoneNumberCallInteraction == null) {
- mPhoneNumberCallInteraction = new PhoneNumberInteraction(this, false, null);
- }
- return mPhoneNumberCallInteraction;
- }
-
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
@@ -482,7 +472,8 @@
@Override
public void onCallContactAction(Uri contactUri) {
- getPhoneNumberCallInteraction().startInteraction(contactUri);
+ PhoneNumberInteraction.startInteractionForPhoneCall(
+ DialtactsActivity.this, contactUri);
}
@Override
@@ -494,7 +485,8 @@
new StrequentContactListFragment.Listener() {
@Override
public void onContactSelected(Uri contactUri) {
- getPhoneNumberCallInteraction().startInteraction(contactUri);
+ PhoneNumberInteraction.startInteractionForPhoneCall(
+ DialtactsActivity.this, contactUri);
}
};
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index c247d43..55acdad 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -119,9 +119,6 @@
private GroupDetailFragment mGroupDetailFragment;
- private PhoneNumberInteraction mPhoneNumberCallInteraction;
- private PhoneNumberInteraction mSendTextMessageInteraction;
-
private boolean mSearchInitiated;
private ContactListFilterController mContactListFilterController;
@@ -637,12 +634,12 @@
@Override
public void onCallContactAction(Uri contactUri) {
- getPhoneNumberCallInteraction().startInteraction(contactUri);
+ PhoneNumberInteraction.startInteractionForPhoneCall(PeopleActivity.this, contactUri);
}
@Override
public void onSmsContactAction(Uri contactUri) {
- getSendTextMessageInteraction().startInteraction(contactUri);
+ PhoneNumberInteraction.startInteractionForTextMessage(PeopleActivity.this, contactUri);
}
@Override
@@ -935,32 +932,6 @@
}
@Override
- protected Dialog onCreateDialog(int id, Bundle bundle) {
- if (DialogManager.isManagedId(id)) return mDialogManager.onCreateDialog(id, bundle);
-
- Dialog dialog = getPhoneNumberCallInteraction().onCreateDialog(id, bundle);
- if (dialog != null) return dialog;
-
- dialog = getSendTextMessageInteraction().onCreateDialog(id, bundle);
- if (dialog != null) return dialog;
-
- return super.onCreateDialog(id, bundle);
- }
-
- @Override
- protected void onPrepareDialog(int id, Dialog dialog, Bundle bundle) {
- if (getPhoneNumberCallInteraction().onPrepareDialog(id, dialog, bundle)) {
- return;
- }
-
- if (getSendTextMessageInteraction().onPrepareDialog(id, dialog, bundle)) {
- return;
- }
-
- super.onPrepareDialog(id, dialog, bundle);
- }
-
- @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case SUBACTIVITY_CUSTOMIZE_FILTER: {
@@ -1088,20 +1059,6 @@
}
}
- private PhoneNumberInteraction getPhoneNumberCallInteraction() {
- if (mPhoneNumberCallInteraction == null) {
- mPhoneNumberCallInteraction = new PhoneNumberInteraction(this, false, null);
- }
- return mPhoneNumberCallInteraction;
- }
-
- private PhoneNumberInteraction getSendTextMessageInteraction() {
- if (mSendTextMessageInteraction == null) {
- mSendTextMessageInteraction = new PhoneNumberInteraction(this, true, null);
- }
- return mSendTextMessageInteraction;
- }
-
@Override
public DialogManager getDialogManager() {
return mDialogManager;
diff --git a/src/com/android/contacts/interactions/PhoneNumberInteraction.java b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
index 399b0ea..8430559 100644
--- a/src/com/android/contacts/interactions/PhoneNumberInteraction.java
+++ b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
@@ -16,11 +16,6 @@
package com.android.contacts.interactions;
-import com.google.i18n.phonenumbers.NumberParseException;
-import com.google.i18n.phonenumbers.PhoneNumberUtil;
-import com.google.i18n.phonenumbers.PhoneNumberUtil.MatchType;
-import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
-
import com.android.contacts.Collapser;
import com.android.contacts.Collapser.Collapsible;
import com.android.contacts.ContactSaveService;
@@ -29,15 +24,21 @@
import com.android.contacts.model.AccountType.StringInflater;
import com.android.contacts.model.AccountTypeManager;
import com.android.contacts.model.DataKind;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.MatchType;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.CursorLoader;
import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.content.Loader;
@@ -57,45 +58,36 @@
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
+import android.widget.ListAdapter;
import android.widget.TextView;
import java.util.ArrayList;
+import java.util.List;
/**
- * Initiates phone calls or a text message.
+ * Initiates phone calls or a text message. If there are multiple candidates, this class shows a
+ * dialog to pick one.
*/
-public class PhoneNumberInteraction
- implements OnLoadCompleteListener<Cursor>, OnClickListener {
+public class PhoneNumberInteraction implements OnLoadCompleteListener<Cursor> {
+ private static final String TAG = PhoneNumberInteraction.class.getSimpleName();
- public static final String EXTRA_KEY_ITEMS = "items";
+ @VisibleForTesting
+ /* package */ enum InteractionType {
+ PHONE_CALL,
+ SMS
+ }
/**
* A model object for capturing a phone number for a given contact.
*/
- static class PhoneItem implements Parcelable, Collapsible<PhoneItem> {
+ @VisibleForTesting
+ /* package */ static class PhoneItem implements Parcelable, Collapsible<PhoneItem> {
long id;
String phoneNumber;
String accountType;
long type;
String label;
- public static Parcelable.Creator<PhoneItem> CREATOR = new Creator<PhoneItem>() {
-
- public PhoneItem[] newArray(int size) {
- return new PhoneItem[size];
- }
-
- public PhoneItem createFromParcel(Parcel source) {
- PhoneItem item = new PhoneItem();
- item.id = source.readLong();
- item.phoneNumber = source.readString();
- item.accountType = source.readString();
- item.type = source.readLong();
- item.label = source.readString();
- return item;
- }
- };
-
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
dest.writeString(phoneNumber);
@@ -140,30 +132,31 @@
/**
* A list adapter that populates the list of contact's phone numbers.
*/
- private class PhoneItemAdapter extends ArrayAdapter<PhoneItem> {
- private final AccountTypeManager mAccountTypes;
+ private static class PhoneItemAdapter extends ArrayAdapter<PhoneItem> {
+ private final InteractionType mInteractionType;
+ private final AccountTypeManager mAccountTypeManager;
- public PhoneItemAdapter(Context context) {
- super(context, R.layout.phone_disambig_item, android.R.id.text2);
- mAccountTypes = AccountTypeManager.getInstance(context);
+ public PhoneItemAdapter(Context context, List<PhoneItem> list,
+ InteractionType interactionType) {
+ super(context, R.layout.phone_disambig_item, android.R.id.text2, list);
+ mInteractionType = interactionType;
+ mAccountTypeManager = AccountTypeManager.getInstance(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- View view = super.getView(position, convertView, parent);
+ final View view = super.getView(position, convertView, parent);
- PhoneItem item = getItem(position);
- AccountType accountType = mAccountTypes.getAccountType(item.accountType);
-
- // Obtain a string representation of the phone type specific to the
- // account type associated with that phone number
- TextView typeView = (TextView)view.findViewById(android.R.id.text1);
- DataKind kind = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
+ final PhoneItem item = getItem(position);
+ final AccountType accountType = mAccountTypeManager.getAccountType(item.accountType);
+ final TextView typeView = (TextView) view.findViewById(android.R.id.text1);
+ final DataKind kind = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
if (kind != null) {
ContentValues values = new ContentValues();
values.put(Phone.TYPE, item.type);
values.put(Phone.LABEL, item.label);
- StringInflater header = mSendTextMessage ? kind.actionAltHeader : kind.actionHeader;
+ StringInflater header = (mInteractionType == InteractionType.SMS)
+ ? kind.actionAltHeader : kind.actionHeader;
typeView.setText(header.inflateUsing(getContext(), values));
} else {
typeView.setText(R.string.call_other);
@@ -172,6 +165,73 @@
}
}
+ /**
+ * {@link DialogFragment} used for displaying a dialog with a list of phone numbers of which
+ * one will be chosen to make a call or initiate an sms message.
+ *
+ * It is recommended to use
+ * {@link PhoneNumberInteraction#startInteractionForPhoneCall(Activity, Uri)} or
+ * {@link PhoneNumberInteraction#startInteractionForTextMessage(Activity, Uri)} instead of
+ * directly using this class, as those methods handle one or multiple data cases appropriately.
+ */
+ /* Made public to let the system reach this class */
+ public static class PhoneDisambiguationDialogFragment extends DialogFragment
+ implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener {
+
+ private static final String ARG_PHONE_LIST = "phoneList";
+ private static final String ARG_INTERACTION_TYPE = "interactionType";
+
+ private InteractionType mInteractionType;
+ private ListAdapter mPhonesAdapter;
+ private List<PhoneItem> mPhoneList;
+
+ public static void show(FragmentManager fragmentManager,
+ ArrayList<PhoneItem> phoneList, InteractionType interactionType) {
+ PhoneDisambiguationDialogFragment fragment = new PhoneDisambiguationDialogFragment();
+ Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(ARG_PHONE_LIST, phoneList);
+ bundle.putSerializable(ARG_INTERACTION_TYPE, interactionType);
+ fragment.setArguments(bundle);
+ fragment.show(fragmentManager, TAG);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Activity activity = getActivity();
+ mPhoneList = getArguments().getParcelableArrayList(ARG_PHONE_LIST);
+ mInteractionType =
+ (InteractionType) getArguments().getSerializable(ARG_INTERACTION_TYPE);
+ mPhonesAdapter = new PhoneItemAdapter(activity, mPhoneList, mInteractionType);
+ final LayoutInflater inflater = activity.getLayoutInflater();
+ final View setPrimaryView = inflater.inflate(R.layout.set_primary_checkbox, null);
+ return new AlertDialog.Builder(activity)
+ .setAdapter(mPhonesAdapter, this)
+ .setTitle(mInteractionType == InteractionType.SMS
+ ? R.string.sms_disambig_title : R.string.call_disambig_title)
+ .setView(setPrimaryView)
+ .create();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ final AlertDialog alertDialog = (AlertDialog)dialog;
+ if (mPhoneList.size() > which && which >= 0) {
+ final PhoneItem phoneItem = mPhoneList.get(which);
+ final CheckBox checkBox = (CheckBox)alertDialog.findViewById(R.id.setPrimary);
+ if (checkBox.isChecked()) {
+ // Request to mark the data as primary in the background.
+ final Intent serviceIntent = ContactSaveService.createSetSuperPrimaryIntent(
+ getActivity(), phoneItem.id);
+ getActivity().startService(serviceIntent);
+ }
+
+ PhoneNumberInteraction.performAction(getActivity(), phoneItem.phoneNumber,
+ mInteractionType);
+ } else {
+ dialog.dismiss();
+ }
+ }
+ }
+
private static final String[] PHONE_NUMBER_PROJECTION = new String[] {
Phone._ID,
Phone.NUMBER,
@@ -186,28 +246,36 @@
private final Context mContext;
private final OnDismissListener mDismissListener;
- private final boolean mSendTextMessage;
+ private final InteractionType mInteractionType;
private CursorLoader mLoader;
- public PhoneNumberInteraction(Context context, boolean sendTextMessage,
+ @VisibleForTesting
+ /* package */ PhoneNumberInteraction(Context context, InteractionType interactionType,
DialogInterface.OnDismissListener dismissListener) {
mContext = context;
- mSendTextMessage = sendTextMessage;
+ mInteractionType = interactionType;
mDismissListener = dismissListener;
}
private void performAction(String phoneNumber) {
- Intent intent;
- if (mSendTextMessage) {
- intent = new Intent(
- Intent.ACTION_SENDTO, Uri.fromParts("sms", phoneNumber, null));
- } else {
- intent = new Intent(
- Intent.ACTION_CALL_PRIVILEGED, Uri.fromParts("tel", phoneNumber, null));
+ PhoneNumberInteraction.performAction(mContext, phoneNumber, mInteractionType);
+ }
+ private static void performAction(
+ Context context, String phoneNumber, InteractionType interactionType) {
+ Intent intent;
+ switch (interactionType) {
+ case SMS:
+ intent = new Intent(
+ Intent.ACTION_SENDTO, Uri.fromParts("sms", phoneNumber, null));
+ break;
+ default:
+ intent = new Intent(
+ Intent.ACTION_CALL_PRIVILEGED, Uri.fromParts("tel", phoneNumber, null));
+ break;
}
- startActivity(intent);
+ context.startActivity(intent);
}
/**
@@ -274,9 +342,8 @@
onDismiss();
performAction(phoneList.get(0).phoneNumber);
} else {
- Bundle bundle = new Bundle();
- bundle.putParcelableArrayList(EXTRA_KEY_ITEMS, phoneList);
- showDialog(getDialogId(), bundle);
+ // There are multiple candidates. Let the user choose one.
+ showDisambiguationDialog(phoneList);
}
}
@@ -286,89 +353,33 @@
}
}
- private int getDialogId() {
- return mSendTextMessage
- ? R.id.dialog_phone_number_message_disambiguation
- : R.id.dialog_phone_number_call_disambiguation;
- }
-
- public Dialog onCreateDialog(int id, Bundle bundle) {
- if (id != getDialogId()) {
- return null;
- }
-
- LayoutInflater inflater = LayoutInflater.from(mContext);
- View setPrimaryView = inflater.inflate(R.layout.set_primary_checkbox, null);
- AlertDialog dialog = new AlertDialog.Builder(mContext)
- .setAdapter(new PhoneItemAdapter(mContext), this)
- .setView(setPrimaryView)
- .setTitle(mSendTextMessage
- ? R.string.sms_disambig_title
- : R.string.call_disambig_title)
- .create();
- dialog.setOnDismissListener(mDismissListener);
- return dialog;
- }
-
- public boolean onPrepareDialog(int id, Dialog dialog, Bundle bundle) {
- if (id != getDialogId()) {
- return false;
- }
-
- ArrayList<PhoneItem> phoneList = bundle.getParcelableArrayList(EXTRA_KEY_ITEMS);
-
- AlertDialog alertDialog = (AlertDialog)dialog;
- PhoneItemAdapter adapter = (PhoneItemAdapter)alertDialog.getListView().getAdapter();
- adapter.clear();
- adapter.addAll(phoneList);
-
- return true;
+ /**
+ * Start call action using given contact Uri. If there are multiple candidates for the phone
+ * call, dialog is automatically shown and the user is asked to choose one.
+ */
+ public static void startInteractionForPhoneCall(Activity activity, Uri contactUri) {
+ (new PhoneNumberInteraction(activity, InteractionType.PHONE_CALL, null))
+ .startInteraction(contactUri);
}
/**
- * Handles the user selection in the disambiguation dialog.
+ * Start text messaging (a.k.a SMS) action using given contact Uri. If there are multiple
+ * candidates for the phone call, dialog is automatically shown and the user is asked to choose
+ * one.
*/
- @Override
- public void onClick(DialogInterface dialog, int which) {
- AlertDialog alertDialog = (AlertDialog)dialog;
- PhoneItemAdapter adapter = (PhoneItemAdapter)alertDialog.getListView().getAdapter();
- PhoneItem phoneItem = adapter.getItem(which);
- if (phoneItem != null) {
- long id = phoneItem.id;
- String phone = phoneItem.phoneNumber;
-
- CheckBox checkBox = (CheckBox)alertDialog.findViewById(R.id.setPrimary);
- if (checkBox.isChecked()) {
- makePrimary(id);
- }
-
- performAction(phone);
- }
+ public static void startInteractionForTextMessage(Activity activity, Uri contactUri) {
+ (new PhoneNumberInteraction(activity, InteractionType.SMS, null))
+ .startInteraction(contactUri);
}
- /**
- * Makes the selected phone number primary.
- */
- void makePrimary(long id) {
- final Intent intent = ContactSaveService.createSetSuperPrimaryIntent(mContext, id);
- mContext.startService(intent);
- }
-
- /* Visible for testing */
- void showDialog(int dialogId, Bundle bundle) {
- Activity activity = (Activity)mContext;
- if (!activity.isFinishing()) {
- activity.showDialog(dialogId, bundle);
- }
- }
-
- /* Visible for testing */
- void startActivity(Intent intent) {
- mContext.startActivity(intent);
- }
-
- /* Visible for testing */
+ @VisibleForTesting
CursorLoader getLoader() {
return mLoader;
}
+
+ @VisibleForTesting
+ void showDisambiguationDialog(ArrayList<PhoneItem> phoneList) {
+ PhoneDisambiguationDialogFragment.show(((Activity)mContext).getFragmentManager(),
+ phoneList, mInteractionType);
+ }
}