From e142481570d7fbda5d035555fe217314e396ae90 Mon Sep 17 00:00:00 2001 From: Yorke Lee Date: Wed, 4 Sep 2013 18:24:48 -0700 Subject: Add call shortcuts to phone number list adapters * Add a new class DialerPhoneNumberListAdapter, which both RegularSearchListADapter and SmartDialNumberListAdapter extend. DialerPhoneNumberListAdapter allows the addition of pre-defined call shortcuts at the end of the phone number list that can be toggled on or off. * For the SmartDialSearchFragment, the only shortcut that is available is always the Add number to contacts shortcut. * For the RegularSearchFragment, if the user enters a string that contains all dialable numbers, it is treated as a phone number and the call directly and add number to contacts shortcuts are enabled. Otherwise, it is treated as a name, and only the add contact with a new name shortcut is enabled. * Add a intent that allows the user to directly create a new contact that has the name field pre-populated. This intent is used if the user enters input that looks like a name in the search view. Bug: 10339630 Change-Id: I2ae757ce505d85a8780d28d89e09fb7084c773b1 --- src/com/android/dialer/DialtactsActivity.java | 14 ++ .../android/dialer/dialpad/DialpadFragment.java | 12 +- .../dialer/dialpad/SmartDialCursorLoader.java | 5 +- .../dialer/list/DialerPhoneNumberListAdapter.java | 188 +++++++++++++++++++++ .../dialer/list/RegularSearchListAdapter.java | 15 +- src/com/android/dialer/list/SearchFragment.java | 49 ++++++ .../dialer/list/SmartDialNumberListAdapter.java | 2 +- .../dialer/list/SmartDialSearchFragment.java | 5 + 8 files changed, 276 insertions(+), 14 deletions(-) create mode 100644 src/com/android/dialer/list/DialerPhoneNumberListAdapter.java (limited to 'src/com') diff --git a/src/com/android/dialer/DialtactsActivity.java b/src/com/android/dialer/DialtactsActivity.java index 398c90e42..c85ce42bf 100644 --- a/src/com/android/dialer/DialtactsActivity.java +++ b/src/com/android/dialer/DialtactsActivity.java @@ -37,6 +37,7 @@ import android.os.ServiceManager; import android.provider.CallLog.Calls; import android.provider.ContactsContract; import android.provider.ContactsContract.Contacts; +import android.provider.ContactsContract.Intents; import android.provider.ContactsContract.Intents.UI; import android.provider.Settings; import android.speech.RecognizerIntent; @@ -882,4 +883,17 @@ public class DialtactsActivity extends TransactionSafeActivity implements View.O final Intent intent = new Intent(this, AllContactsActivity.class); startActivity(intent); } + + public static Intent getAddNumberToContactIntent(CharSequence text) { + final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); + intent.putExtra(Intents.Insert.PHONE, text); + intent.setType(Contacts.CONTENT_ITEM_TYPE); + return intent; + } + + public static Intent getInsertContactWithNameIntent(CharSequence text) { + final Intent intent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI); + intent.putExtra(Intents.Insert.NAME, text); + return intent; + } } diff --git a/src/com/android/dialer/dialpad/DialpadFragment.java b/src/com/android/dialer/dialpad/DialpadFragment.java index 79e830730..79d10c07c 100644 --- a/src/com/android/dialer/dialpad/DialpadFragment.java +++ b/src/com/android/dialer/dialpad/DialpadFragment.java @@ -36,10 +36,11 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; -import android.provider.Contacts.Intents.Insert; +import android.provider.ContactsContract.Contacts; import android.provider.Contacts.People; import android.provider.Contacts.Phones; import android.provider.Contacts.PhonesColumns; +import android.provider.ContactsContract.Intents; import android.provider.Settings; import android.telephony.PhoneNumberUtils; import android.telephony.PhoneStateListener; @@ -766,18 +767,11 @@ public class DialpadFragment extends Fragment } else { final CharSequence digits = mDigits.getText(); // Put the current digits string into an intent - addToContactMenuItem.setIntent(getAddToContactIntent(digits)); + addToContactMenuItem.setIntent(DialtactsActivity.getAddNumberToContactIntent(digits)); addToContactMenuItem.setVisible(true); } } - private static Intent getAddToContactIntent(CharSequence digits) { - final Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT); - intent.putExtra(Insert.PHONE, digits); - intent.setType(People.CONTENT_ITEM_TYPE); - return intent; - } - private void keyPressed(int keyCode) { switch (keyCode) { case KeyEvent.KEYCODE_1: diff --git a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java index f558e37ca..a13ecd8da 100644 --- a/src/com/android/dialer/dialpad/SmartDialCursorLoader.java +++ b/src/com/android/dialer/dialpad/SmartDialCursorLoader.java @@ -59,11 +59,10 @@ public class SmartDialCursorLoader extends AsyncTaskLoader { if (DEBUG) { Log.v(TAG, "Configure new query to be " + query); } - mQuery = query; + mQuery = SmartDialNameMatcher.normalizeNumber(query, SmartDialPrefix.getMap()); /** Constructs a name matcher object for matching names. */ - mNameMatcher = new SmartDialNameMatcher(PhoneNumberUtils.normalizeNumber(query), - SmartDialPrefix.getMap()); + mNameMatcher = new SmartDialNameMatcher(mQuery, SmartDialPrefix.getMap()); } /** diff --git a/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java b/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java new file mode 100644 index 000000000..e9117107e --- /dev/null +++ b/src/com/android/dialer/list/DialerPhoneNumberListAdapter.java @@ -0,0 +1,188 @@ +package com.android.dialer.list; + +import android.content.Context; +import android.content.res.Resources; +import android.telephony.PhoneNumberUtils; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; + +import com.android.contacts.common.GeoUtil; +import com.android.contacts.common.list.ContactListItemView; +import com.android.contacts.common.list.PhoneNumberListAdapter; +import com.android.dialer.R; + +/** + * {@link PhoneNumberListAdapter} with the following added shortcuts, that are displayed as list + * items: + * 1) Directly calling the phone number query + * 2) Adding the phone number query to a contact + * + * These shortcuts can be enabled or disabled to toggle whether or not they show up in the + * list. + */ +public class DialerPhoneNumberListAdapter extends PhoneNumberListAdapter { + + private String mFormattedQueryString; + private String mCountryIso; + + public final static int SHORTCUT_INVALID = -1; + public final static int SHORTCUT_DIRECT_CALL = 0; + public final static int SHORTCUT_ADD_NUMBER_TO_CONTACTS = 1; + public final static int SHORTCUT_ADD_NEW_NAMED_CONTACT = 2; + + public final static int SHORTCUT_COUNT = 3; + + private final boolean[] mShortcutEnabled = new boolean[SHORTCUT_COUNT]; + + public DialerPhoneNumberListAdapter(Context context) { + super(context); + + mCountryIso = GeoUtil.getCurrentCountryIso(context); + + // Enable all shortcuts by default + for (int i = 0; i < mShortcutEnabled.length; i++) { + mShortcutEnabled[i] = true; + } + } + + @Override + public int getCount() { + return super.getCount() + getShortcutCount(); + } + + /** + * @return The number of enabled shortcuts. Ranges from 0 to a maximum of SHORTCUT_COUNT + */ + public int getShortcutCount() { + int count = 0; + for (int i = 0; i < mShortcutEnabled.length; i++) { + if (mShortcutEnabled[i]) count++; + } + return count; + } + + @Override + public int getItemViewType(int position) { + final int shortcut = getShortcutTypeFromPosition(position); + if (shortcut >= 0) { + // shortcutPos should always range from 1 to SHORTCUT_COUNT + return super.getViewTypeCount() + shortcut; + } else { + return super.getItemViewType(position); + } + } + + @Override + public int getViewTypeCount() { + // Number of item view types in the super implementation + 2 for the 2 new shortcuts + return super.getViewTypeCount() + SHORTCUT_COUNT; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final int shortcutType = getShortcutTypeFromPosition(position); + if (shortcutType >= 0) { + if (convertView != null) { + assignShortcutToView((ContactListItemView) convertView, shortcutType); + return convertView; + } else { + final ContactListItemView v = new ContactListItemView(getContext(), null); + assignShortcutToView(v, shortcutType); + return v; + } + } else { + return super.getView(position, convertView, parent); + } + } + + /** + * @param position The position of the item + * @return The enabled shortcut type matching the given position if the item is a + * shortcut, -1 otherwise + */ + public int getShortcutTypeFromPosition(int position) { + int shortcutCount = position - super.getCount(); + if (shortcutCount >= 0) { + // Iterate through the array of shortcuts, looking only for shortcuts where + // mShortcutEnabled[i] is true + for (int i = 0; shortcutCount >= 0 && i < mShortcutEnabled.length; i++) { + if (mShortcutEnabled[i]) { + shortcutCount--; + if (shortcutCount < 0) return i; + } + } + throw new IllegalArgumentException("Invalid position - greater than cursor count " + + " but not a shortcut."); + } + return SHORTCUT_INVALID; + } + + @Override + public boolean isEmpty() { + return getShortcutCount() == 0 && super.isEmpty(); + } + + @Override + public boolean isEnabled(int position) { + final int shortcutType = getShortcutTypeFromPosition(position); + if (shortcutType >= 0) { + return true; + } else { + return super.isEnabled(position); + } + } + + private void assignShortcutToView(ContactListItemView v, int shortcutType) { + final CharSequence text; + final int drawableId; + final Resources resources = getContext().getResources(); + final String number = getFormattedQueryString(); + switch (shortcutType) { + case SHORTCUT_DIRECT_CALL: + text = resources.getString(R.string.search_shortcut_call_number, number); + drawableId = R.drawable.ic_phone_dk; + break; + case SHORTCUT_ADD_NUMBER_TO_CONTACTS: + text = resources.getString(R.string.search_shortcut_add_to_contacts); + drawableId = R.drawable.ic_add_person_dk; + break; + case SHORTCUT_ADD_NEW_NAMED_CONTACT: + text = resources.getString(R.string.search_shortcut_add_to_contacts); + drawableId = R.drawable.ic_add_person_dk; + break; + default: + throw new IllegalArgumentException("Invalid shortcut type"); + } + v.setDrawableResource(R.drawable.list_item_avatar_bg, drawableId); + v.setDisplayName(text); + v.setPhotoPosition(super.getPhotoPosition()); + } + + public void setShortcutEnabled(int shortcutType, boolean visible) { + mShortcutEnabled[shortcutType] = visible; + } + + public String getFormattedQueryString() { + return mFormattedQueryString; + } + + @Override + public void setQueryString(String queryString) { + boolean containsNonDialableCharacters = false; + for (int i = 0; i < queryString.length(); i++) { + if (!PhoneNumberUtils.isDialable(queryString.charAt(i))) { + containsNonDialableCharacters = true; + break; + } + } + + if (containsNonDialableCharacters) { + mFormattedQueryString = null; + } else { + mFormattedQueryString = PhoneNumberUtils.formatNumber(queryString, mCountryIso); + } + + super.setQueryString(queryString); + } +} diff --git a/src/com/android/dialer/list/RegularSearchListAdapter.java b/src/com/android/dialer/list/RegularSearchListAdapter.java index 390dbb56c..627262ebe 100644 --- a/src/com/android/dialer/list/RegularSearchListAdapter.java +++ b/src/com/android/dialer/list/RegularSearchListAdapter.java @@ -19,6 +19,7 @@ import android.content.Context; import android.database.Cursor; import android.net.Uri; import android.provider.ContactsContract; +import android.text.TextUtils; import com.android.contacts.common.list.DirectoryPartition; import com.android.contacts.common.list.PhoneNumberListAdapter; @@ -27,7 +28,7 @@ import com.android.dialer.service.CachedNumberLookupService.CachedContactInfo; /** * List adapter to display regular search results. */ -public class RegularSearchListAdapter extends PhoneNumberListAdapter { +public class RegularSearchListAdapter extends DialerPhoneNumberListAdapter { public RegularSearchListAdapter(Context context) { super(context); @@ -59,4 +60,16 @@ public class RegularSearchListAdapter extends PhoneNumberListAdapter { } return info; } + + @Override + public void setQueryString(String queryString) { + final boolean showNumberShortcuts = !TextUtils.isEmpty(getFormattedQueryString()); + setShortcutEnabled(SHORTCUT_DIRECT_CALL, showNumberShortcuts); + // Either one of the add contacts options should be enabled. If the user entered + // a dialable number, then clicking add to contact should add it as a number. + // Otherwise, it should add it to a new contact as a name. + setShortcutEnabled(SHORTCUT_ADD_NUMBER_TO_CONTACTS, showNumberShortcuts); + setShortcutEnabled(SHORTCUT_ADD_NEW_NAMED_CONTACT, !showNumberShortcuts); + super.setQueryString(queryString); + } } diff --git a/src/com/android/dialer/list/SearchFragment.java b/src/com/android/dialer/list/SearchFragment.java index 54ee43600..0302d9724 100644 --- a/src/com/android/dialer/list/SearchFragment.java +++ b/src/com/android/dialer/list/SearchFragment.java @@ -16,12 +16,19 @@ package com.android.dialer.list; import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Intent; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; +import android.widget.Toast; import com.android.contacts.common.list.ContactEntryListAdapter; import com.android.contacts.common.list.ContactListItemView; +import com.android.contacts.common.list.OnPhoneNumberPickerActionListener; import com.android.contacts.common.list.PhoneNumberPickerFragment; +import com.android.dialer.DialtactsActivity; +import com.android.dialer.R; +import com.android.dialer.dialpad.DialpadFragment; import com.android.dialer.list.OnListFragmentScrolledListener; public class SearchFragment extends PhoneNumberPickerFragment { @@ -73,4 +80,46 @@ public class SearchFragment extends PhoneNumberPickerFragment { adapter.setHasHeader(0, false); } } + + @Override + protected ContactEntryListAdapter createListAdapter() { + DialerPhoneNumberListAdapter adapter = new DialerPhoneNumberListAdapter(getActivity()); + adapter.setDisplayPhotos(true); + adapter.setUseCallableUri(super.usesCallableUri()); + return adapter; + } + + @Override + protected void onItemClick(int position, long id) { + final DialerPhoneNumberListAdapter adapter = (DialerPhoneNumberListAdapter) getAdapter(); + final int shortcutType = adapter.getShortcutTypeFromPosition(position); + + if (shortcutType == DialerPhoneNumberListAdapter.SHORTCUT_INVALID) { + super.onItemClick(position, id); + } else if (shortcutType == DialerPhoneNumberListAdapter.SHORTCUT_DIRECT_CALL) { + final OnPhoneNumberPickerActionListener listener = + getOnPhoneNumberPickerListener(); + if (listener != null) { + listener.onCallNumberDirectly(getQueryString()); + } + } else if (shortcutType == DialerPhoneNumberListAdapter.SHORTCUT_ADD_NUMBER_TO_CONTACTS) { + final String number = adapter.getFormattedQueryString(); + final Intent intent = DialtactsActivity.getAddNumberToContactIntent(number); + startActivityWithErrorToast(intent); + } else if (shortcutType == DialerPhoneNumberListAdapter.SHORTCUT_ADD_NEW_NAMED_CONTACT) { + final String name = adapter.getQueryString(); + final Intent intent = DialtactsActivity.getInsertContactWithNameIntent(name); + startActivityWithErrorToast(intent); + } + } + + private void startActivityWithErrorToast(Intent intent) { + try { + startActivity(intent); + } catch (ActivityNotFoundException e) { + Toast toast = Toast.makeText(getActivity(), R.string.add_contact_not_available, + Toast.LENGTH_SHORT); + toast.show(); + } + } } diff --git a/src/com/android/dialer/list/SmartDialNumberListAdapter.java b/src/com/android/dialer/list/SmartDialNumberListAdapter.java index c5ce59af2..962d8ee43 100644 --- a/src/com/android/dialer/list/SmartDialNumberListAdapter.java +++ b/src/com/android/dialer/list/SmartDialNumberListAdapter.java @@ -37,7 +37,7 @@ import java.util.ArrayList; /** * List adapter to display the SmartDial search results. */ -public class SmartDialNumberListAdapter extends PhoneNumberListAdapter{ +public class SmartDialNumberListAdapter extends DialerPhoneNumberListAdapter { private static final String TAG = SmartDialNumberListAdapter.class.getSimpleName(); private static final boolean DEBUG = false; diff --git a/src/com/android/dialer/list/SmartDialSearchFragment.java b/src/com/android/dialer/list/SmartDialSearchFragment.java index a163f5db7..4248c85fb 100644 --- a/src/com/android/dialer/list/SmartDialSearchFragment.java +++ b/src/com/android/dialer/list/SmartDialSearchFragment.java @@ -38,6 +38,11 @@ public class SmartDialSearchFragment extends SearchFragment { SmartDialNumberListAdapter adapter = new SmartDialNumberListAdapter(getActivity()); adapter.setUseCallableUri(super.usesCallableUri()); adapter.setQuickContactEnabled(true); + // Disable the direct call shortcut for the smart dial fragment, since the call button + // will already be showing anyway. + adapter.setShortcutEnabled(SmartDialNumberListAdapter.SHORTCUT_DIRECT_CALL, false); + adapter.setShortcutEnabled(SmartDialNumberListAdapter.SHORTCUT_ADD_NEW_NAMED_CONTACT, + false); return adapter; } -- cgit v1.2.3